[
  {
    "path": ".eslintrc.json",
    "content": "{\n  \"extends\": \"eslint:recommended\",\n  \"parser\": \"babel-eslint\",\n  \"parserOptions\": {\n    \"ecmaVersion\": 6,\n    \"sourceType\": \"module\"\n  },\n  \"rules\": {\n    \"no-console\": \"off\",\n    \"no-var\": \"error\",\n    \"semi\": \"error\",\n    \"strict\": \"error\",\n    \"valid-jsdoc\": [\"error\", {\n      \"requireReturn\": false,\n      \"prefer\": {\n        \"arg\": \"param\",\n        \"argument\": \"param\",\n        \"returns\": \"return\"\n      },\n      \"preferType\": {\n        \"Boolean\": \"boolean\",\n        \"Number\": \"number\",\n        \"String\": \"string\",\n        \"object\": \"Object\",\n        \"array\": \"Array\"\n      }\n    }],\n    \"no-useless-escape\": \"off\"\n  },\n  \"env\": {\n    \"browser\": true,\n    \"es6\": true\n  },\n  \"plugins\": [\n    \"html\"\n  ],\n  \"globals\": {\n    \"customElements\": true,\n    \"HTMLImports\": true,\n    \"Polymer\": true,\n    \"ShadyDOM\": true,\n    \"ShadyCSS\": true,\n    \"JSCompiler_renameProperty\": true,\n    \"trustedTypes\": true\n  }\n}\n"
  },
  {
    "path": ".gitattributes",
    "content": "* text=auto\n"
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "# Code owners for Polymer\n* @sorvell @kevinpschaaf @azakus\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "<!--\nIf you are asking a question rather than filing a bug, try one of these instead:\n- StackOverflow (https://stackoverflow.com/questions/tagged/polymer)\n- Polymer Slack Channel (https://bit.ly/polymerslack)\n- Mailing List (https://groups.google.com/forum/#!forum/polymer-dev)\n-->\n<!-- Instructions For Filing a Bug: https://github.com/Polymer/polymer/blob/master/CONTRIBUTING.md#filing-bugs -->\n### Description\n<!-- Example: Error thrown when calling `appendChild` on Polymer element -->\n\n#### Live Demo\n<!-- jsBin starting point (fork and edit) -->\nhttps://jsbin.com/luhaxab/edit\n<!-- glitch.me starting point (remix and edit -- must be logged in to persist!) -->\nhttps://glitch.com/edit/#!/polymer-repro?path=my-element.html:2:0\n<!-- ...or provide your own repro URL -->\n\n#### Steps to Reproduce\n<!--\nExample:\n\n1. Create `my-element`\n2. Append `my-element` to document.body\n3. Create `div`.\n4. Append `div` to `my-element`\n-->\n\n\n#### Expected Results\n<!-- Example: No error is throw -->\n\n#### Actual Results\n<!-- Example: Error is thrown -->\n\n### Browsers Affected\n<!-- Check all that apply -->\n- [ ] Chrome\n- [ ] Firefox\n- [ ] Edge\n- [ ] Safari 11\n- [ ] Safari 10\n- [ ] IE 11\n\n### Versions\n<!--\n`Polymer.version` will show the version for Polymer\n`bower ls` or `npm ls` will show the version of webcomponents.js or webcomponents-lite.js\n-->\n- Polymer: vX.X.X\n- webcomponents: vX.X.X \n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "<!-- Instructions: https://github.com/Polymer/polymer/blob/master/CONTRIBUTING.md#contributing-pull-requests -->\n### Reference Issue\n<!-- Example: Fixes #1234 -->\n"
  },
  {
    "path": ".github/stale.yml",
    "content": "# Mark issues stale after 1 year\ndaysUntilStale: 365\n# Delete stale issues after 2 years\ndaysUntilClose: 730\nmarkComment: >\n  This issue has been automatically marked as stale because it has not had\n  recent activity. It will be closed if no further activity occurs. Thank you\n  for your contributions.\ncloseComment: >\n  This issue has been automatically closed after being marked stale. If you're\n  still facing this problem with the above solution, please comment and we'll\n  reopen!\n"
  },
  {
    "path": ".gitignore",
    "content": "# dependencies\nbower_components\nnode_modules\n\n# compiled output\ndist\n\n# IDEs\n.idea\n.vscode\n\n# misc\n.DS_Store\nnpm-debug.log\n\n# Analyzer output used in the docs\nanalysis.json\n\n# NPM artifact\npolymer-polymer-*.tgz\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: node_js\nsudo: false\ndist: xenial\nnode_js: '10'\nservices:\n  - xvfb\naddons:\n  firefox: latest\n  chrome: stable\ncache:\n  directories:\n    - node_modules\nbefore_script:\n- npm install -g gulp-cli@1\n- gulp lint-eslint\nscript:\n- node ./node_modules/.bin/polymer test --npm --module-resolution=node -l chrome\n- node ./node_modules/.bin/polymer test --npm --module-resolution=node -l firefox\n- if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then travis_wait 30 ./util/travis-sauce-test.sh; fi\nenv:\n  global:\n  - secure: bfF/o1ewpOxDNqTzWfvlwgRgGfP8OXhSQLLdEwZ6izO9tckMJuSNghk3qBXCEQJwTcUEyXP6EqfzIrRAvDXPa0H3OoinbrooDyV2wIDaVRK++WR2iZIqzqo3hGOdzm4tdrGJZe5av5Rk661Hls8aPfLbjdzcGuYXi8B4wZq2xMI=\n  - secure: jBrKtQBdoL2dsXi9BQpw5tMkYZOsQAy2iSB+0xPOxhPI8EbXKnm8OhWQDEJ5TdduLWUxLLc12IJwjBy9ocLlC1ZvzgOXNfqOUkLD03qSPnyT/LomTXeP4XuojUAemc/w1MHd61nFz4YJaO8cQ+yfy6GOX2susabW+Y80mnIeGJk=\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Change Log\n\n## [v3.5.2] (2024-10-07)\n- FlattenedNodesObserver.getFlattenedNodes was accidentally quadratic if given a non-slot node. Found by @mvanbem-goog.\n\n## [v3.5.1](https://github.com/Polymer/polymer/tree/v3.5.1) (2022-06-03)\n- [ci skip] bump to 3.5.1 ([commit](https://github.com/Polymer/polymer/commit/2cbb3d2b))\n\n- `_valueToNodeAttribute` converts the empty string to `trustedTypes.emptyScript` before setting, if available. ([commit](https://github.com/Polymer/polymer/commit/d69041cc))\n\n- Adds Trusted Types support for reflected boolean properties. ([commit](https://github.com/Polymer/polymer/commit/ce474db9))\n\n- [ci skip] update changelog ([commit](https://github.com/Polymer/polymer/commit/76e77b6d))\n\n## [v3.5.0](https://github.com/Polymer/polymer/tree/v3.5.0) (2022-05-18)\n- [ci skip] bump to 3.5.0 ([commit](https://github.com/Polymer/polymer/commit/a800a1a9))\n\n- Add `CHANGELOG.md` to the packaged files. ([commit](https://github.com/Polymer/polymer/commit/6696976e))\n\n- Upstream http://cl/374717449 ([commit](https://github.com/Polymer/polymer/commit/adc6d517))\n\n- Upstream http://cl/362104095 ([commit](https://github.com/Polymer/polymer/commit/96897876))\n\n- Upstream http://cl/368587394 ([commit](https://github.com/Polymer/polymer/commit/4036db44))\n\n- Upstream http://cl/330613283 ([commit](https://github.com/Polymer/polymer/commit/178dfa5e))\n\n- Upstream http://cl/397536696 ([commit](https://github.com/Polymer/polymer/commit/2445554f))\n\n- Upstream http://cl/374930792 ([commit](https://github.com/Polymer/polymer/commit/4a85c7f9))\n\n- Upstream http://cl/438642754 ([commit](https://github.com/Polymer/polymer/commit/8582dd64))\n\n- Upstream http://cl/387624221 ([commit](https://github.com/Polymer/polymer/commit/067dd302))\n\n- Upstream http://cl/420889188 ([commit](https://github.com/Polymer/polymer/commit/d0d39b8d))\n\n- Upstream http://cl/416087593 ([commit](https://github.com/Polymer/polymer/commit/ec36597f))\n\n- Fix typo in dom-repeat.js ([commit](https://github.com/Polymer/polymer/commit/7b37193e))\n\n- Update polymer -> lit link to point at new lit repo instead of old lit-element repo ([commit](https://github.com/Polymer/polymer/commit/4586fed6))\n\n- Add support for TrustedTypes (#5692) ([commit](https://github.com/Polymer/polymer/commit/10220c9a))\n\n- Fix typo in disable-upgrade-mixin.js ([commit](https://github.com/Polymer/polymer/commit/5c06ae9b))\n\n- Fix `Polymer.dom(el).attachShadow/shadowRoot` ([commit](https://github.com/Polymer/polymer/commit/2b0494a9))\n\n- Fix typo in dom-module.js ([commit](https://github.com/Polymer/polymer/commit/69eb8a7a))\n\n- Fix SyntaxError ([commit](https://github.com/Polymer/polymer/commit/1e9be28d))\n\n- Upstream internal error suppression. ([commit](https://github.com/Polymer/polymer/commit/2515cd21))\n\n- Updated Readme ([commit](https://github.com/Polymer/polymer/commit/78602fcc))\n\n- Fix let back to const ([commit](https://github.com/Polymer/polymer/commit/04a4ded8))\n\n- Cancel chunking when disconnected. Fixes #5667 ([commit](https://github.com/Polymer/polymer/commit/32d7d61d))\n\n- Accept function in legacy _template field for template parsing. Fixes #5660 ([commit](https://github.com/Polymer/polymer/commit/22ac86a8))\n\n- Upstream internal type differences. ([commit](https://github.com/Polymer/polymer/commit/9e8df682))\n\n- Remove types from LegacyElementMixin's overridden setAttribute and removeAttribute. ([commit](https://github.com/Polymer/polymer/commit/00b36709))\n\n- [ci skip] update changelog ([commit](https://github.com/Polymer/polymer/commit/6acf6e3c))\n\n## [v3.4.1](https://github.com/Polymer/polymer/tree/v3.4.1) (2020-04-29)\n- [ci skip] bump to 3.4.1 ([commit](https://github.com/Polymer/polymer/commit/12fa1b50))\n\n- Add type for DomApiNative's setAttribute method. ([commit](https://github.com/Polymer/polymer/commit/024ab01e))\n\n- Remove gen-typescript-declarations; manually add LegacyElementMixin's setAttribute type. ([commit](https://github.com/Polymer/polymer/commit/e717f0f0))\n\n- Remove \"DO NOT EDIT\" warning comments. ([commit](https://github.com/Polymer/polymer/commit/8b2ea7bc))\n\n- Track TypeScript declarations. ([commit](https://github.com/Polymer/polymer/commit/ec7b7c55))\n\n- Update Closure types for overridden setAttribute in LegacyElementMixin. ([commit](https://github.com/Polymer/polymer/commit/604856b2))\n\n- Add method / parameter descriptions. ([commit](https://github.com/Polymer/polymer/commit/370ae5eb))\n\n- Fix TypeScript breakages by specifying types for overridden `setAttribute` and `getAttribute`. ([commit](https://github.com/Polymer/polymer/commit/c8715b50))\n\n- Add complete commit list for v3.4.0 ([commit](https://github.com/Polymer/polymer/commit/e47493b0))\n\n- Fix a couple more compiler warnings ([commit](https://github.com/Polymer/polymer/commit/ad2bca18))\n\n- Typos and other minor changes. ([commit](https://github.com/Polymer/polymer/commit/a55e248d))\n\n- Add a note about a bug fix for <dom-repeat> chunking. ([commit](https://github.com/Polymer/polymer/commit/002c98a0))\n\n- Add `useAdoptedStyleSheetsWithBuiltCSS` section. ([commit](https://github.com/Polymer/polymer/commit/d9fc4fbf))\n\n- Add setters to settings titles. ([commit](https://github.com/Polymer/polymer/commit/9c78b481))\n\n- Add a note about `orderedComputed` and cycles. ([commit](https://github.com/Polymer/polymer/commit/c181c3d8))\n\n- Add example of overriding `suppressTemplateNotifications` via `notify-dom-change`. ([commit](https://github.com/Polymer/polymer/commit/1fa4948b))\n\n- Add a section about automatic use of constructable stylesheets. ([commit](https://github.com/Polymer/polymer/commit/d9c18b47))\n\n- Add \"Other new features\" section for `reuseChunkedInstances` and `LegacyElementMixin`'s built-in `disable-upgrade` support. ([commit](https://github.com/Polymer/polymer/commit/7a2e9f81))\n\n- Added notes for `fastDomIf`, `removeNestedTemplates`, `suppressNestedTemplates`, and `suppressTemplateNotifications`. ([commit](https://github.com/Polymer/polymer/commit/3b6494bf))\n\n- Started on release notes for `legacyUndefined`, `legacyWarnings`, `orderedComputed`. (...) ([commit](https://github.com/Polymer/polymer/commit/d80fdca0))\n\n- Remove unused externs. ([commit](https://github.com/Polymer/polymer/commit/0da4e63f))\n\n## [v3.4.0](https://github.com/Polymer/polymer/tree/v3.4.0) (2020-04-23)\n\n### New global settings\n\nThis update to Polymer includes some new [global settings](https://polymer-library.polymer-project.org/3.0/docs/devguide/settings):\n\n- `legacyUndefined` / `setLegacyUndefined`\n\n  **What does it do?** This setting reverts how computed properties handle `undefined` values to the Polymer 1 behavior: when enabled, computed properties will only be recomputed if none of their dependencies are `undefined`.\n\n  Components can override the global setting by setting their `_overrideLegacyUndefined` property to `true`. This is useful for reenabling the default behavior as you migrate individual components:\n\n  ```js\n  import {PolymerElement, html} from '@polymer/polymer/polymer-element.js';\n\n  class MigratedElement extends PolymerElement { /* ... */ }\n\n  // All MigratedElement instances will use the default behavior.\n  MigratedElement.prototype._overrideLegacyUndefined = true;\n\n  customElements.define('migrated-element', SomeElement);\n  ```\n\n  **Should I use it?** This setting should only be used for migrating legacy codebases that depend on this behavior and is otherwise **not recommended**.\n\n- `legacyWarnings` / `setLegacyWarnings`\n\n  **What does it do?** This setting causes Polymer to warn if a component's template contains bindings to properties that are not listed in that element's [`properties` block](https://polymer-library.polymer-project.org/3.0/docs/devguide/properties). For example:\n\n  ```js\n  import {PolymerElement, html} from '@polymer/polymer/polymer-element.js';\n\n  class SomeElement extends PolymerElement {\n    static get template() {\n      return html`<span>[[someProperty]] is used here</span>`;\n    }\n\n    static get properties() {\n      return { /* but `someProperty` is not declared here */ };\n    }\n  }\n\n  customElements.define('some-element', SomeElement);\n  ```\n\n  Only properties explicitly declared in the `properties` block are [associated with an attribute](https://polymer-library.polymer-project.org/3.0/docs/devguide/properties#property-name-mapping) and [update when that attribute changes](https://polymer-library.polymer-project.org/3.0/docs/devguide/properties#attribute-deserialization). Enabling this setting will show you where you might have forgotten to declare properties.\n\n  **Should I use it?** Consider using this feature during development but don't enable it in production.\n\n- `orderedComputed` / `setOrderedComputed`\n\n  **What does it do?** This setting causes Polymer to topologically sort each component's computed properties graph when the class is initialized and uses that order whenever computed properties are run.\n\n  For example:\n\n  ```js\n  import {PolymerElement, html} from '@polymer/polymer/polymer-element.js';\n\n  class SomeElement extends PolymerElement {\n    static get properties() {\n      return {\n        a: {type: Number, value: 0},\n        b: {type: Number, computed: 'computeB(a)'},\n        c: {type: Number, computed: 'computeC(a, b)'},\n      };\n    }\n\n    computeB(a) {\n      console.log('Computing b...');\n      return a + 1;\n    }\n\n    computeC(a, b) {\n      console.log('Computing c...');\n      return (a + b) * 2;\n    }\n  }\n\n  customElements.define('some-element', SomeElement);\n  ```\n\n  When `a` changes, Polymer's default behavior does not specify the order in which its dependents will run. Given that both `b` and `c` depend directly on `a`, one of two possible orders could occur: [`computeB`, `computeC`] or [`computeC`, `computeB`].\n\n  - In the first case - [`computeB`, `computeC`] - `computeB` is run with the new value of `a` and produces a new value for `b`. Then, `computeC` is run with both the new values of `a` and `b` to produce `c`.\n\n  - In the second case - [`computeC`, `computeB`] - `computeC` is run first with the new value of `a` and the _current_ value of `b` to produce `c`. Then, `computeB` is run with the new value of `a` to produce `b`. If `computeB` changed the value of `b` then `computeC` will be run again, with the new values of both `a` and `b` to produce the final value of `c`.\n\n  However, with `orderedComputed` enabled, the computed properties would have been previously sorted into [`computeB`, `computeC`], so updating `a` would cause them to run specifically in that order.\n\n  If your component's computed property graph contains cycles, the order in which they are run when using `orderedComputed` is still undefined.\n\n  **Should I use it?** The value of this setting depends on how your computed property functions are implemented. If they are pure and relatively inexpensive, you shouldn't need to enable this feature. If they have side effects that would make the order in which they are run important or are expensive enough that it would be a problem to run them multiple times for a property update, consider enabling it.\n\n- `fastDomIf` / `setFastDomIf`\n\n  **What does it do?** This setting enables a different implementation of `<dom-if>` that uses its host element's template stamping facilities (provided as part of `PolymerElement`) rather than including its own. This setting can help with performance but comes with a few caveats:\n\n  - First, `fastDomIf` requires that every `<dom-if>` is in the shadow root of a Polymer element: you can't use a `<dom-if>` directly in the main document or inside a shadow root of an element that doesn't extend `PolymerElement`.\n\n  - Second, because the `fastDomIf` implementation of `<dom-if>` doesn't include its own template stamping features, it doesn't create its own scope for property effects. This means that any properties you were previously setting on the `<dom-if>` will no longer be applied within its template, only properties of the host element are available.\n\n  **Should I use it?** This setting is recommended as long as your app doesn't use `<dom-if>` as described in the section above.\n\n- `removeNestedTemplates` / `setRemoveNestedTemplates`\n\n  **What does it do?** This setting causes Polymer to remove the child `<template>` elements used by `<dom-if>` and `<dom-repeat>` from the their containing templates. This can improve the performance of cloning your component's template when new instances are created.\n\n  **Should I use it?** This setting is generally recommended.\n\n- `suppressTemplateNotifications` / `setSuppressTemplateNotifications`\n\n  **What does it do?** This setting causes `<dom-if>` and `<dom-repeat>` not to dispatch `dom-change` events when their rendered content is updated. If you're using lots of `<dom-if>` and `<dom-repeat>` but not listening for these events, this setting lets you disable them and their associated dispatch work.\n\n  You can override the global setting for an individual `<dom-if>` or `<dom-repeat>` by setting its `notify-dom-change` boolean attribute:\n\n  ```js\n  import {PolymerElement, html} from '@polymer/polymer/polymer-element.js';\n\n  class SomeElement extends PolymerElement {\n    static get properties() {\n      return {\n        visible: {type: Boolean, value: false},\n      };\n    }\n\n    static get template() {\n      return html`\n        <button on-click=\"_toggle\">Toggle</button>\n        <!-- Set notify-dom-change to enable dom-change events for this particular <dom-if>. -->\n        <dom-if if=\"[[visible]]\" notify-dom-change on-dom-change=\"_onDomChange\">\n          <template>\n            Hello!\n          </template>\n        </dom-if>\n      `;\n    }\n\n    _toggle() {\n      this.visible = !this.visible;\n    }\n\n    _onDomChange(e) {\n      console.log(\"Received 'dom-change' event.\");\n    }\n  }\n\n  customElements.define('some-element', SomeElement);\n  ```\n\n  **Should I use it?** This setting is generally recommended.\n\n- `legacyNoObservedAttributes` / `setLegacyNoObservedAttributes`\n\n  **What does it do?** This setting causes `LegacyElementMixin` not to use the browser's built-in mechanism for informing elements of attribute changes (i.e. `observedAttributes` and `attributeChangedCallback`), which lets Polymer skip computing the list of attributes it tells the browser to observe. Instead, `LegacyElementMixin` simulates this behavior by overriding attribute APIs on the element and calling `attributeChangedCallback` itself.\n\n  This setting has similar API restrictions to those of the [custom elements polyfill](https://github.com/webcomponents/polyfills/tree/master/packages/custom-elements). You should only use the element's `setAttribute` and `removeAttribute` methods to modify attributes: using (e.g.) the element's `attributes` property to modify its attributes is not supported with `legacyNoObservedAttributes` and won't properly trigger `attributeChangedCallback` or any property effects.\n\n  Components can override the global setting by setting their `_legacyForceObservedAttributes` property to `true`. This property's effects occur at startup; it won't have any effect if modified at runtime and should be set in the class definition.\n\n  **Should I use it?** This setting should only be used if startup time is significantly affected by Polymer's class initialization work - for example, if you have a large number of components being loaded but are only instantiating a small subset of them. Otherwise, this setting is **not recommended**.\n\n- `useAdoptedStyleSheetsWithBuiltCSS` / `setUseAdoptedStyleSheetsWithBuiltCSS`\n\n  **What does it do?** If your application is uses [pre-built Shady CSS styles](https://github.com/polymer/polymer-css-build) and your browser supports [constructable stylesheet objects](https://wicg.github.io/construct-stylesheets/), this setting will cause Polymer to extract all `<style>` elements from your components' templates, join them into a single stylesheet, and share this stylesheet with all instances of the component using their shadow roots' [`adoptedStyleSheets`](https://wicg.github.io/construct-stylesheets/#dom-documentorshadowroot-adoptedstylesheets) array. This setting may improve your components' memory usage and performance depending on how many instances you create and how large their style sheets are.\n\n  **Should I use it?** Consider using this setting if your app already uses pre-built Shady CSS styles. Note that position-dependent CSS selectors (e.g. containing `:nth-child()`) may become unreliable for siblings of your components' styles as a result of runtime-detected browser support determining if styles are removed from your components' shadow roots.\n\n### Other new features\n\n#### `<dom-repeat>`\n\n- `reuseChunkedInstances`\n\n  **What does it do?** This boolean property causes `<dom-repeat>` to reuse template instances even when `items` is replaced with a new array, matching the Polymer 1 behavior.\n\n  By default, a `<dom-repeat>` with chunking enabled (i.e. `initialCount` >= 0) will drop all previously rendered template instances and create new ones whenever the `items` array is replaced. With `reuseChunkedInstances` set, any previously rendered template instances will instead be repopulated with data from the new array before new instances are created.\n\n  **Should I use it?** This flag is generally recommended and can improve rendering performance of chunked `<dom-repeat>` instances with live data.\n\n#### `LegacyElementMixin`\n\n- `disable-upgrade`\n\n  **What does it do?** `LegacyElementMixin` now has built-in support for the `disable-upgrade` attribute (usually provided by [`DisableUpgradeMixin`](https://polymer-library.polymer-project.org/3.0/api/mixins/disable-upgrade-mixin)) that becomes active when the global `legacyOptimizations` setting is enabled, matching the Polymer 1 behavior.\n\n  **Should I use it?** Consider using this setting if you are already using the `legacyOptimizations` setting and migrating older components that depend on `disable-upgrade` without explicit application of `DisableUpgradeMixin`.\n\n### Bug fixes\n\n#### `<dom-repeat>`\n\n- Chunking behavior\n\n  `<dom-repeat>` no longer resets the number of rendered instances to `initialCount` when modifying `items` with `PolymerElement`'s array modification methods ([`splice`](https://polymer-library.polymer-project.org/3.0/api/mixins/element-mixin#ElementMixin-method-splice), [`push`](https://polymer-library.polymer-project.org/3.0/api/mixins/element-mixin#ElementMixin-method-push), etc.). The number of rendered instances will only be reset to `initialCount` if the `items` array itself is replaced with a new array object.\n\n  See [#5631](https://github.com/Polymer/polymer/issues/5631) for more information.\n\n### All commits\n\n- [ci skip] bump to 3.4.0 ([commit](https://github.com/Polymer/polymer/commit/08585311))\n\n- `shareBuiltCSSWithAdoptedStyleSheets` -> `useAdoptedStyleSheetsWithBuiltCSS` ([commit](https://github.com/Polymer/polymer/commit/33e14986))\n\n- formatting ([commit](https://github.com/Polymer/polymer/commit/d0848d83))\n\n- Fix incorrect JSDoc param name. ([commit](https://github.com/Polymer/polymer/commit/c0813cd3))\n\n- Gate feature behind `shareBuiltCSSWithAdoptedStyleSheets`; update tests. ([commit](https://github.com/Polymer/polymer/commit/bdd76581))\n\n- Add `shareBuiltCSSWithAdoptedStyleSheets` global setting ([commit](https://github.com/Polymer/polymer/commit/2fc9062d))\n\n- Add stalebot config ([commit](https://github.com/Polymer/polymer/commit/b8362abb))\n\n- Annotate more return types as !defined (#5642) ([commit](https://github.com/Polymer/polymer/commit/20b207e1))\n\n- Ensure any previously enqueued rAF is canceled when re-rendering. Also, use instances length instead of renderedItemCount since it will be undefined on first render. ([commit](https://github.com/Polymer/polymer/commit/ddb37df9))\n\n- Improve comment. ([commit](https://github.com/Polymer/polymer/commit/d92ff92f))\n\n- Remove obsolete tests. ([commit](https://github.com/Polymer/polymer/commit/91f01e57))\n\n- Simplify by making limit a derived value from existing state. This centralizes the calculation of limit based on changes to other state variables. ([commit](https://github.com/Polymer/polymer/commit/b5664cba))\n\n- Update Sauce config to drop Safari 9, add 12 & 13. Safari 9 is now very old, and has micro task ordering bugs issues that make testing flaky. ([commit](https://github.com/Polymer/polymer/commit/a02ed026))\n\n- Remove accidental commit of test.only ([commit](https://github.com/Polymer/polymer/commit/d67a8b51))\n\n- When re-enabling, ensure __limit is at a good starting point and add a test for that. Also: * Ensure `__itemsArrayChanged` is cleared after every render. * Enqueue `__continueChunkingAfterRaf` before notifying renderedItemCount for safety ([commit](https://github.com/Polymer/polymer/commit/1d96db3c))\n\n- Remove accidental commit of suite.only ([commit](https://github.com/Polymer/polymer/commit/b503db15))\n\n- Ensure limit is reset when initialCount is disabled. Note that any falsey value for initialCount (including `0`) is interpreted as \"chunking disabled\". This is consistent with 1.x logic, and follows from the logic of \"starting chunking by rendering zero items\" doesn't really make sense. ([commit](https://github.com/Polymer/polymer/commit/60f6ccfb))\n\n- Updates from review. * Refactoring `__render` for readability * Removing `__pool`; this was never used in v2: since we reset the pool every update and items are only ever pushed at detach time and we only detach at the end of updates (as opposed to v1 which had more sophisticated splicing) ([commit](https://github.com/Polymer/polymer/commit/0797488b))\n\n- Store syncInfo on the dom-if, but null it in teardown. (same as invalidProps for non-fastDomIf) ([commit](https://github.com/Polymer/polymer/commit/fe86a8c8))\n\n- Fixes for several related dom-repeat chunking issues. Fixes #5631. * Only restart chunking (resetting the list to the initialCount) if the `items` array itself changed (and not splices to the array), to match Polymer 1 behavior. * Add `reuseChunkedInstances` option to allow reusing instances even when `items` changes; this is likely the more common optimal case when using immutable data, but making it optional for backward compatibility. * Only measure render time and throttle the chunk size if we rendered a full chunk of new items. Ensures that fast re-renders of existing items don't cause the chunk size to scale up dramatically, subsequently causing too many new items to be created in one chunk. * Increase the limit by the chunk size as part of any render if there are new items to render, rather than only as a result of rendering. * Continue chunking by comparing the filtered item count to the limit (not the unfiltered item count). ([commit](https://github.com/Polymer/polymer/commit/b40840b9))\n\n- Update comment. ([commit](https://github.com/Polymer/polymer/commit/b9bbee2c))\n\n- Store syncInfo on instance and don't sync paths. Fixes #5629 ([commit](https://github.com/Polymer/polymer/commit/353eabde))\n\n- Avoid Array.find (doesn't exist in IE) ([commit](https://github.com/Polymer/polymer/commit/5383f5f2))\n\n- Add comment to skip. ([commit](https://github.com/Polymer/polymer/commit/7df89ae2))\n\n- Skip test when custom elements polyfill is in use ([commit](https://github.com/Polymer/polymer/commit/fb1a7835))\n\n- Copy flag to a single location rather than two. ([commit](https://github.com/Polymer/polymer/commit/688243b3))\n\n- Lint fix. ([commit](https://github.com/Polymer/polymer/commit/3fd96719))\n\n- Update test name. ([commit](https://github.com/Polymer/polymer/commit/dfd0e641))\n\n- Introduce opt-out per class for `legacyNoObservedAttributes` ([commit](https://github.com/Polymer/polymer/commit/eaca1954))\n\n- Ensure telemetry system works with `legacyNoObservedAttributes` setting ([commit](https://github.com/Polymer/polymer/commit/63addd39))\n\n- Update package-lock.json ([commit](https://github.com/Polymer/polymer/commit/a7ffc390))\n\n- Update test/unit/inheritance.html ([commit](https://github.com/Polymer/polymer/commit/47a54ef8))\n\n- Fix testing issues with latest webcomponentsjs ([commit](https://github.com/Polymer/polymer/commit/61a14c17))\n\n- Allow `undefined` in legacy _template field to fall-through to normal lookup path. ([commit](https://github.com/Polymer/polymer/commit/220099cf))\n\n- re-add npm cache ([commit](https://github.com/Polymer/polymer/commit/700c2b0c))\n\n- regen package-lock ([commit](https://github.com/Polymer/polymer/commit/168572a7))\n\n- mispelled services, node 10 for consistency ([commit](https://github.com/Polymer/polymer/commit/15dba241))\n\n- modernize travis ([commit](https://github.com/Polymer/polymer/commit/148b2ea2))\n\n- Adds support for imperatively created elements to `legacyNoObservedAttributes` ([commit](https://github.com/Polymer/polymer/commit/28f12ca9))\n\n- Rebase sanitize dom value getter onto legacy-undefined-noBatch (#5618) ([commit](https://github.com/Polymer/polymer/commit/afdd9119))\n\n- Add getSanitizeDOMValue to settings API (#5617) ([commit](https://github.com/Polymer/polymer/commit/aec4cb68))\n\n- FIx closure annotation ([commit](https://github.com/Polymer/polymer/commit/15ce881f))\n\n- Fix closure annotation. ([commit](https://github.com/Polymer/polymer/commit/0427abe4))\n\n- `legacyNoObservedAttributes`: Ensure user created runs before attributesChanged ([commit](https://github.com/Polymer/polymer/commit/c6675db0))\n\n- Enable tests for `legacyNoObservedAttributes` ([commit](https://github.com/Polymer/polymer/commit/b8315d60))\n\n- Only auto-use disable-upgrade if legacyOptimizations is set. ([commit](https://github.com/Polymer/polymer/commit/99b87649))\n\n- Adds disable-upgrade functionality directly to LegacyElementMixin ([commit](https://github.com/Polymer/polymer/commit/a4b4723f))\n\n- Add doc comment ([commit](https://github.com/Polymer/polymer/commit/12c39131))\n\n- Lint fixes. ([commit](https://github.com/Polymer/polymer/commit/fa5570b1))\n\n- Update externs. ([commit](https://github.com/Polymer/polymer/commit/41df9a59))\n\n- Update extern format. ([commit](https://github.com/Polymer/polymer/commit/3c128fa2))\n\n- Address review feedback. ([commit](https://github.com/Polymer/polymer/commit/957c8c4d))\n\n- Address review feedback ([commit](https://github.com/Polymer/polymer/commit/f8dfaa56))\n\n- Lint fixes. ([commit](https://github.com/Polymer/polymer/commit/7b0c57a4))\n\n- Adds `legacyNoAttributes` setting ([commit](https://github.com/Polymer/polymer/commit/8ef2cc70))\n\n- [ci skip] update changelog ([commit](https://github.com/Polymer/polymer/commit/640bc80a))\n\n- Update polymer externs for new settings. ([commit](https://github.com/Polymer/polymer/commit/5d130fae))\n\n- Update lib/utils/settings.js ([commit](https://github.com/Polymer/polymer/commit/dbd9140a))\n\n- Changes based on review. ([commit](https://github.com/Polymer/polymer/commit/124d878e))\n\n- Add basic support for `adoptedStyleSheets` ([commit](https://github.com/Polymer/polymer/commit/ab04377b))\n\n- [ci skip] Add/fix comments per review. ([commit](https://github.com/Polymer/polymer/commit/cbc722b1))\n\n- Add missing externs for global settings. ([commit](https://github.com/Polymer/polymer/commit/7fa78973))\n\n- Revert optimization to not wrap change notifications. This was causing a number of rendering tests to fail. Needs investigation, but possibly because wrapping calls ShadyDOM.flush, and this alters distribution timing which some tests may have inadvertently relied on. ([commit](https://github.com/Polymer/polymer/commit/848e8c9b))\n\n- Reintroduce suppressTemplateNotifications and gate Dom-change & renderedItemCount on that. Matches Polymer 1 setting for better backward compatibility. ([commit](https://github.com/Polymer/polymer/commit/d64ee9ef))\n\n- Add notifyDomChange back to dom-if & dom-repeat to match P1. ([commit](https://github.com/Polymer/polymer/commit/e9e0cd17))\n\n- Simplify host stack, set __dataHost unconditionally, and make _registerHost patchable. ([commit](https://github.com/Polymer/polymer/commit/929d056b))\n\n- Move @private annotation to decorate class definition. ([commit](https://github.com/Polymer/polymer/commit/534654de))\n\n- Add type for _overrideLegacyUndefined. ([commit](https://github.com/Polymer/polymer/commit/a7866b36))\n\n- Attempt to fix travis issues ([commit](https://github.com/Polymer/polymer/commit/e2895403))\n\n- Revert `isAttached` change based on review feedback. Deemed a breaking change. ([commit](https://github.com/Polymer/polymer/commit/1ff51e68))\n\n- Update travis to use xenial distro and, latest Firefox, and node 10 ([commit](https://github.com/Polymer/polymer/commit/9c80994f))\n\n- Applies micro-optimizations and removes obsolete settings ([commit](https://github.com/Polymer/polymer/commit/280f4f0a))\n\n- Work around Closure Compiler bug to avoid upcoming type error ([commit](https://github.com/Polymer/polymer/commit/5382e2ca))\n\n- Only import each file once (#5588) ([commit](https://github.com/Polymer/polymer/commit/27779a32))\n\n- Avoid Array.from on Set. ([commit](https://github.com/Polymer/polymer/commit/991b0997))\n\n- Update nested template names. ([commit](https://github.com/Polymer/polymer/commit/dc0754ee))\n\n- Add runtime stamping tests around linking & unlinking effects. ([commit](https://github.com/Polymer/polymer/commit/9e106d82))\n\n- Ensure parent is linked to child templateInfo. Fixes fastDomIf unstopping issue. ([commit](https://github.com/Polymer/polymer/commit/5e1a8b6d))\n\n- Remove unused TemplateInfo properties from types. ([commit](https://github.com/Polymer/polymer/commit/5d6f34f5))\n\n- Add other used TemplateInfo property types. ([commit](https://github.com/Polymer/polymer/commit/93854364))\n\n- Add type for TemplateInfo#parent. ([commit](https://github.com/Polymer/polymer/commit/2697cf10))\n\n- [ci-skip] Add comment explaining confusing check in _addPropertyToAttributeMap ([commit](https://github.com/Polymer/polymer/commit/c65a58ae))\n\n- Ensure clients are flushed when runtime stamping via `_stampTemplate`. Maintains flush semantics with Templatizer stamping (relevant to fastDomIf, which is a switch between Templatizer-based stamping and runtime _stampTemplate-based stamping). Works around an issue with `noPatch` where nested undistributed dom-if's won't stamp.  The changes to the tests are to remove testing that the full host tree is correct since the host doing the runtime stamping will no longer be the DOM getRootNode().host at ready time (this is exactly the case with Templatizer, whose semantics we intend to match). ([commit](https://github.com/Polymer/polymer/commit/7e7febc3))\n\n- Fix template-finding issue with DisableUpgrade mixin. The existing rules are that `prototype._template` is first priority and dom-module via `is` is second priority _for a given class_. A subclass has a new shot at overriding the previous template either by defining a new `prototype._template` or a new `is` resulting in a dom-module lookup.  However, trivially subclassing a Polymer legacy element breaks these rules, since if there is no _own_ `prototype._template` on the current class, it will lookup a dom-module using `is` from up the entire prototype chain. This defeats the rule that a `prototype._template` on the superclass should have taken priority over its dom-module.  This change ensures that we only lookup dom-module if the class has an _own_ is property. ([commit](https://github.com/Polymer/polymer/commit/e534c3cf))\n\n- Fix issue with camel cased properties and disable-upgrade ([commit](https://github.com/Polymer/polymer/commit/f95fd327))\n\n- More closure fixes. ([commit](https://github.com/Polymer/polymer/commit/04ddc240))\n\n- closure fixes ([commit](https://github.com/Polymer/polymer/commit/2bb488c8))\n\n- lint fixes ([commit](https://github.com/Polymer/polymer/commit/11256634))\n\n- Fix issue with defaults overriding bound values when disable-upgrade is used. ([commit](https://github.com/Polymer/polymer/commit/cd6d5d01))\n\n- Add closure types ([commit](https://github.com/Polymer/polymer/commit/69140787))\n\n- Use DisbleUpgradeMixin in legacy class generation ([commit](https://github.com/Polymer/polymer/commit/2203dae3))\n\n- Add comment about why code is duplicated. ([commit](https://github.com/Polymer/polymer/commit/f4943890))\n\n- Add tests for connected/disconnected while disabled ([commit](https://github.com/Polymer/polymer/commit/658c885c))\n\n- Improve comments. ([commit](https://github.com/Polymer/polymer/commit/1e8b656c))\n\n- Added comments. ([commit](https://github.com/Polymer/polymer/commit/d6f3a9ff))\n\n- Fix typo and improve readbility ([commit](https://github.com/Polymer/polymer/commit/933995a0))\n\n- Enable disable-upgrade when `legacyOptimizations` is set to true ([commit](https://github.com/Polymer/polymer/commit/f2784343))\n\n- Remove use of Object.create on template info (significant perf impact). ([commit](https://github.com/Polymer/polymer/commit/309f77ba))\n\n- Attempt to sync host properties on every call to _showHideChildren. Fixes an issue where a dom-if that is toggled synchronously true-false-true could fail to sync properties invalidated while false, since the hidden state is only checked at render timing, and the newly added dirty-check could fail if the hidden state has been changed back to its initial value. ([commit](https://github.com/Polymer/polymer/commit/e772ed0c))\n\n- Add tests for extension and dom-if/repeat ([commit](https://github.com/Polymer/polymer/commit/2c264c67))\n\n- Update stand alone disable-upgrade mixin. ([commit](https://github.com/Polymer/polymer/commit/e0ba67c4))\n\n- Remove cruft from test ([commit](https://github.com/Polymer/polymer/commit/872094a2))\n\n- Simplify logic for disable-upgrade ([commit](https://github.com/Polymer/polymer/commit/9c6f2661))\n\n- Use a safer flag, based on internal testing. ([commit](https://github.com/Polymer/polymer/commit/c563d5a3))\n\n- Reorder based on review feedback. ([commit](https://github.com/Polymer/polymer/commit/b5f8a6de))\n\n- Fix closure type. ([commit](https://github.com/Polymer/polymer/commit/d32d300e))\n\n- Updated comment. ([commit](https://github.com/Polymer/polymer/commit/53119175))\n\n- Ensure hasPaths is also accumulated as part of info necessary to sync. ([commit](https://github.com/Polymer/polymer/commit/89d70557))\n\n- Fix one more closure annotation. ([commit](https://github.com/Polymer/polymer/commit/3d09455b))\n\n- Simplify algorithm; we already have list of computed deps in effect list. ([commit](https://github.com/Polymer/polymer/commit/064d0eff))\n\n- Build computed graph from dependencies, rather than properties. ([commit](https://github.com/Polymer/polymer/commit/567e4640))\n\n- Fix closure annotations for dom-if. ([commit](https://github.com/Polymer/polymer/commit/cee1893b))\n\n- Avoid lint warnings. ([commit](https://github.com/Polymer/polymer/commit/18adf5fb))\n\n- Minor simplifications/comments. ([commit](https://github.com/Polymer/polymer/commit/4f9fda06))\n\n- Updates from review. ([commit](https://github.com/Polymer/polymer/commit/f0cbc837))\n\n- Closure type fixes. ([commit](https://github.com/Polymer/polymer/commit/ff25283a))\n\n- Initialize all settings from Polymer object when available. ([commit](https://github.com/Polymer/polymer/commit/df1eb73b))\n\n- Fix host prop merging. ([commit](https://github.com/Polymer/polymer/commit/e4eb9f22))\n\n- Updates based on review. ([commit](https://github.com/Polymer/polymer/commit/39207cce))\n\n- Fix defaults back to false for new settings. ([commit](https://github.com/Polymer/polymer/commit/4bdbe925))\n\n- Add a dirty check to showHideChildren ([commit](https://github.com/Polymer/polymer/commit/0ba19b4e))\n\n- Fix host property syncing ([commit](https://github.com/Polymer/polymer/commit/fc693a09))\n\n- Adds disable-upgrade directly into legacy `Polymer` elements ([commit](https://github.com/Polymer/polymer/commit/9756d861))\n\n- Refactor DomIf into separate subclasses. ([commit](https://github.com/Polymer/polymer/commit/c2f31eda))\n\n- Runtime stamped dom-if ([commit](https://github.com/Polymer/polymer/commit/e690dfe2))\n\n- dom-if/dom-repeat bind-to-parent ([commit](https://github.com/Polymer/polymer/commit/27ed93af))\n\n- Fix a few closure compiler issues ([commit](https://github.com/Polymer/polymer/commit/d55b9cb5))\n\n- [ci skip] Add comment ([commit](https://github.com/Polymer/polymer/commit/70337ac8))\n\n- Fix typo in comment ([commit](https://github.com/Polymer/polymer/commit/61715f1d))\n\n- Cleanup, add tests. * remove old implementation * add API docs * rename some API * add dynamicFn to dep count * add test for method as dependency ([commit](https://github.com/Polymer/polymer/commit/b065d145))\n\n- [wip] Add additional topo-sort based algorithm. ([commit](https://github.com/Polymer/polymer/commit/7cda770e))\n\n- Dedupe against a single turn on only under orderedComputed ([commit](https://github.com/Polymer/polymer/commit/fc49a925))\n\n- Fix closure issues ([commit](https://github.com/Polymer/polymer/commit/42dd361f))\n\n- Add hasPaths optimziation ([commit](https://github.com/Polymer/polymer/commit/ef0efa6e))\n\n- Minor comment updates ([commit](https://github.com/Polymer/polymer/commit/9ed31895))\n\n- Evaluate computed property dependencies first. Fixes #5143 ([commit](https://github.com/Polymer/polymer/commit/832fcdec))\n\n- Add more externs ([commit](https://github.com/Polymer/polymer/commit/2ed3bfac))\n\n- Fix lint warnings ([commit](https://github.com/Polymer/polymer/commit/4151ef4d))\n\n- Add comments per review feedback ([commit](https://github.com/Polymer/polymer/commit/bef674a9))\n\n- Add legacyNotifyOrder.  Improve comments. ([commit](https://github.com/Polymer/polymer/commit/52fe20da))\n\n- Add test for literal-only static function. ([commit](https://github.com/Polymer/polymer/commit/4c65db8d))\n\n- Remove unnecessary literal check ([commit](https://github.com/Polymer/polymer/commit/bf05e383))\n\n- Simplify ([commit](https://github.com/Polymer/polymer/commit/11bdc39a))\n\n- Add templatizer warnings. Move to legacyWarnings flag. ([commit](https://github.com/Polymer/polymer/commit/aa63db00))\n\n- Add legacyUndefined and legacyNoBatch to externs ([commit](https://github.com/Polymer/polymer/commit/cc7d4cc8))\n\n- NOOP has to be an array for closure compiler ([commit](https://github.com/Polymer/polymer/commit/e351f4dd))\n\n- Add comments on warning limitations. ([commit](https://github.com/Polymer/polymer/commit/940d1a7a))\n\n- Ensure properties are set one-by-one at startup. ([commit](https://github.com/Polymer/polymer/commit/add77842))\n\n- Remove unnecessary qualification. ([commit](https://github.com/Polymer/polymer/commit/2874c86d))\n\n- Avoid over-warning on templatizer props and \"static\" dynamicFns. ([commit](https://github.com/Polymer/polymer/commit/c966eb1f))\n\n- Store splices directly on array when `legacyUndefined` is set ([commit](https://github.com/Polymer/polymer/commit/e29a3150))\n\n- Fix test ([commit](https://github.com/Polymer/polymer/commit/32c30837))\n\n- Add arg length check ([commit](https://github.com/Polymer/polymer/commit/6139e889))\n\n- Adds `legacyNoBatch` setting ([commit](https://github.com/Polymer/polymer/commit/363bef2c))\n\n- Add tests for `legacyUndefined` setting ([commit](https://github.com/Polymer/polymer/commit/52a559fc))\n\n- Adds `legacyUndefined` setting ([commit](https://github.com/Polymer/polymer/commit/987ae2c4))\n\n## [v3.3.1](https://github.com/Polymer/polymer/tree/v3.3.1) (2019-11-08)\n- [ci skip] bump to 3.3.1 ([commit](https://github.com/Polymer/polymer/commit/11f1f139))\n\n- Remove TimvdLippe from CODEOWNERS ([commit](https://github.com/Polymer/polymer/commit/b99c2997))\n\n- Add node field to PolymerDomApi ([commit](https://github.com/Polymer/polymer/commit/15747c83))\n\n- Improve types for the template field on Polymer elements. (#5596) ([commit](https://github.com/Polymer/polymer/commit/4274bcec))\n\n- Add module field ([commit](https://github.com/Polymer/polymer/commit/9a4d4d9a))\n\n- Wrap other `hasOwnProperty` checks in `JSCompiler_renameProperty`. ([commit](https://github.com/Polymer/polymer/commit/0541b21a))\n\n- Wrap `hasOwnProperty` checks for `__hasRegisterFinished` in `JSCompiler_renameProperty()`. ([commit](https://github.com/Polymer/polymer/commit/9e90fd2e))\n\n- Fix typing error in fixPlaceholder ([commit](https://github.com/Polymer/polymer/commit/f050ce9e))\n\n- Fix up comments based on feedback ([commit](https://github.com/Polymer/polymer/commit/ab49f51a))\n\n- Workaround bindings to textarea.placeholder in IE ([commit](https://github.com/Polymer/polymer/commit/61767da2))\n\n- Add additional externs (#5575) ([commit](https://github.com/Polymer/polymer/commit/69ee4688))\n\n- Make Closure compiler happier about ShadyDOM access ([commit](https://github.com/Polymer/polymer/commit/46ee2aec))\n\n- Remove other double import (#5565) ([commit](https://github.com/Polymer/polymer/commit/0d2c2e5d))\n\n- Only use CONST_CASE for constants. (#5564) ([commit](https://github.com/Polymer/polymer/commit/54f8b47f))\n\n- [skip ci] update changelog ([commit](https://github.com/Polymer/polymer/commit/ac12b3bc))\n\n## [v3.3.0](https://github.com/Polymer/polymer/tree/v3.3.0) (2019-06-24)\n- [ci skip] Update version to 3.3.0 ([commit](https://github.com/Polymer/polymer/commit/dd7c0d70))\n\n- Don't import/export from the same file twice (#5562) ([commit](https://github.com/Polymer/polymer/commit/94585c31))\n\n- Add @override, remove @attribute/@group/@hero/@homepage ([commit](https://github.com/Polymer/polymer/commit/ed7709f6))\n\n- Closure compilation tweaks ([commit](https://github.com/Polymer/polymer/commit/15090f26))\n\n- Add @return description ([commit](https://github.com/Polymer/polymer/commit/a6bff436))\n\n- Fix some Closure annotations ([commit](https://github.com/Polymer/polymer/commit/0810bf3e))\n\n- Pin to firefox 66 because of selenium error ([commit](https://github.com/Polymer/polymer/commit/f0fb532d))\n\n- Fix eslint errors. ([commit](https://github.com/Polymer/polymer/commit/6dfaa5f0))\n\n- Add some casts for places Closure doesn't understand constructor ([commit](https://github.com/Polymer/polymer/commit/10d43ce8))\n\n- Add new mixin annotations, remove GestureEventListeners alias ([commit](https://github.com/Polymer/polymer/commit/0ae14b9c))\n\n- Align signatures of attributeChangedCallback ([commit](https://github.com/Polymer/polymer/commit/4cc6c339))\n\n- Add @return annotation for PROPERTY_EFFECT_TYPES getter ([commit](https://github.com/Polymer/polymer/commit/3dd189c4))\n\n- Annotate __dataEnabled in a way analyzer understands ([commit](https://github.com/Polymer/polymer/commit/e4e9e2fb))\n\n- Fix old global namespace type annotation for TemplateInstanceBase ([commit](https://github.com/Polymer/polymer/commit/fc190dd5))\n\n- Add @suppress annotation for use of deprecated cssFromModules ([commit](https://github.com/Polymer/polymer/commit/54b1d78d))\n\n- Fix GestureEventListeners generated externs name. ([commit](https://github.com/Polymer/polymer/commit/cdd4e204))\n\n- Globally hide dom-{bind,if,repeat} elements with legacyOptmizations on ([commit](https://github.com/Polymer/polymer/commit/43f57b10))\n\n- Update dependencies to fix firefox 67 tests ([commit](https://github.com/Polymer/polymer/commit/ff2edd5c))\n\n- Sync closure compiler annotations ([commit](https://github.com/Polymer/polymer/commit/ad084201))\n\n- remove unused variable in test ([commit](https://github.com/Polymer/polymer/commit/c051c5bb))\n\n- remove debugger line ([commit](https://github.com/Polymer/polymer/commit/634d736c))\n\n- Make sure scopeSubtree does not recurse through other ShadowRoots ([commit](https://github.com/Polymer/polymer/commit/8a5c1e9b))\n\n- Don't set display: none under legacyOptimizations. Fixes #5541. ([commit](https://github.com/Polymer/polymer/commit/c9cf56c0))\n\n- Use Array.from instead of a list comprehension ([commit](https://github.com/Polymer/polymer/commit/338d420c))\n\n- Add check for // ([commit](https://github.com/Polymer/polymer/commit/3db56085))\n\n- Use native qSA ([commit](https://github.com/Polymer/polymer/commit/e10019a0))\n\n- Implement scopeSubtree for ShadyDOM noPatch mode ([commit](https://github.com/Polymer/polymer/commit/6bc95340))\n\n- Remove unneccessary test ([commit](https://github.com/Polymer/polymer/commit/1f080595))\n\n- Add URL try/catch ([commit](https://github.com/Polymer/polymer/commit/940b3cdc))\n\n- Upstreaming cl/245273850 ([commit](https://github.com/Polymer/polymer/commit/413ef2fb))\n\n- Allow configuring cancelling synthetic click behavior ([commit](https://github.com/Polymer/polymer/commit/00d4cdf4))\n\n- Add test for class$ binding ([commit](https://github.com/Polymer/polymer/commit/8043d4c1))\n\n- Fix class$ bindings for ShadyDOM.noPatch mode ([commit](https://github.com/Polymer/polymer/commit/a0b83b25))\n\n- Add test for resolveUrl('//') ([commit](https://github.com/Polymer/polymer/commit/55373808))\n\n- Check directly for // in resolveUrl because it isn't a valid URL ([commit](https://github.com/Polymer/polymer/commit/d0ea20a1))\n\n- Run resolveUrl for protocol-relative urls (#5530) ([commit](https://github.com/Polymer/polymer/commit/733cf683))\n\n- Fix lint ([commit](https://github.com/Polymer/polymer/commit/6960c2b9))\n\n- Cast GestureEventListeners. ([commit](https://github.com/Polymer/polymer/commit/34373349))\n\n- Work around https://github.com/google/closure-compiler/issues/3240 ([commit](https://github.com/Polymer/polymer/commit/cc7702b4))\n\n- Fix `localTareget` when `ShadyDOM.noPatch` is in use ([commit](https://github.com/Polymer/polymer/commit/7925254b))\n\n- webcomponentsjs 2.2.10 ([commit](https://github.com/Polymer/polymer/commit/002a4319))\n\n- upgrade dependencies. ([commit](https://github.com/Polymer/polymer/commit/3b7c9f8e))\n\n- upgrade webcomponentsjs to 2.2.9 ([commit](https://github.com/Polymer/polymer/commit/4e60395a))\n\n- [ci skip] Add comment ([commit](https://github.com/Polymer/polymer/commit/c7eb7c19))\n\n- Use `attachShadow({shadyUpgradeFragment})` ([commit](https://github.com/Polymer/polymer/commit/3af9f340))\n\n- Remove test.only ([commit](https://github.com/Polymer/polymer/commit/ca124480))\n\n- Ensure wildcard arguments get undefined treatment. Fixes #5428. ([commit](https://github.com/Polymer/polymer/commit/f5a45ebc))\n\n- Fix typo ([commit](https://github.com/Polymer/polymer/commit/6adbc23c))\n\n- Fix `className` on browsers without good native accessors ([commit](https://github.com/Polymer/polymer/commit/b13e656f))\n\n- don't depend on `attachDom` existing. ([commit](https://github.com/Polymer/polymer/commit/8d7def72))\n\n- Simplify ([commit](https://github.com/Polymer/polymer/commit/f1a9d4fa))\n\n- Avoid upgrading template if no hostProps, for better perf. ([commit](https://github.com/Polymer/polymer/commit/65a5b48c))\n\n- Update webcomponents dev dependency for testing className fix ([commit](https://github.com/Polymer/polymer/commit/a1c67e45))\n\n- fix closure compiler error ([commit](https://github.com/Polymer/polymer/commit/002ef94e))\n\n- fix lint issues ([commit](https://github.com/Polymer/polymer/commit/439c2455))\n\n- Address review feedback via comment. ([commit](https://github.com/Polymer/polymer/commit/4e1d6a1a))\n\n- Ensure `className` bindings work correctly when `ShadyDOM.noPatch` is used. ([commit](https://github.com/Polymer/polymer/commit/eb2385aa))\n\n- Remove use of TreeWalker for finding nodes in templates. ([commit](https://github.com/Polymer/polymer/commit/24d642ec))\n\n- Remove Google+ links in README.md and CONTRIBUTING.MD ([commit](https://github.com/Polymer/polymer/commit/dc880571))\n\n- Use correct ShadyDOM API: `attachDom` ([commit](https://github.com/Polymer/polymer/commit/1aeaa801))\n\n- Use `ShadyDOM.upgrade` ([commit](https://github.com/Polymer/polymer/commit/50ba9cea))\n\n## [v3.2.0](https://github.com/Polymer/polymer/tree/v3.2.0) (2019-03-21)\n- [ci skip] update polymer version ([commit](https://github.com/Polymer/polymer/commit/48769c4b))\n\n- Fix lint ([commit](https://github.com/Polymer/polymer/commit/4cd70333))\n\n- Add tests. ([commit](https://github.com/Polymer/polymer/commit/5886be5d))\n\n- Ensure debouncer is removed from queue before running callback. ([commit](https://github.com/Polymer/polymer/commit/a23ac645))\n\n- Don't clear set at end for flush reentrancy safety; canceling removes from set ([commit](https://github.com/Polymer/polymer/commit/3b164761))\n\n- Assert the callback was called. ([commit](https://github.com/Polymer/polymer/commit/d48336d6))\n\n- Ensure the debouncer is not already canceled before canceling. ([commit](https://github.com/Polymer/polymer/commit/fed97654))\n\n- Fix a couple of closure type issues. * gestures - update internal type changes * debounce - fix mistaken return type ([commit](https://github.com/Polymer/polymer/commit/eb725f7f))\n\n- Revert to `getStyle()` ([commit](https://github.com/Polymer/polymer/commit/03aec686))\n\n- Fix getStyle definition ([commit](https://github.com/Polymer/polymer/commit/f13dd75f))\n\n- Add extra test ([commit](https://github.com/Polymer/polymer/commit/62cf9d98))\n\n- Use in check rather than undefined. ([commit](https://github.com/Polymer/polymer/commit/c467c345))\n\n- Allow value to merge from previous behavior property declaration. Fixes #5503 ([commit](https://github.com/Polymer/polymer/commit/bc258d6f))\n\n- Fix/suppress upcoming JSCompiler build errors ([commit](https://github.com/Polymer/polymer/commit/0d0da569))\n\n- Add comment about flush order when re-debouncing ([commit](https://github.com/Polymer/polymer/commit/b63c887f))\n\n- FIx lint ([commit](https://github.com/Polymer/polymer/commit/1e56b0e9))\n\n- Remove debug code ([commit](https://github.com/Polymer/polymer/commit/cc6ef0e1))\n\n- Re-add the queue removal in setConfig ([commit](https://github.com/Polymer/polymer/commit/be1afacc))\n\n- Remove debug code ([commit](https://github.com/Polymer/polymer/commit/b750a52d))\n\n- Remove test.only ([commit](https://github.com/Polymer/polymer/commit/1526626b))\n\n- Fix order of flushed debouncers to match 1.x ([commit](https://github.com/Polymer/polymer/commit/b9d49597))\n\n- Add comments and avoid Array.fill ([commit](https://github.com/Polymer/polymer/commit/567c10b3))\n\n- Use set and clear debouncer upon completion. Fixes #5250. ([commit](https://github.com/Polymer/polymer/commit/e8c24ff4))\n\n- Added comment based on review feedback. ([commit](https://github.com/Polymer/polymer/commit/764a233c))\n\n- Add property reflection to notify path and friends calls to support closure-compiler renaming. ([commit](https://github.com/Polymer/polymer/commit/ad05f567))\n\n- Add `classList` to `Polymer.dom` when `ShadyDOM.noPatch` is used ([commit](https://github.com/Polymer/polymer/commit/18ba9ae0))\n\n- Update externs from internal ([commit](https://github.com/Polymer/polymer/commit/e35a1a7c))\n\n- Use webcomponents 2.2.7 for initialSync tests ([commit](https://github.com/Polymer/polymer/commit/073d25f6))\n\n- Add `@fileoverview`, put `@suppress` after it ([commit](https://github.com/Polymer/polymer/commit/aba0f904))\n\n- address feedback ([commit](https://github.com/Polymer/polymer/commit/4321da01))\n\n- use JSCompiler_renameProperty bare ([commit](https://github.com/Polymer/polymer/commit/fb246562))\n\n- Remove semicolon after class definition (lint). ([commit](https://github.com/Polymer/polymer/commit/ae899c54))\n\n- Refactor symbols to make gen-typescript-declarations happy ([commit](https://github.com/Polymer/polymer/commit/4a24ba3c))\n\n- Ensure argument types match. ([commit](https://github.com/Polymer/polymer/commit/42735d11))\n\n- Backport closure compiler fixes from internal ([commit](https://github.com/Polymer/polymer/commit/e3c6b254))\n\n- Fix test warning in Edge/IE ([commit](https://github.com/Polymer/polymer/commit/a272506c))\n\n- Fix test in IE/Edge ([commit](https://github.com/Polymer/polymer/commit/391715fb))\n\n- Update package-lock ([commit](https://github.com/Polymer/polymer/commit/c93fc482))\n\n- Update webcomponents vesrion. ([commit](https://github.com/Polymer/polymer/commit/0a91b158))\n\n- Remove unused import ([commit](https://github.com/Polymer/polymer/commit/21e83e9e))\n\n- Add comment re: undefined issue ([commit](https://github.com/Polymer/polymer/commit/67caf458))\n\n- Move undeclared property warning to element-mixin. ([commit](https://github.com/Polymer/polymer/commit/11cd9cb2))\n\n- Add issue for TODO ([commit](https://github.com/Polymer/polymer/commit/d3f27d0a))\n\n- Upgrade wcjs ([commit](https://github.com/Polymer/polymer/commit/c309fef6))\n\n- Fix lint errors. ([commit](https://github.com/Polymer/polymer/commit/0c85340b))\n\n- Upgrade wcjs ([commit](https://github.com/Polymer/polymer/commit/09fa9854))\n\n- Updates based on review. ([commit](https://github.com/Polymer/polymer/commit/98304fb6))\n\n- Add better messaging for scoping test ([commit](https://github.com/Polymer/polymer/commit/4fcd9512))\n\n- Remove addressed TODO comment. ([commit](https://github.com/Polymer/polymer/commit/28f2281b))\n\n- Clarify warning. Add comment. ([commit](https://github.com/Polymer/polymer/commit/9dea1f78))\n\n- Add warnings for disabling boolean settings. ([commit](https://github.com/Polymer/polymer/commit/35c48d89))\n\n- Upgrade webcomponentsjs ([commit](https://github.com/Polymer/polymer/commit/6bd15ccb))\n\n- Upgrade webcomponentsjs ([commit](https://github.com/Polymer/polymer/commit/2480b259))\n\n- Refactor to make code more readable, add tests, remove dead code. ([commit](https://github.com/Polymer/polymer/commit/c78f6799))\n\n- Adds `syncInitialRender` setting ([commit](https://github.com/Polymer/polymer/commit/d4857ecc))\n\n- Ensure that marshalArgs pulls wildcard info value from __data It currently pulls the value from `changedProps` rather than __data, meaning it could provide stale data for re-entrant changes. ([commit](https://github.com/Polymer/polymer/commit/4d99099d))\n\n- Fix lint warning ([commit](https://github.com/Polymer/polymer/commit/563bc858))\n\n- Add warning for redeclared computed properties. ([commit](https://github.com/Polymer/polymer/commit/007f3cc2))\n\n- Add warning for undeclared properties used in bindings. ([commit](https://github.com/Polymer/polymer/commit/63dadbf2))\n\n- Make initial distribution synchronous when `legacyOptimizations` is set ([commit](https://github.com/Polymer/polymer/commit/fc7858ce))\n\n- Ensure dispatchEvent is wrapped ([commit](https://github.com/Polymer/polymer/commit/491c2a77))\n\n- Disable auto `strip-whitespace` on template with legacyOptimizations ([commit](https://github.com/Polymer/polymer/commit/d577c8c8))\n\n- Add tests for calling Polymer() with ES6 class ([commit](https://github.com/Polymer/polymer/commit/3ff4ed1b))\n\n- use a regular for-loop intead of for-of ([commit](https://github.com/Polymer/polymer/commit/86db24cd))\n\n- Lint clean ([commit](https://github.com/Polymer/polymer/commit/bdcd37c5))\n\n- Remove `@override` from static methods on mixins. ([commit](https://github.com/Polymer/polymer/commit/f15b137d))\n\n- Externs should use var instead of let ([commit](https://github.com/Polymer/polymer/commit/7745d431))\n\n- Add @suppress annotations for missing property checks. ([commit](https://github.com/Polymer/polymer/commit/7f2d736a))\n\n- Allow `Polymer({})` calls with ES6 class ([commit](https://github.com/Polymer/polymer/commit/3624a140))\n\n- [wrap] Fix doc comment. ([commit](https://github.com/Polymer/polymer/commit/8e506028))\n\n- Fix typo ([commit](https://github.com/Polymer/polymer/commit/d8aac3b5))\n\n- Make sure `_valueToNodeAttribute` uses wrap ([commit](https://github.com/Polymer/polymer/commit/4e4d6fe4))\n\n- Suppress upcoming jscompiler errors. ([commit](https://github.com/Polymer/polymer/commit/cf2cd05e))\n\n- compromise with typescript and closure ([commit](https://github.com/Polymer/polymer/commit/e73285b3))\n\n- Closure typing fixes ([commit](https://github.com/Polymer/polymer/commit/e4b56e46))\n\n- Add type jsdoc to templatize root property. ([commit](https://github.com/Polymer/polymer/commit/0da022fd))\n\n- Remove meaningless \"undefined\" in settings.js ([commit](https://github.com/Polymer/polymer/commit/fcc87527))\n\n- Make `noPatch` safe with older versions of ShadyDOM ([commit](https://github.com/Polymer/polymer/commit/a2e597c2))\n\n- Temporarily disable type genration ([commit](https://github.com/Polymer/polymer/commit/bade986e))\n\n- Changes based on review. ([commit](https://github.com/Polymer/polymer/commit/8954c251))\n\n- Changes based on review. ([commit](https://github.com/Polymer/polymer/commit/42b13d0a))\n\n- More shady compatible wrapping ([commit](https://github.com/Polymer/polymer/commit/b8f3b79c))\n\n- Fix typos ([commit](https://github.com/Polymer/polymer/commit/acbe6496))\n\n- Update to match 2.x branch ([commit](https://github.com/Polymer/polymer/commit/e3b3baa7))\n\n- Revert \"Manual merge from `perf-opt-disable-upgrade` branch.\" ([commit](https://github.com/Polymer/polymer/commit/c3bd4d6f))\n\n- Update Polymer 3 package-lock. ([commit](https://github.com/Polymer/polymer/commit/dfe7a54c))\n\n- Update to webcomponentsjs 2.2.0 ([commit](https://github.com/Polymer/polymer/commit/51ebf4df))\n\n- Update to latest webcomponentsjs ([commit](https://github.com/Polymer/polymer/commit/2c560bc1))\n\n- Manual merge from `perf-opt-disable-upgrade` branch. ([commit](https://github.com/Polymer/polymer/commit/0f022dfe))\n\n- Remove double-import of settings ([commit](https://github.com/Polymer/polymer/commit/5422792f))\n\n- Document properties for eslint. ([commit](https://github.com/Polymer/polymer/commit/3a4db3b1))\n\n- Add back event tests. ([commit](https://github.com/Polymer/polymer/commit/1bce4f08))\n\n- Use closure-safe name ([commit](https://github.com/Polymer/polymer/commit/ed5f7f27))\n\n- Add tests ([commit](https://github.com/Polymer/polymer/commit/f3b66755))\n\n- Ensure properties and observers are interleaved per behavior ([commit](https://github.com/Polymer/polymer/commit/ad5cb268))\n\n- Ensure property values are always overridden by extendors/behaviors ([commit](https://github.com/Polymer/polymer/commit/2b35a74f))\n\n- Ensure `registered` is always called on element prototype ([commit](https://github.com/Polymer/polymer/commit/50ad018c))\n\n- err instead of air ([commit](https://github.com/Polymer/polymer/commit/ee68ea92))\n\n- Do lazy behavior copying only when `legacyOptimizations` is set ([commit](https://github.com/Polymer/polymer/commit/d64a9c27))\n\n- Behavior property copying fixes ([commit](https://github.com/Polymer/polymer/commit/310c7ead))\n\n- Ensure initial static classes are preserved when a class$ binding is present ([commit](https://github.com/Polymer/polymer/commit/65a3149b))\n\n- Get typescript compiling again. ([commit](https://github.com/Polymer/polymer/commit/bbf24c0c))\n\n- Remove extra space ([commit](https://github.com/Polymer/polymer/commit/82c9d17e))\n\n- Avoid copying certain properties from behaviors ([commit](https://github.com/Polymer/polymer/commit/cf30a8cc))\n\n- skip some tests that never really worked in ShadyDOM ([commit](https://github.com/Polymer/polymer/commit/e00bf993))\n\n- Move __activateDir into check instead of replace ([commit](https://github.com/Polymer/polymer/commit/ec00d26b))\n\n- Don't set up observer in ShadyDOM ([commit](https://github.com/Polymer/polymer/commit/08bc1ff5))\n\n- Manually merge changes from #5418 ([commit](https://github.com/Polymer/polymer/commit/d5e0043a))\n\n- Fix merge conflict around toggleAttribute ([commit](https://github.com/Polymer/polymer/commit/419dce63))\n\n- Get Polymer compiling clean under closure recommended flags ([commit](https://github.com/Polymer/polymer/commit/566dcfae))\n\n- Apply LegacyDataMixin to TemplatizeInstanceBase. Fixes #5422 ([commit](https://github.com/Polymer/polymer/commit/6dd34569))\n\n- TemplateStamp ([commit](https://github.com/Polymer/polymer/commit/d57e05e5))\n\n- Fixes #5420 ([commit](https://github.com/Polymer/polymer/commit/926a6735))\n\n- Lint fix ([commit](https://github.com/Polymer/polymer/commit/725d52c6))\n\n- Updates ported from `perf-opt` branch ([commit](https://github.com/Polymer/polymer/commit/a08c9840))\n\n- rename test file. ([commit](https://github.com/Polymer/polymer/commit/b211436f))\n\n- Check for ShadyDOM and `:dir` selectors before trying css transform ([commit](https://github.com/Polymer/polymer/commit/d290be90))\n\n- Rename Closure V1 compatibility PolymerDomApi types for TypeScript types. ([commit](https://github.com/Polymer/polymer/commit/b34b6fcb))\n\n- Hybrid compatibility for PolymerDomApi and Polymer.Iconset types. ([commit](https://github.com/Polymer/polymer/commit/b8e30021))\n\n- Fix another unsafe property assignment in Polymer. ([commit](https://github.com/Polymer/polymer/commit/3ee4eb96))\n\n- Add explicit null template for array-selector ([commit](https://github.com/Polymer/polymer/commit/d2d49dd9))\n\n- remove cruft ([commit](https://github.com/Polymer/polymer/commit/079ac3bc))\n\n- Adds basic legacy support for ShadyDOM.unPatch (WIP) ([commit](https://github.com/Polymer/polymer/commit/e752636c))\n\n- [ci skip] update changelog ([commit](https://github.com/Polymer/polymer/commit/2db60f5b))\n\n- Adds setting to skip style incudes and url rewriting ([commit](https://github.com/Polymer/polymer/commit/4fcacaab))\n\n- restores functionality of Polymer.mixinBehaviors ([commit](https://github.com/Polymer/polymer/commit/4af44c8d))\n\n- Avoids using mixins for behaviors. ([commit](https://github.com/Polymer/polymer/commit/624513f6))\n\n- Fix jsdoc comment ([commit](https://github.com/Polymer/polymer/commit/e69c8b3c))\n\n- Upstream warning text. ([commit](https://github.com/Polymer/polymer/commit/b4d6e70a))\n\n- Upstream changes to externs ([commit](https://github.com/Polymer/polymer/commit/83834aff))\n\n## [v3.1.0](https://github.com/Polymer/polymer/tree/v3.1.0) (2018-10-26)\n- update dependencies ([commit](https://github.com/Polymer/polymer/commit/99e39706))\n\n- Add beforeRegister callback to externs ([commit](https://github.com/Polymer/polymer/commit/0492390b))\n\n- Make toggleAttribute match with native signature (#5372) ([commit](https://github.com/Polymer/polymer/commit/693f9e4e))\n\n- Fixed typos on lines 133 and 157 (#5409) ([commit](https://github.com/Polymer/polymer/commit/750e7e1a))\n\n- Fix signature of toggleAttribute to match native version (#5370) ([commit](https://github.com/Polymer/polymer/commit/ce85eb99))\n\n- Update jsdoc for PropertyEffects.splice (#5367) ([commit](https://github.com/Polymer/polymer/commit/96557f78))\n\n- Expand type of LegacyElementMixin#listen and unlisten to accept EventTargets. ([commit](https://github.com/Polymer/polymer/commit/b55c56f7))\n\n- Update gen-closure-declarations to 0.5.0 (#5360) ([commit](https://github.com/Polymer/polymer/commit/9dbc8728))\n\n- Add TypeScript types for observer parameters. (#5359) ([commit](https://github.com/Polymer/polymer/commit/912c19cc))\n\n- Add missing return type to attributeChanged ([commit](https://github.com/Polymer/polymer/commit/239e99a5))\n\n- Add specific type for behaviors ([commit](https://github.com/Polymer/polymer/commit/bf02bd32))\n\n- Improve typings for legacy elements ([commit](https://github.com/Polymer/polymer/commit/d6d3c822))\n\n- Add @export ([commit](https://github.com/Polymer/polymer/commit/84b69918))\n\n- Improve types of flattened-nodes-observer further. ([commit](https://github.com/Polymer/polymer/commit/29428a82))\n\n- Add cast for compilation ([commit](https://github.com/Polymer/polymer/commit/b0aa913d))\n\n- Only generate types once on Travis ([commit](https://github.com/Polymer/polymer/commit/2a497433))\n\n- Move type generation from prepack to prepare ([commit](https://github.com/Polymer/polymer/commit/104e3e56))\n\n- Collapse imports for file into one statement ([commit](https://github.com/Polymer/polymer/commit/82e705f7))\n\n- Cleanup modulizer conversion leftovers (#5347) ([commit](https://github.com/Polymer/polymer/commit/448093b6))\n\n- Add comments re: need for mixing in before metaprogramming ([commit](https://github.com/Polymer/polymer/commit/d93cbfa5))\n\n- regen-package-lock ([commit](https://github.com/Polymer/polymer/commit/2d06ff59))\n\n- Don't run Firefox in headless mode. ([commit](https://github.com/Polymer/polymer/commit/44fcb9db))\n\n- Fix jsdoc syntax. ([commit](https://github.com/Polymer/polymer/commit/8d4e04bc))\n\n- Updates based on code review. Add computed tests. ([commit](https://github.com/Polymer/polymer/commit/ae1b4173))\n\n- Use type generator binary instead of gulp script. ([commit](https://github.com/Polymer/polymer/commit/a5afc8f1))\n\n- Remove unnecessary @const. ([commit](https://github.com/Polymer/polymer/commit/89cc5c62))\n\n- Add return description. ([commit](https://github.com/Polymer/polymer/commit/7901dc9d))\n\n- Grandfather defaulting sanitizeDOMValue from legacy Polymer object. ([commit](https://github.com/Polymer/polymer/commit/d5672dcf))\n\n- Minor changes to formatting and jsdoc ([commit](https://github.com/Polymer/polymer/commit/d5935a9c))\n\n- Update paths in gulpfile ([commit](https://github.com/Polymer/polymer/commit/f845842f))\n\n- Fix mixin jsdoc. ([commit](https://github.com/Polymer/polymer/commit/2d2320e5))\n\n- Add legacy-data-mixin as 1.x->2.x/3.x migration aide. Fixes #5262. ([commit](https://github.com/Polymer/polymer/commit/e385e49b))\n\n- Fix jsdoc to pass lint ([commit](https://github.com/Polymer/polymer/commit/33828f38))\n\n- Add documentation to boot.js ([commit](https://github.com/Polymer/polymer/commit/27036ea6))\n\n- The return type of mixinBehaviors is unknown ([commit](https://github.com/Polymer/polymer/commit/6cf5f9d0))\n\n- Export EventApi, same as DomApi ([commit](https://github.com/Polymer/polymer/commit/b71f9f4e))\n\n- Remove undocumented logging feature (#5331) ([commit](https://github.com/Polymer/polymer/commit/33ab3ae6))\n\n- Cleanup element-mixin leftovers from modulizer ([commit](https://github.com/Polymer/polymer/commit/dae63e3d))\n\n- Use case-map lib in a saner way. ([commit](https://github.com/Polymer/polymer/commit/7241ec58))\n\n- Fix a grab bag of closure compiler warnings. ([commit](https://github.com/Polymer/polymer/commit/658d1cf7))\n\n- Protect DomModule.import against renaming ([commit](https://github.com/Polymer/polymer/commit/aaf2cca0))\n\n- Add @nocollapse for jscompiler ([commit](https://github.com/Polymer/polymer/commit/4e4db700))\n\n- Ensure boot.js can only be parsed as a module ([commit](https://github.com/Polymer/polymer/commit/a64dfb08))\n\n- Use simpler class declaration and export form (#5325) ([commit](https://github.com/Polymer/polymer/commit/6dc01841))\n\n- Ensure unresolved.js is an es module (#5324) ([commit](https://github.com/Polymer/polymer/commit/20d4e35c))\n\n- Move version to ElementMixin prototype ([commit](https://github.com/Polymer/polymer/commit/2957e9d4))\n\n- Use relative path module specifier in gen-tsd autoImport setting. ([commit](https://github.com/Polymer/polymer/commit/76cf2af1))\n\n- Update TemplateStamp event listen param types from Node to EventTarget. (#5320) ([commit](https://github.com/Polymer/polymer/commit/e8167f7f))\n\n- Add test for direct assignment to template. ([commit](https://github.com/Polymer/polymer/commit/7644464c))\n\n- Add a template setter to ElementMixin. ([commit](https://github.com/Polymer/polymer/commit/d27b4a12))\n\n- Export the current Polymer version in polymer-element.js ([commit](https://github.com/Polymer/polymer/commit/05c62f44))\n\n- Make Polymer gestures library safe for Closure property renaming (take 2). (#5314) ([commit](https://github.com/Polymer/polymer/commit/6847cf47))\n\n- Make event notification handler read the value from currentTarget, (#5313) ([commit](https://github.com/Polymer/polymer/commit/db2f3cc7))\n\n- [ci skip] update changelog ([commit](https://github.com/Polymer/polymer/commit/0bf1e60c))\n\n- Upstream externs changes for DomRepeatEvent ([commit](https://github.com/Polymer/polymer/commit/e3b9d4e6))\n\n- Back to single template getter. Add more comments. ([commit](https://github.com/Polymer/polymer/commit/10d657b3))\n\n- Revert to legacy template getter, update tests. ([commit](https://github.com/Polymer/polymer/commit/c4b94a02))\n\n- More updates based on code review. ([commit](https://github.com/Polymer/polymer/commit/376f44c4))\n\n- Fix allowTemplateFromDomModule opt-in ([commit](https://github.com/Polymer/polymer/commit/36727379))\n\n- Fix lint warnings. ([commit](https://github.com/Polymer/polymer/commit/a199aa91))\n\n- Updates based on code review. ([commit](https://github.com/Polymer/polymer/commit/36c4dfa9))\n\n- npm upgrade dependencies ([commit](https://github.com/Polymer/polymer/commit/a515c992))\n\n- Fix lint warnings. ([commit](https://github.com/Polymer/polymer/commit/a0c5268c))\n\n- Catch errors on top window using uncaughtErrorFilter Works around safari quirk when running in iframe ([commit](https://github.com/Polymer/polymer/commit/47ade191))\n\n- Fix latent (benign) error thrown when removing dom-if via innerHTML. ([commit](https://github.com/Polymer/polymer/commit/e3066924))\n\n- Use setting via setStrictTemplatePolicy export. ([commit](https://github.com/Polymer/polymer/commit/8667b895))\n\n- Add tests. ([commit](https://github.com/Polymer/polymer/commit/625372ea))\n\n- Implement opt-in `strictTemplatePolicy` (flag TBD) - disable dom-bind - disable dom-module template lookup - disable templatizer of templates not stamped in trusted polymer template ([commit](https://github.com/Polymer/polymer/commit/2e6df0ee))\n\n- Ensure properties is only called once ([commit](https://github.com/Polymer/polymer/commit/63c7fc00))\n\n- Remove dom-module in test ([commit](https://github.com/Polymer/polymer/commit/617cb4c9))\n\n## [v3.0.5](https://github.com/Polymer/polymer/tree/v3.0.5) (2018-07-30)\n- Add more missing .d.ts files from being npm published. ([commit](https://github.com/Polymer/polymer/commit/f372ea89))\n\n- [ci skip] update changelog ([commit](https://github.com/Polymer/polymer/commit/1a9e81c2))\n\n## [v3.0.4](https://github.com/Polymer/polymer/tree/v3.0.4) (2018-07-30)\n- Ensure generated interfaces.d.ts is included in npm package ([commit](https://github.com/Polymer/polymer/commit/003b0518))\n\n- [ci skip] update changelog ([commit](https://github.com/Polymer/polymer/commit/028a718c))\n\n## [v3.0.3](https://github.com/Polymer/polymer/tree/v3.0.3) (2018-07-30)\n- rebuild package-lock ([commit](https://github.com/Polymer/polymer/commit/95bbefd0))\n\n- Generate typings for Polymer 3. ([commit](https://github.com/Polymer/polymer/commit/536030ac))\n\n- Revert Promise<void> changes. ([commit](https://github.com/Polymer/polymer/commit/ac6011e0))\n\n- Lint fixes. ([commit](https://github.com/Polymer/polymer/commit/73ae8b4d))\n\n- Restore some externs. ([commit](https://github.com/Polymer/polymer/commit/8b1e7934))\n\n- Upstream a bunch of g3 changes. ([commit](https://github.com/Polymer/polymer/commit/3b817192))\n\n- Add no-unused-vars eslint suppressions. ([commit](https://github.com/Polymer/polymer/commit/745883ea))\n\n- Annotate another two ephemeral classes. ([commit](https://github.com/Polymer/polymer/commit/c96b4502))\n\n- Mark some ephemeral super classes as private. ([commit](https://github.com/Polymer/polymer/commit/8728287f))\n\n- Annotate Node parameter as not null. ([commit](https://github.com/Polymer/polymer/commit/642f94f8))\n\n- Annotate some internal classes as private. ([commit](https://github.com/Polymer/polymer/commit/fa58519c))\n\n- Fix some appliesMixin annotations still with Polymer namespace. ([commit](https://github.com/Polymer/polymer/commit/a0a6c6b9))\n\n- TypeScript generator config and extra interfaces for Polymer 3. ([commit](https://github.com/Polymer/polymer/commit/3ac7eed2))\n\n- Tweaks to make Polymer 3 more amenable to typings generation. ([commit](https://github.com/Polymer/polymer/commit/605c8912))\n\n- Fix gulp 4 issues ([commit](https://github.com/Polymer/polymer/commit/4f0337a5))\n\n- Extend Safari exceptions beyond 10.1 ([commit](https://github.com/Polymer/polymer/commit/a78732ff))\n\n- Ignore shady CSS scoping in getComposedHTML ([commit](https://github.com/Polymer/polymer/commit/b1aa3058))\n\n- Fix method to force CE polyfill on in 3.x ([commit](https://github.com/Polymer/polymer/commit/84455c9c))\n\n- Convert object to class for better compilation ([commit](https://github.com/Polymer/polymer/commit/b2681170))\n\n- Fix Typo in Readme (#5260) ([commit](https://github.com/Polymer/polymer/commit/665901ab))\n\n- regen package-lock.json ([commit](https://github.com/Polymer/polymer/commit/a7152dd5))\n\n- Update supported browsers in issue template ([commit](https://github.com/Polymer/polymer/commit/1bd28098))\n\n- Remove modulized comment ([commit](https://github.com/Polymer/polymer/commit/07f26b26))\n\n- Update package.lock ([commit](https://github.com/Polymer/polymer/commit/1e1709cc))\n\n- Fix typo in jsdoc (#5248) ([commit](https://github.com/Polymer/polymer/commit/218189e2))\n\n- Replace .npmignore with package.json \"files\" option. (#5245) ([commit](https://github.com/Polymer/polymer/commit/eb84ea04))\n\n- Spelling ([commit](https://github.com/Polymer/polymer/commit/2eade585))\n\n- Update template docs (#5233) ([commit](https://github.com/Polymer/polymer/commit/31e5d058))\n\n- fix lint ([commit](https://github.com/Polymer/polymer/commit/44e725b8))\n\n- Port disabled fixes from 2.x ([commit](https://github.com/Polymer/polymer/commit/358a1c67))\n\n- Update repo URL ([commit](https://github.com/Polymer/polymer/commit/cdb34fc8))\n\n- Add badges ([commit](https://github.com/Polymer/polymer/commit/41d69801))\n\n- Update development instructions for 3.0 (#5226) ([commit](https://github.com/Polymer/polymer/commit/83ab5a14))\n\n- [ci skip] update changelog ([commit](https://github.com/Polymer/polymer/commit/e366b368))\n\n- Closure extern update ([commit](https://github.com/Polymer/polymer/commit/3c23d673))\n\n- Add user-importable files to `bower.json`'s `main` field for modulizer. ([commit](https://github.com/Polymer/polymer/commit/40e312f8))\n\n## [v3.0.2](https://github.com/Polymer/polymer/tree/v3.0.2) (2018-05-09)\n- Add back modulizer manifest ([commit](https://github.com/Polymer/polymer/commit/d32797e9))\n\n- [ci skip] update changelog ([commit](https://github.com/Polymer/polymer/commit/4794b323))\n\n## [v3.0.1](https://github.com/Polymer/polymer/tree/v3.0.1) (2018-05-09)\n- [ci skip] update changelog ([commit](https://github.com/Polymer/polymer/commit/3a4b8b89))\n\n- Remove importHref from 3.0 ([commit](https://github.com/Polymer/polymer/commit/fd416a21))\n\n## [v3.0.0](https://github.com/Polymer/polymer/tree/v3.0.0) (2018-05-08)\n- use released versions of shadycss and webcomponentsjs ([commit](https://github.com/Polymer/polymer/commit/8f79ec40))\n\n- Bump dependencies ([commit](https://github.com/Polymer/polymer/commit/8894e22b))\n\n- Run Chrome & FF serially to try and help flakiness ([commit](https://github.com/Polymer/polymer/commit/95740463))\n\n- Fix lint warning ([commit](https://github.com/Polymer/polymer/commit/ecf36f8a))\n\n- Bump to cli 1.7.0 ([commit](https://github.com/Polymer/polymer/commit/ccb29d27))\n\n- Removing support for returning strings from template getter. (Per previous documented deprecation: https://www.polymer-project.org/2.0/docs/devguide/dom-template#templateobject) ([commit](https://github.com/Polymer/polymer/commit/ba4491d5))\n\n- Fix typos and nits ([commit](https://github.com/Polymer/polymer/commit/c54ff70a))\n\n- Update to Gulp 4 ([commit](https://github.com/Polymer/polymer/commit/4e31768c))\n\n- Add serve command to package.json and update package-lock.json ([commit](https://github.com/Polymer/polymer/commit/eb72d5aa))\n\n- Fix for browsers that don't have input.labels. ([commit](https://github.com/Polymer/polymer/commit/036e4f66))\n\n- Tweak introductory note, fix webpack capitalization ([commit](https://github.com/Polymer/polymer/commit/b823620e))\n\n- gestures: Avoid spreading non-iterable in older browsers ([commit](https://github.com/Polymer/polymer/commit/2ce4f700))\n\n- wip ([commit](https://github.com/Polymer/polymer/commit/f4534c6a))\n\n- Readme: very small tweaks ([commit](https://github.com/Polymer/polymer/commit/d896cdd0))\n\n- Tweak wording. ([commit](https://github.com/Polymer/polymer/commit/fb7630c3))\n\n- Fix link ([commit](https://github.com/Polymer/polymer/commit/fc0ce189))\n\n- Re-order sections ([commit](https://github.com/Polymer/polymer/commit/ee6a67ee))\n\n- Fix LitElement typo ([commit](https://github.com/Polymer/polymer/commit/928c47fc))\n\n- Depend on polymer-cli rather than wct ([commit](https://github.com/Polymer/polymer/commit/503f5631))\n\n- Minor tweaks ([commit](https://github.com/Polymer/polymer/commit/e924ba86))\n\n- Update README for 3.x ([commit](https://github.com/Polymer/polymer/commit/956bba73))\n\n- Update Edge testing versions. ([commit](https://github.com/Polymer/polymer/commit/445c979b))\n\n- Exclude all Edge versions from keyframe/font tests. ([commit](https://github.com/Polymer/polymer/commit/85278860))\n\n- Update wcjs version. ([commit](https://github.com/Polymer/polymer/commit/4805e31f))\n\n- Add .npmignore file (#5215) ([commit](https://github.com/Polymer/polymer/commit/b3c36df7))\n\n- Use node 9 ([commit](https://github.com/Polymer/polymer/commit/0bb5d7c5))\n\n- Use module flags for wct ([commit](https://github.com/Polymer/polymer/commit/8abf2ec9))\n\n- Use babel parser for aslant for dynamic import. ([commit](https://github.com/Polymer/polymer/commit/bddeff4a))\n\n- Fix lint errors. ([commit](https://github.com/Polymer/polymer/commit/dea23515))\n\n- 3.0.0-pre.13 ([commit](https://github.com/Polymer/polymer/commit/da2d66dc))\n\n- [package.json] Remove version script ([commit](https://github.com/Polymer/polymer/commit/e88c1eef))\n\n- Update dependencies ([commit](https://github.com/Polymer/polymer/commit/1ed2b310))\n\n- Fix test typo on Chrome ([commit](https://github.com/Polymer/polymer/commit/a11febe7))\n\n- Fixes IE11 test issues ([commit](https://github.com/Polymer/polymer/commit/8b5803c2))\n\n- Fixes styling tests related to using HTML Imports ([commit](https://github.com/Polymer/polymer/commit/26747422))\n\n- Remove crufty global (fixes globals.html test) ([commit](https://github.com/Polymer/polymer/commit/676f5f3d))\n\n- Update to webcomponents 2.0.0 and webcomponents-bundle.js ([commit](https://github.com/Polymer/polymer/commit/a4d80d09))\n\n- Fix meaningful whitespace in test assertion ([commit](https://github.com/Polymer/polymer/commit/bff03b2d))\n\n- Fix latent mistake using old SD API ([commit](https://github.com/Polymer/polymer/commit/3f24f71d))\n\n- Add global for wct callback when amd compiling ([commit](https://github.com/Polymer/polymer/commit/7f9de46c))\n\n- Eliminate pre-module code from resolveUrl tests ([commit](https://github.com/Polymer/polymer/commit/a93f81f1))\n\n- Improve documentation and legibility. ([commit](https://github.com/Polymer/polymer/commit/ab103dc1))\n\n- Add some global whitelists ([commit](https://github.com/Polymer/polymer/commit/d6821e45))\n\n- Fix references to js files instead of html files ([commit](https://github.com/Polymer/polymer/commit/dfcaadb2))\n\n- Fix glob patterns for eslint ([commit](https://github.com/Polymer/polymer/commit/206cf724))\n\n- Fix ESLint warnings ([commit](https://github.com/Polymer/polymer/commit/6d240138))\n\n- Eliminate more canonical path usage ([commit](https://github.com/Polymer/polymer/commit/1761c79b))\n\n- Eliminate canonical path to wcjs ([commit](https://github.com/Polymer/polymer/commit/4b7cd869))\n\n- Remove extra polymer-legacy.js imports ([commit](https://github.com/Polymer/polymer/commit/f39aaa8c))\n\n- Clean up Polymer fn import ([commit](https://github.com/Polymer/polymer/commit/8069dff4))\n\n- Add WCT config used by all tests ([commit](https://github.com/Polymer/polymer/commit/f1266845))\n\n- Clean up exports ([commit](https://github.com/Polymer/polymer/commit/0b75920f))\n\n- Allow Polymer fn's call to Class to be overridden. ([commit](https://github.com/Polymer/polymer/commit/65d73f17))\n\n- add sill-relevant, deleted tests back in ([commit](https://github.com/Polymer/polymer/commit/180a92ff))\n\n- manually change inter-package dep imports from paths to names ([commit](https://github.com/Polymer/polymer/commit/d913614d))\n\n- manually add assetpath (import.meta.url) for tests that require it ([commit](https://github.com/Polymer/polymer/commit/0c850659))\n\n- move behavior definition to before usage ([commit](https://github.com/Polymer/polymer/commit/09b11fa4))\n\n- define omitted class declaration ([commit](https://github.com/Polymer/polymer/commit/ec36165e))\n\n- remove &lt; and replace with < for innerHTML ([commit](https://github.com/Polymer/polymer/commit/5ce0d24d))\n\n- fixed typo causing test to fail ([commit](https://github.com/Polymer/polymer/commit/0caa7dab))\n\n- fix missing dom-module in modulization ([commit](https://github.com/Polymer/polymer/commit/6c7c770c))\n\n- revert module wait ([commit](https://github.com/Polymer/polymer/commit/12a650b1))\n\n- wait for elements in other modules to be defined ([commit](https://github.com/Polymer/polymer/commit/f0376406))\n\n- no more undefined.hasShadow ([commit](https://github.com/Polymer/polymer/commit/0985652e))\n\n- removed link rel import type css tests ([commit](https://github.com/Polymer/polymer/commit/57d4190c))\n\n- delete debugger ([commit](https://github.com/Polymer/polymer/commit/6905dd10))\n\n- skip link rel import type css tests on native imports ([commit](https://github.com/Polymer/polymer/commit/811ee301))\n\n- add missing css html import ([commit](https://github.com/Polymer/polymer/commit/a52148a3))\n\n- remove importHref tests ([commit](https://github.com/Polymer/polymer/commit/a84ad782))\n\n- Import Polymer function in tests from legacy/polymer-fn.js ([commit](https://github.com/Polymer/polymer/commit/232b0042))\n\n- Export Polymer function from polymer-legacy.js ([commit](https://github.com/Polymer/polymer/commit/69f488b2))\n\n- Add new wct deps. ([commit](https://github.com/Polymer/polymer/commit/a4bedbfd))\n\n- Fixup a few places where comments were misplaced. ([commit](https://github.com/Polymer/polymer/commit/ac2fa81f))\n\n- Fixup license comments. ([commit](https://github.com/Polymer/polymer/commit/f664f251))\n\n- Update package.json from modulizer's output, set polymer-element.js as main. ([commit](https://github.com/Polymer/polymer/commit/5abf4728))\n\n- Replace sources with modulizer output. ([commit](https://github.com/Polymer/polymer/commit/cf3b7215))\n\n- Rename HTML files to .js files to trick git's rename detection. ([commit](https://github.com/Polymer/polymer/commit/527d2cdd))\n\n- Delete typings for now. ([commit](https://github.com/Polymer/polymer/commit/03d85982))\n\n- Add reasoning for suppress missingProperties ([commit](https://github.com/Polymer/polymer/commit/61ca60e4))\n\n- Don't rely on dom-module synchronously until WCR. ([commit](https://github.com/Polymer/polymer/commit/e64bd0ba))\n\n- Avoid closure warnings. ([commit](https://github.com/Polymer/polymer/commit/412bb1e0))\n\n- Add ability to define importMeta on legacy elements. Fixes #5163 ([commit](https://github.com/Polymer/polymer/commit/616f6662))\n\n- Allow legacy element property definitions with only a type. Fixes #5173 ([commit](https://github.com/Polymer/polymer/commit/d321c6c9))\n\n- Update docs. ([commit](https://github.com/Polymer/polymer/commit/c8c9e24d))\n\n- Use Polymer.ResolveUrl.pathFromUrl ([commit](https://github.com/Polymer/polymer/commit/d9d3e439))\n\n- Fix test under shadydom. Slight logic refactor. ([commit](https://github.com/Polymer/polymer/commit/2128ebe2))\n\n- Fix lint warning ([commit](https://github.com/Polymer/polymer/commit/fb741ee3))\n\n- Add importMeta getter to derive importPath from modules. Fixes #5163 ([commit](https://github.com/Polymer/polymer/commit/f7672da9))\n\n- Reference dependencies as siblings in tests. ([commit](https://github.com/Polymer/polymer/commit/2561d868))\n\n- Update types ([commit](https://github.com/Polymer/polymer/commit/23ba7dee))\n\n- Add note about performance vs correctness ([commit](https://github.com/Polymer/polymer/commit/89ab7385))\n\n- Update types. ([commit](https://github.com/Polymer/polymer/commit/5357d64a))\n\n- Lint clean. ([commit](https://github.com/Polymer/polymer/commit/f78b0518))\n\n- Pass through fourth namespace param on attributeChangedCallback. ([commit](https://github.com/Polymer/polymer/commit/91d4aeba))\n\n- Add a @const annotation to help the Closure Compiler understand that Polymer.Debouncer is the name of a type. ([commit](https://github.com/Polymer/polymer/commit/e5a5725d))\n\n- [ci skip] update changelog ([commit](https://github.com/Polymer/polymer/commit/92d282a9))\n\n- Update docs and types ([commit](https://github.com/Polymer/polymer/commit/211c223f))\n\n- Update perf test to use strict-binding-parser ([commit](https://github.com/Polymer/polymer/commit/f53e9e8a))\n\n- Correct import paths ([commit](https://github.com/Polymer/polymer/commit/ab93ab08))\n\n- Only store method once for dynamic functions ([commit](https://github.com/Polymer/polymer/commit/0f0ccdad))\n\n- Move strict-binding-parser to lib/mixins ([commit](https://github.com/Polymer/polymer/commit/a4d4eb9a))\n\n- Rename to StrictBindingParser ([commit](https://github.com/Polymer/polymer/commit/19d4b8cb))\n\n- Fix linter errors ([commit](https://github.com/Polymer/polymer/commit/d8cf449e))\n\n- Extract to a mixin ([commit](https://github.com/Polymer/polymer/commit/57a14236))\n\n- Add missing dependency to bower.json ([commit](https://github.com/Polymer/polymer/commit/333a4664))\n\n- Fix linter warning ([commit](https://github.com/Polymer/polymer/commit/14fac019))\n\n- Add documentation ([commit](https://github.com/Polymer/polymer/commit/df0ee354))\n\n- Add performance test for binding-expressions ([commit](https://github.com/Polymer/polymer/commit/42f7d785))\n\n- Rewrite parser to use switch-case instead of functions ([commit](https://github.com/Polymer/polymer/commit/423074d1))\n\n- Remove escaping from bindings ([commit](https://github.com/Polymer/polymer/commit/8cd49479))\n\n- Fix linter warning ([commit](https://github.com/Polymer/polymer/commit/8a5525b0))\n\n- Refactor to be functional and add more tests ([commit](https://github.com/Polymer/polymer/commit/7eb1a627))\n\n- Fix linter warnings ([commit](https://github.com/Polymer/polymer/commit/79d05b8a))\n\n- Rewrite expression parser to state machine ([commit](https://github.com/Polymer/polymer/commit/13b834df))\n\n## [v2.6.0](https://github.com/Polymer/polymer/tree/v2.6.0) (2018-03-22)\n- Use function instead of Set ([commit](https://github.com/Polymer/polymer/commit/33d2e1a8))\n\n- [ci skip] Fix typo ([commit](https://github.com/Polymer/polymer/commit/0d1b1c2e))\n\n- Fix test in shady DOM ([commit](https://github.com/Polymer/polymer/commit/a586b72c))\n\n- Deduplicate style includes ([commit](https://github.com/Polymer/polymer/commit/acfef71d))\n\n- use a clearer test for shadowRoot ([commit](https://github.com/Polymer/polymer/commit/b2fb1cfd))\n\n- Returning null in template should nullify parent template ([commit](https://github.com/Polymer/polymer/commit/2a6c0a2a))\n\n- [ci skip] Add clarifying comment ([commit](https://github.com/Polymer/polymer/commit/0573d483))\n\n- Correct the JSBin version ([commit](https://github.com/Polymer/polymer/commit/cb1ae7d3))\n\n- Put attribute capitalization fix in property-effects ([commit](https://github.com/Polymer/polymer/commit/d45dd575))\n\n- Add note about pre v3 releases ([commit](https://github.com/Polymer/polymer/commit/f9391618))\n\n- Add note for npm package ([commit](https://github.com/Polymer/polymer/commit/8f2cc0d5))\n\n- Add iron-component-page dev-dependency ([commit](https://github.com/Polymer/polymer/commit/d93dd1ce))\n\n- Update several gulp dependencies ([commit](https://github.com/Polymer/polymer/commit/ca57a1f3))\n\n- Update dom5 to 3.0.0 ([commit](https://github.com/Polymer/polymer/commit/d4a0914e))\n\n- Update Google Closure Compiler version and fix cast ([commit](https://github.com/Polymer/polymer/commit/4004c9c4))\n\n- Update types ([commit](https://github.com/Polymer/polymer/commit/bb61a20d))\n\n- Fix several issues in the documentation of dom-* elements ([commit](https://github.com/Polymer/polymer/commit/8e1b3f45))\n\n- Handle `disabled` attribute correctly for tap gesture ([commit](https://github.com/Polymer/polymer/commit/5c0f3e6a))\n\n- add test case for nested label ([commit](https://github.com/Polymer/polymer/commit/c11c99b2))\n\n- Add docs and cleanup matchingLabels ([commit](https://github.com/Polymer/polymer/commit/e1df1662))\n\n- Add tests ([commit](https://github.com/Polymer/polymer/commit/70edf1f8))\n\n- update types ([commit](https://github.com/Polymer/polymer/commit/2d674e75))\n\n- fix tests and add dependency import ([commit](https://github.com/Polymer/polymer/commit/a37ba7e2))\n\n- fix typings ([commit](https://github.com/Polymer/polymer/commit/8f8135b2))\n\n- Ensure DisableUpgradeMixin extends PropertiesMixin ([commit](https://github.com/Polymer/polymer/commit/7e74e363))\n\n- Format comment and remove deduping mixin ([commit](https://github.com/Polymer/polymer/commit/b8c66ded))\n\n- update types ([commit](https://github.com/Polymer/polymer/commit/1fd5f9cf))\n\n- update types ([commit](https://github.com/Polymer/polymer/commit/5bc45ce3))\n\n- Add mixin to automatically detect capitalized HTML attributes ([commit](https://github.com/Polymer/polymer/commit/37fd5ffe))\n\n- Add instructions for locally viewing the source documentation ([commit](https://github.com/Polymer/polymer/commit/206d3610))\n\n- Simplify condition checking in stylesFromModule function ([commit](https://github.com/Polymer/polymer/commit/e6903821))\n\n- Bump type generator and generate new typings. (#5119) ([commit](https://github.com/Polymer/polymer/commit/5c027309))\n\n- dispatchEvent returns boolean (#5117) ([commit](https://github.com/Polymer/polymer/commit/9d86135c))\n\n- Update types ([commit](https://github.com/Polymer/polymer/commit/63e7bbc7))\n\n- Fix license links ([commit](https://github.com/Polymer/polymer/commit/f3939875))\n\n- Fix issue with not genering the Templatizer docs ([commit](https://github.com/Polymer/polymer/commit/55708acf))\n\n- Bump TS type generator to pick up transitive mixin handling. ([commit](https://github.com/Polymer/polymer/commit/c3dad540))\n\n- Remove unnecessary mutableData property from MutableData mixin ([commit](https://github.com/Polymer/polymer/commit/92b83249))\n\n- Update types ([commit](https://github.com/Polymer/polymer/commit/868fba7c))\n\n- Add note to updateStyles regarding updates to CSS mixins ([commit](https://github.com/Polymer/polymer/commit/d458bab3))\n\n- Avoid timing issues with polyfilled Promise ([commit](https://github.com/Polymer/polymer/commit/6b3e007e))\n\n- Revert use of async/await due to lack of build/serve support. ([commit](https://github.com/Polymer/polymer/commit/d4a7a45b))\n\n- Revert types. ([commit](https://github.com/Polymer/polymer/commit/dea90802))\n\n- Update eslint parserOptions to es2017 for async/await support. ([commit](https://github.com/Polymer/polymer/commit/ef579e29))\n\n- Use stronger check for PropertyEffects clients. Fixes #5017 ([commit](https://github.com/Polymer/polymer/commit/e6d558ec))\n\n- Remove unneeded file ([commit](https://github.com/Polymer/polymer/commit/a5393b6d))\n\n- [PropertiesChanged]: allow old data to be gc'd after `_propertiesChanged` ([commit](https://github.com/Polymer/polymer/commit/74907b9a))\n\n- Update package-lock.json ([commit](https://github.com/Polymer/polymer/commit/c58f3e0d))\n\n- Make Travis update-types failure style the same as the elements. ([commit](https://github.com/Polymer/polymer/commit/8189382d))\n\n- Bump TypeScript generator version. ([commit](https://github.com/Polymer/polymer/commit/3e432190))\n\n- Make EventApi.path EventTarget type non-nullable. ([commit](https://github.com/Polymer/polymer/commit/3ede9b51))\n\n- Lint and type fixes ([commit](https://github.com/Polymer/polymer/commit/5607a2d8))\n\n- [PropertiesChanged]: adds _shouldPropertiesChange ([commit](https://github.com/Polymer/polymer/commit/c1885a6a))\n\n- Update docs: templatize() cannot be called multiple times ([commit](https://github.com/Polymer/polymer/commit/27fc21c5))\n\n- [ci skip] update changelog ([commit](https://github.com/Polymer/polymer/commit/65b4df86))\n\n- Update types. ([commit](https://github.com/Polymer/polymer/commit/c3b6236a))\n\n- Fix JSDoc example formatting ([commit](https://github.com/Polymer/polymer/commit/699cd87f))\n\n- Use latest webcomponents polyfill bundle ([commit](https://github.com/Polymer/polymer/commit/8fef6776))\n\n- Fix label tap by checking matched label pairs ([commit](https://github.com/Polymer/polymer/commit/a77d64e5))\n\n- Defer creation related work via `disable-upgrade` ([commit](https://github.com/Polymer/polymer/commit/a7eb9754))\n\n- lint fixes ([commit](https://github.com/Polymer/polymer/commit/de0ac5a2))\n\n- Adds `Polymer.DisableUpgradeMixin` ([commit](https://github.com/Polymer/polymer/commit/62ce3148))\n\n## [v2.5.0](https://github.com/Polymer/polymer/tree/v2.5.0) (2018-02-02)\n- Update types ([commit](https://github.com/Polymer/polymer/commit/5fa059fa))\n\n- Update JSDocs to use <dom-repeat> tags ([commit](https://github.com/Polymer/polymer/commit/636abae0))\n\n- Fix type declarations inadvertedtly referencing Polymer.Element. (#5084) ([commit](https://github.com/Polymer/polymer/commit/82cd3dad))\n\n- Use class syntax in <dom-repeat> documentation (#5077) ([commit](https://github.com/Polymer/polymer/commit/97837c7c))\n\n- Add hash/abs URL resolution tests. ([commit](https://github.com/Polymer/polymer/commit/d97373dd))\n\n- Update types. ([commit](https://github.com/Polymer/polymer/commit/892df3f3))\n\n- Add comments about resolveUrl idiosyncrasies. ([commit](https://github.com/Polymer/polymer/commit/a829cbce))\n\n- Revert \"Move absolute url logic to element-mixin\" ([commit](https://github.com/Polymer/polymer/commit/127bc866))\n\n- Added Polymer.version to polymer-externs (#5079) ([commit](https://github.com/Polymer/polymer/commit/b52ab81d))\n\n- Avoid tracking parentNode since it's unncessary ([commit](https://github.com/Polymer/polymer/commit/1463e3b2))\n\n- Update types. ([commit](https://github.com/Polymer/polymer/commit/2253e0db))\n\n- Fix nit. ([commit](https://github.com/Polymer/polymer/commit/c9208fd6))\n\n- Avoid comment constructor for IE support. ([commit](https://github.com/Polymer/polymer/commit/a39cfd11))\n\n- Disallow non-templates as interpolations in Polymer.html (#5023) ([commit](https://github.com/Polymer/polymer/commit/eeb71600))\n\n- Exclude index.html from type generation. (#5076) ([commit](https://github.com/Polymer/polymer/commit/6fc285c4))\n\n- update types ([commit](https://github.com/Polymer/polymer/commit/5521e43e))\n\n- [element-mixin] Do not create property accessors unless a property effect exists ([commit](https://github.com/Polymer/polymer/commit/4177d9ce))\n\n- Use containers for testing again (#5070) ([commit](https://github.com/Polymer/polymer/commit/5e2990e3))\n\n- Invoke JS compiler rename for properties ([commit](https://github.com/Polymer/polymer/commit/74a4626a))\n\n- Add package-lock.json back ([commit](https://github.com/Polymer/polymer/commit/c90eeb67))\n\n- fix test. ([commit](https://github.com/Polymer/polymer/commit/1c74ecde))\n\n- Enhance robustness by replacing slot with a comment ([commit](https://github.com/Polymer/polymer/commit/b76d81ee))\n\n- Avoid use of element accessors on doc frag to fix IE/Edge. ([commit](https://github.com/Polymer/polymer/commit/ecb1005e))\n\n- Fix linter errors ([commit](https://github.com/Polymer/polymer/commit/5e0bee77))\n\n- Fix issue with observers being called twice ([commit](https://github.com/Polymer/polymer/commit/291e4f56))\n\n- Revert package-lock change ([commit](https://github.com/Polymer/polymer/commit/86ecd982))\n\n- [ci-skip] Update changelog (2.4.0) ([commit](https://github.com/Polymer/polymer/commit/cb88252d))\n\n- Add package-lock.json to .gitignore ([commit](https://github.com/Polymer/polymer/commit/e53db30f))\n\n- Update types ([commit](https://github.com/Polymer/polymer/commit/7a52cda2))\n\n- Add comments re: instanceProps ([commit](https://github.com/Polymer/polymer/commit/cf5f818e))\n\n- Change if-condition to check for arguments.length ([commit](https://github.com/Polymer/polymer/commit/27750109))\n\n- Delete package-lock.json ([commit](https://github.com/Polymer/polymer/commit/e77149e2))\n\n- [ci skip] Fix test case name ([commit](https://github.com/Polymer/polymer/commit/eee609d4))\n\n- Fix issue where el.splice could not clear full array ([commit](https://github.com/Polymer/polymer/commit/a51de9e3))\n\n- Make owner optional as well. ([commit](https://github.com/Polymer/polymer/commit/b52c315e))\n\n- Update package-lock.json ([commit](https://github.com/Polymer/polymer/commit/38c0e443))\n\n- Update typescript types again, after fixing jsdoc. ([commit](https://github.com/Polymer/polymer/commit/3045e4b7))\n\n- Fix lint warnings. ([commit](https://github.com/Polymer/polymer/commit/715cde47))\n\n- Update typescript types. ([commit](https://github.com/Polymer/polymer/commit/c218ae62))\n\n- Ensure path notifications from templatized instances don't throw. Fixes #3422 ([commit](https://github.com/Polymer/polymer/commit/a9f71bd1))\n\n- Allow templatizer to be used without owner or host prop forwarding. Fixes #4458 ([commit](https://github.com/Polymer/polymer/commit/bde5898e))\n\n- Templatize: remove slots when hiding children ([commit](https://github.com/Polymer/polymer/commit/ea0abb95))\n\n- Clarify API docs for PropertyAccessors mixin ([commit](https://github.com/Polymer/polymer/commit/ae58e88b))\n\n## [v2.4.0](https://github.com/Polymer/polymer/tree/v2.4.0) (2018-01-26)\n- Simplify code for <dom-repeat>'s `sort` and `filter` properties ([commit](https://github.com/Polymer/polymer/commit/88cca860))\n\n- fix test for normal escaping ([commit](https://github.com/Polymer/polymer/commit/5fa02aa2))\n\n- Use javascript string escaping in Polymer.html ([commit](https://github.com/Polymer/polymer/commit/4c662141))\n\n- [ci skip] Add CODEOWNERS file (#5061) ([commit](https://github.com/Polymer/polymer/commit/90199f3b))\n\n- Fix incorrect path modification in dom-repeat __handleObservedPaths() (#4983) (#5048) ([commit](https://github.com/Polymer/polymer/commit/4b58f54b))\n\n- Skip certain tests in Edge 16 ([commit](https://github.com/Polymer/polymer/commit/09897d18))\n\n- add Edge 16 testing ([commit](https://github.com/Polymer/polymer/commit/36fa08ae))\n\n- Fix tests (#5050) ([commit](https://github.com/Polymer/polymer/commit/ecd1ba3a))\n\n- Update to latest wct. ([commit](https://github.com/Polymer/polymer/commit/a85ff3fc))\n\n- HTTPS, please ([commit](https://github.com/Polymer/polymer/commit/c868575c))\n\n- Remove unnecessary limit check ([commit](https://github.com/Polymer/polymer/commit/5fb9c559))\n\n- Fix documentation in typescript ([commit](https://github.com/Polymer/polymer/commit/bc95c5ad))\n\n- test(logging): improve _log with single parameter with sinon.spy ([commit](https://github.com/Polymer/polymer/commit/9891f31a))\n\n- Add article \"a\" ([commit](https://github.com/Polymer/polymer/commit/cefdaa93))\n\n- Update mixinBehaviors annotation. Behaviors don't satisfy PolymerInit. (#5036) ([commit](https://github.com/Polymer/polymer/commit/d7ea2464))\n\n- add correct return type for `querySelectorAll` (#5034) ([commit](https://github.com/Polymer/polymer/commit/6ab5c4a4))\n\n- Gestures: fall back to event.target when composedPath is empty. (#5029) ([commit](https://github.com/Polymer/polymer/commit/98b5aadc))\n\n- add void return type annotations (#5000) ([commit](https://github.com/Polymer/polymer/commit/589684a5))\n\n- Easy script to update closure and typescript typings (#5026) ([commit](https://github.com/Polymer/polymer/commit/60e7121d))\n\n- Prefer jsBin since glitch.me requires signin to not be gc'ed. ([commit](https://github.com/Polymer/polymer/commit/e7722243))\n\n- Note that glitch editing environment is not IE11 friendly. ([commit](https://github.com/Polymer/polymer/commit/06ca708b))\n\n- Add links to glitch.me template using polyserve. Fixes #5016 ([commit](https://github.com/Polymer/polymer/commit/9f2ec5f6))\n\n- Update .travis.yml ([commit](https://github.com/Polymer/polymer/commit/9715ab8f))\n\n- [ci skip] Add comment to aid archeology ([commit](https://github.com/Polymer/polymer/commit/e76a2b90))\n\n- Move absolute url logic to element-mixin ([commit](https://github.com/Polymer/polymer/commit/9c189ac9))\n\n- Use double tabs ([commit](https://github.com/Polymer/polymer/commit/6f7b8608))\n\n- indentation fix ([commit](https://github.com/Polymer/polymer/commit/5dca5cd0))\n\n- Remove trailing spaces and extra lines in CONTRIBUTING.md ([commit](https://github.com/Polymer/polymer/commit/8ed376e6))\n\n- test(logging.html): #5007 make sure _logger called one time ([commit](https://github.com/Polymer/polymer/commit/fe48dfa4))\n\n- _loggertest(logging.html): make seperate test suite for _logger ([commit](https://github.com/Polymer/polymer/commit/bd5821b6))\n\n- test(logging.html): missing semicolon ([commit](https://github.com/Polymer/polymer/commit/df3c3c02))\n\n- test(logging): _log with single parameter #5007 ([commit](https://github.com/Polymer/polymer/commit/818c537d))\n\n- fix(legacy-element-mixin): syntax error in _logger ([commit](https://github.com/Polymer/polymer/commit/e0affe3f))\n\n- fix(legacy-element-mixin): _log with single parameter #5006 ([commit](https://github.com/Polymer/polymer/commit/f4ecbae5))\n\n- Fix settings so that its properly picked up by both gen-ts and modulizer ([commit](https://github.com/Polymer/polymer/commit/0356b2df))\n\n- Unbreak the build by changing back the type ([commit](https://github.com/Polymer/polymer/commit/d5dc2a21))\n\n- Enable gulp generate-typescript on Travis ([commit](https://github.com/Polymer/polymer/commit/764146cd))\n\n- Make sure that Travis fails when there are non-updated generated files ([commit](https://github.com/Polymer/polymer/commit/b2cd4370))\n\n- run `gulp generate-typescript` ([commit](https://github.com/Polymer/polymer/commit/541d1f89))\n\n- fix ArraySplice types to more closely match code ([commit](https://github.com/Polymer/polymer/commit/f6182b34))\n\n- [ProperitesChanged] Fix deserialization (#4996) ([commit](https://github.com/Polymer/polymer/commit/2719a9d6))\n\n- fix(FlattenedNodesObserver): do not fail on node without children ([commit](https://github.com/Polymer/polymer/commit/09bb6cd8))\n\n- Address latest round of comments. ([commit](https://github.com/Polymer/polymer/commit/7b581de9))\n\n- Update PropertyEffects interface name in remap config. ([commit](https://github.com/Polymer/polymer/commit/0ebfc24d))\n\n- Tighten more types for TypeScript and Closure (#4998) ([commit](https://github.com/Polymer/polymer/commit/e8729822))\n\n- Add renameTypes config. ([commit](https://github.com/Polymer/polymer/commit/73666c39))\n\n- New typings. ([commit](https://github.com/Polymer/polymer/commit/a1f33174))\n\n- Bump gen-typescript version. ([commit](https://github.com/Polymer/polymer/commit/266d599a))\n\n- Tighten Closure type annotations. (#4997) ([commit](https://github.com/Polymer/polymer/commit/ee4445f8))\n\n- Mark some FlattenedNodesObserver things private. ([commit](https://github.com/Polymer/polymer/commit/5190a89c))\n\n- Add TypeScript equivalent to Closure ITemplateArray. ([commit](https://github.com/Polymer/polymer/commit/a77310af))\n\n- Fix compilation errors. ([commit](https://github.com/Polymer/polymer/commit/f0e31f2d))\n\n- Use glob patterns instead of RegExps to exclude files. ([commit](https://github.com/Polymer/polymer/commit/8f8e54ca))\n\n- Bump version of gen-typescript-declarations. ([commit](https://github.com/Polymer/polymer/commit/cf11a826))\n\n- Handle case where there are no elements in the template ([commit](https://github.com/Polymer/polymer/commit/2d6b4684))\n\n- Update various Polymer annotations to constrain generated types. ([commit](https://github.com/Polymer/polymer/commit/ffc35e48))\n\n- Fix typo in comment ([commit](https://github.com/Polymer/polymer/commit/ade5e796))\n\n- Fix regression with imported css ([commit](https://github.com/Polymer/polymer/commit/706e6021))\n\n- Bring in latest gen-typescript-declarations updates. ([commit](https://github.com/Polymer/polymer/commit/6a0d214d))\n\n- Apply `listeners` in constructor rather than `ready` ([commit](https://github.com/Polymer/polymer/commit/35e3c54b))\n\n- Replace `disconnectedCallback` stub since this change is breaking. ([commit](https://github.com/Polymer/polymer/commit/c8acc183))\n\n- Minor fixes ([commit](https://github.com/Polymer/polymer/commit/1b514b4f))\n\n- Fix html-tag import path. ([commit](https://github.com/Polymer/polymer/commit/c9be530d))\n\n- Update CHANGELOG. ([commit](https://github.com/Polymer/polymer/commit/3ffb895e))\n\n- Fix import path for html-tag. ([commit](https://github.com/Polymer/polymer/commit/eb309934))\n\n- Add generated TypeScript declarations. ([commit](https://github.com/Polymer/polymer/commit/60450bf4))\n\n- Add script to generate TypeScript declarations. ([commit](https://github.com/Polymer/polymer/commit/1f9be786))\n\n- Annotate klass class as @private. Annotate that dedupingMixin returns T. ([commit](https://github.com/Polymer/polymer/commit/b02c4583))\n\n- fix eslint error for unused var in _setPendingProperty ([commit](https://github.com/Polymer/polymer/commit/a89c9ba0))\n\n- fix closure typing with Polymer.html function ([commit](https://github.com/Polymer/polymer/commit/c519796f))\n\n- re-add AsyncInterface definition, fix comment ([commit](https://github.com/Polymer/polymer/commit/986fb3e9))\n\n- Avoid _setPendingProperty warning due to types not understanding deduping mixin. ([commit](https://github.com/Polymer/polymer/commit/40d47f24))\n\n- [ci skip] Update changelog ([commit](https://github.com/Polymer/polymer/commit/f6cc61bd))\n\n- add test for legacy Polymer({}) elements ([commit](https://github.com/Polymer/polymer/commit/8a1c76cd))\n\n- Rename html-fn to html-tag ([commit](https://github.com/Polymer/polymer/commit/02c06aa3))\n\n- Fix most closure warnings. ([commit](https://github.com/Polymer/polymer/commit/a12934c5))\n\n- Add back disconnectedCallback. ([commit](https://github.com/Polymer/polymer/commit/fa40f205))\n\n- Merge with master ([commit](https://github.com/Polymer/polymer/commit/b158e082))\n\n- Move function out of closure.  Add comments. ([commit](https://github.com/Polymer/polymer/commit/ad539fe7))\n\n- [ci skip] TODO for link to docs and comment spellcheck ([commit](https://github.com/Polymer/polymer/commit/5c919850))\n\n- Use values.reduce instead of a temporary array ([commit](https://github.com/Polymer/polymer/commit/be9d6210))\n\n- Add deprecation notice for class.template returning a string ([commit](https://github.com/Polymer/polymer/commit/530a68b4))\n\n- [skip-ci] update comment for Polymer.html ([commit](https://github.com/Polymer/polymer/commit/bdfa5fcb))\n\n- remove null/undefined to empty string ([commit](https://github.com/Polymer/polymer/commit/75d873a0))\n\n- Address feedback ([commit](https://github.com/Polymer/polymer/commit/d5070bbe))\n\n- `html` tag function for generating templates ([commit](https://github.com/Polymer/polymer/commit/1bba3abb))\n\n- Add example for flattened-nodes-observer ([commit](https://github.com/Polymer/polymer/commit/08ad6e37))\n\n- Minor updates based on review. ([commit](https://github.com/Polymer/polymer/commit/ed1454d6))\n\n- Use correct assertation. ([commit](https://github.com/Polymer/polymer/commit/4692510f))\n\n- Add tests for non-JSON literals on object props. ([commit](https://github.com/Polymer/polymer/commit/7d49e803))\n\n- Remove PropertiesElement in favor of PropertiesMixin. ([commit](https://github.com/Polymer/polymer/commit/40f02ea1))\n\n- FIx typo ([commit](https://github.com/Polymer/polymer/commit/8af14800))\n\n- Skip test in old browsers. ([commit](https://github.com/Polymer/polymer/commit/a1bd9a4f))\n\n- Remove `propertyNameForAttribute` since it's never needed. ([commit](https://github.com/Polymer/polymer/commit/8d57a6e9))\n\n- Fix subclassing and simplify. ([commit](https://github.com/Polymer/polymer/commit/e09285db))\n\n- Move property<->attribute case mapping to PropertiesChanged. ([commit](https://github.com/Polymer/polymer/commit/603123e1))\n\n- Allow non-JSON literals when property type is \"Object\". ([commit](https://github.com/Polymer/polymer/commit/77b17b43))\n\n- Update tests ([commit](https://github.com/Polymer/polymer/commit/82cf96bb))\n\n- [PropertiesMixin] Fix mapping property names from attributes ([commit](https://github.com/Polymer/polymer/commit/feac9328))\n\n- Add test for observing id attribute. ([commit](https://github.com/Polymer/polymer/commit/c56f74f9))\n\n- Cleanup based on review. ([commit](https://github.com/Polymer/polymer/commit/4b9170ab))\n\n- Fix deserializing dates. ([commit](https://github.com/Polymer/polymer/commit/8d24c212))\n\n- Factoring improvements around attribute serialize/deserialize ([commit](https://github.com/Polymer/polymer/commit/a7b46b15))\n\n- Remove crufty comment. ([commit](https://github.com/Polymer/polymer/commit/fb0f90bc))\n\n- Lint fix ([commit](https://github.com/Polymer/polymer/commit/e8c27671))\n\n- Add tests for setting custom `attribute` name ([commit](https://github.com/Polymer/polymer/commit/1e903a94))\n\n- Expose less protected data. ([commit](https://github.com/Polymer/polymer/commit/74fb5151))\n\n- ElementMixin uses PropertiesMixin for ([commit](https://github.com/Polymer/polymer/commit/0fe9434f))\n\n- PropertiesMixin ([commit](https://github.com/Polymer/polymer/commit/3c50f44a))\n\n- PropertyAccessors ([commit](https://github.com/Polymer/polymer/commit/5846d582))\n\n- PropertiesChanged ([commit](https://github.com/Polymer/polymer/commit/05cb5d2c))\n\n- Force literal true` to be set as an attribute with a value of empty string. ([commit](https://github.com/Polymer/polymer/commit/1b501944))\n\n- Better attribute suppport ([commit](https://github.com/Polymer/polymer/commit/c91b9d19))\n\n- fix some formatting and closure linting ([commit](https://github.com/Polymer/polymer/commit/5ae21a08))\n\n- Lint fixes. ([commit](https://github.com/Polymer/polymer/commit/946aad5c))\n\n- Renamed basic element to properties element ([commit](https://github.com/Polymer/polymer/commit/e3e128ba))\n\n- Implement `basic-element` with `properties-changed` ([commit](https://github.com/Polymer/polymer/commit/d26955b4))\n\n- Fix lint issues ([commit](https://github.com/Polymer/polymer/commit/b8fd241a))\n\n- Improve docs and add test for case conversion. ([commit](https://github.com/Polymer/polymer/commit/152f896f))\n\n- Add test to runner. ([commit](https://github.com/Polymer/polymer/commit/dcdb750b))\n\n- Adds `Polymer.BasicElement` ([commit](https://github.com/Polymer/polymer/commit/717a4f41))\n\n- Factor PropertiesChanged out of PropertyAccessors ([commit](https://github.com/Polymer/polymer/commit/aa4f186e))\n\n- Add `accessor` property to properties object ([commit](https://github.com/Polymer/polymer/commit/c7b43f78))\n\n- Factor to treeshake better ([commit](https://github.com/Polymer/polymer/commit/e91b6a75))\n\n## [v2.3.1](https://github.com/Polymer/polymer/tree/v2.3.1) (2017-12-07)\n- Add test that would fail with the \"last style\" behavior in master ([commit](https://github.com/Polymer/polymer/commit/913dfce6))\n\n- Use padding-top to get correct computed style on older safari ([commit](https://github.com/Polymer/polymer/commit/b7c56173))\n\n- Handle styles that are not direct children of templates correctly ([commit](https://github.com/Polymer/polymer/commit/0b1cd70a))\n\n- [ci skip] update changelog again ([commit](https://github.com/Polymer/polymer/commit/2d739c75))\n\n## [v2.3.0](https://github.com/Polymer/polymer/tree/v2.3.0) (2017-12-05)\n- [ci skip] update changelog ([commit](https://github.com/Polymer/polymer/commit/c727d35d))\n\n## [v2.2.1](https://github.com/Polymer/polymer/tree/v2.2.1) (2017-12-05)\n- [ci skip] commit new version in lib/utils/boot.html when using npm version ([commit](https://github.com/Polymer/polymer/commit/71fbf6ef))\n\n- change PolymerElement extern to var ([commit](https://github.com/Polymer/polymer/commit/5c3d58aa))\n\n- update node devDependencies ([commit](https://github.com/Polymer/polymer/commit/a39f3f41))\n\n- fix lint error ([commit](https://github.com/Polymer/polymer/commit/f242e197))\n\n- Fix :dir selectors with nested custom elements ([commit](https://github.com/Polymer/polymer/commit/3b76e86f))\n\n- Update test to be more descriptive ([commit](https://github.com/Polymer/polymer/commit/86a64b6c))\n\n- Annotate Polymer function with @global. (#4967) ([commit](https://github.com/Polymer/polymer/commit/b124b707))\n\n- make PASSIVE_TOUCH take an argument ([commit](https://github.com/Polymer/polymer/commit/c5407a8b))\n\n- Do not set touchend listeners to passive ([commit](https://github.com/Polymer/polymer/commit/84fa3bf3))\n\n- Add some @function annotations to APIs that are defined by assignment. ([commit](https://github.com/Polymer/polymer/commit/29f2a0e7))\n\n- add return jsdoc to void functions ([commit](https://github.com/Polymer/polymer/commit/a8105e55))\n\n- Update CONTRIBUTING.md ([commit](https://github.com/Polymer/polymer/commit/14fd53c3))\n\n- Fix typo. ([commit](https://github.com/Polymer/polymer/commit/581483f2))\n\n- Comment reworded based on feedback. ([commit](https://github.com/Polymer/polymer/commit/80a7f1e5))\n\n- Semantic issue (proposal) plus minor fixes ([commit](https://github.com/Polymer/polymer/commit/42ec14bf))\n\n- Depend on webcomponents and shadycss with shady-unscoped support ([commit](https://github.com/Polymer/polymer/commit/8241b887))\n\n- Also clarify `delay` units. Fixes #4707 ([commit](https://github.com/Polymer/polymer/commit/348ed92c))\n\n- Ensure re-sort/filter always happens after array item set. Fixes #3626 ([commit](https://github.com/Polymer/polymer/commit/f6d4771c))\n\n- Clarify docs on target-framerate. Fixes #4897 ([commit](https://github.com/Polymer/polymer/commit/c18a5349))\n\n- move test after ([commit](https://github.com/Polymer/polymer/commit/45598302))\n\n- test more permutations ([commit](https://github.com/Polymer/polymer/commit/f03e8d1b))\n\n- Fix missing comma in `Path.translate` JSDoc ([commit](https://github.com/Polymer/polymer/commit/41616c6f))\n\n- fix(bower): standardized version tagging (#4921) ([commit](https://github.com/Polymer/polymer/commit/6e3ae2e5))\n\n- Minor fixes (update URLs) ([commit](https://github.com/Polymer/polymer/commit/8e7024e6))\n\n- add license headers ([commit](https://github.com/Polymer/polymer/commit/518b4699))\n\n- Prep for processing of `shady-unscoped` moving to ShadyCSS ([commit](https://github.com/Polymer/polymer/commit/08c3a02e))\n\n- Implement type change in Polymer.ElementMixin ([commit](https://github.com/Polymer/polymer/commit/cda62d5f))\n\n- instance.$.foo should only give Elements ([commit](https://github.com/Polymer/polymer/commit/4837e4a8))\n\n- Annotate DomApi with @memberof Polymer ([commit](https://github.com/Polymer/polymer/commit/7308d8b6))\n\n- Clarify all elements between changes must apply mixing. Fixes #4914 ([commit](https://github.com/Polymer/polymer/commit/7360f42a))\n\n- add safari 11 to sauce testing ([commit](https://github.com/Polymer/polymer/commit/428ad8c2))\n\n- Fix tests on Firefox. ([commit](https://github.com/Polymer/polymer/commit/9a468335))\n\n- Update externs again. ([commit](https://github.com/Polymer/polymer/commit/1c5b731f))\n\n- Update externs. ([commit](https://github.com/Polymer/polymer/commit/8683b27c))\n\n- Lint fixes ([commit](https://github.com/Polymer/polymer/commit/092b210f))\n\n- Allow style elements to be separate in the element template. ([commit](https://github.com/Polymer/polymer/commit/819652eb))\n\n- Lint fix. ([commit](https://github.com/Polymer/polymer/commit/982d28c6))\n\n- Add support for styles with a `shady-unscoped` attribute ([commit](https://github.com/Polymer/polymer/commit/d77e073e))\n\n- [ci skip] Update CHANGELOG ([commit](https://github.com/Polymer/polymer/commit/314bada5))\n\n- [ci skip] version script did not work as expected ([commit](https://github.com/Polymer/polymer/commit/4265cba1))\n\n- adding test case for 4696 4706 ([commit](https://github.com/Polymer/polymer/commit/939ce63c))\n\n- Support property observers which are direct function references in addition to strings. Provides better static analysis and refactoring support in multiple tools. Alleviates the need for property reflection with Closure-compiler renaming. ([commit](https://github.com/Polymer/polymer/commit/4bae2b62))\n\n- removing package-lock.json from PR ([commit](https://github.com/Polymer/polymer/commit/0da00a1d))\n\n- implementing the code review suggestions ([commit](https://github.com/Polymer/polymer/commit/1b51f601))\n\n- Updating deserialize function (use of ternary operation). Fixes #4696 ([commit](https://github.com/Polymer/polymer/commit/ca139ed0))\n\n- Updating deserialize function. Fixes #4696 ([commit](https://github.com/Polymer/polymer/commit/277ca89a))\n\n## [v2.2.0](https://github.com/Polymer/polymer/tree/v2.2.0) (2017-10-18)\n- [ci skip] Autoupdate version when releasing ([commit](https://github.com/Polymer/polymer/commit/d893d6ae))\n\n- add edge 15, use chrome stable ([commit](https://github.com/Polymer/polymer/commit/c6f2d817))\n\n- super it and put back takeRecords ([commit](https://github.com/Polymer/polymer/commit/02e2f148))\n\n- more feedback ([commit](https://github.com/Polymer/polymer/commit/15cbdff5))\n\n- Address feedback ([commit](https://github.com/Polymer/polymer/commit/e71b84a8))\n\n- add some description of the dir mixin ([commit](https://github.com/Polymer/polymer/commit/f98ad117))\n\n- Fix linting ([commit](https://github.com/Polymer/polymer/commit/624189a3))\n\n- Always do the :dir transform ([commit](https://github.com/Polymer/polymer/commit/31c0ebc7))\n\n- Clean up closure externs ([commit](https://github.com/Polymer/polymer/commit/1e5ea942))\n\n- remove bogus semicolon ([commit](https://github.com/Polymer/polymer/commit/7d044b49))\n\n- Declare Polymer.Templatizer directly, for Closure. (#4870) ([commit](https://github.com/Polymer/polymer/commit/3b155173))\n\n- First draft of a `:dir` aware element mixin ([commit](https://github.com/Polymer/polymer/commit/2ef65aa6))\n\n- [ci-skip] Update CHANGELOG ([commit](https://github.com/Polymer/polymer/commit/28e60271))\n\n## [v2.1.1](https://github.com/Polymer/polymer/tree/v2.1.1) (2017-09-28)\n- Prepare for release 2.1.1 ([commit](https://github.com/Polymer/polymer/commit/f049dd91))\n\n- Move @externs before @license because Closure likes that. ([commit](https://github.com/Polymer/polymer/commit/c3f31455))\n\n- just move the style instead ([commit](https://github.com/Polymer/polymer/commit/61b2c8a5))\n\n- Copy <custom-style> styles to main document ([commit](https://github.com/Polymer/polymer/commit/155ab8a2))\n\n- Fix typos and jsdoc (#4846) ([commit](https://github.com/Polymer/polymer/commit/b19e180a))\n\n- [ci skip] update changelog ([commit](https://github.com/Polymer/polymer/commit/44fd1eaa))\n\n- Fix shady dom style querySelector ([commit](https://github.com/Polymer/polymer/commit/d5b6bad3))\n\n- Fix linter error ([commit](https://github.com/Polymer/polymer/commit/2da30c33))\n\n- Exclude script and style tags for parsing bindings ([commit](https://github.com/Polymer/polymer/commit/41fa90b3))\n\n- Special-case undefined textarea.value same as input. Fixes #4630 ([commit](https://github.com/Polymer/polymer/commit/8aa201b9))\n\n## [v2.1.0](https://github.com/Polymer/polymer/tree/v2.1.0) (2017-09-19)\n- [ci skip] bump version to 2.1.0 ([commit](https://github.com/Polymer/polymer/commit/64788aad))\n\n- Port #3844 to 2.x ([commit](https://github.com/Polymer/polymer/commit/00bc76e4))\n\n- Provide a `Polymer.setPassiveTouchGestures()` function ([commit](https://github.com/Polymer/polymer/commit/3547fd37))\n\n- Make sure closure types have braces ([commit](https://github.com/Polymer/polymer/commit/fb8039e0))\n\n- a few more comments in return ([commit](https://github.com/Polymer/polymer/commit/f6f0a3b7))\n\n- Fix setting, add smoke test ([commit](https://github.com/Polymer/polymer/commit/6312da57))\n\n- Optional passive touch listeners for gestures ([commit](https://github.com/Polymer/polymer/commit/5f7597f7))\n\n- Don't have `return /** comment */` lines ([commit](https://github.com/Polymer/polymer/commit/c802b8b2))\n\n- [ci skip] disable closure lint for now (travis java errors) ([commit](https://github.com/Polymer/polymer/commit/e45e5bba))\n\n- try to avoid introducing spelling errors in changelogs ([commit](https://github.com/Polymer/polymer/commit/7616e3c9))\n\n- spelling: webcomponents ([commit](https://github.com/Polymer/polymer/commit/70504627))\n\n- spelling: veiling ([commit](https://github.com/Polymer/polymer/commit/43f6b971))\n\n- spelling: unnecessary ([commit](https://github.com/Polymer/polymer/commit/dc0573f8))\n\n- spelling: toolkit ([commit](https://github.com/Polymer/polymer/commit/42edf634))\n\n- spelling: together ([commit](https://github.com/Polymer/polymer/commit/7d6e4351))\n\n- spelling: there-when ([commit](https://github.com/Polymer/polymer/commit/240701ec))\n\n- spelling: theming ([commit](https://github.com/Polymer/polymer/commit/d991cce1))\n\n- spelling: supported ([commit](https://github.com/Polymer/polymer/commit/4a2e7750))\n\n- spelling: stylesheet ([commit](https://github.com/Polymer/polymer/commit/d138df3c))\n\n- spelling: static ([commit](https://github.com/Polymer/polymer/commit/4354e710))\n\n- spelling: sometimes ([commit](https://github.com/Polymer/polymer/commit/802817dc))\n\n- spelling: shuffling ([commit](https://github.com/Polymer/polymer/commit/93a18c58))\n\n- spelling: returns ([commit](https://github.com/Polymer/polymer/commit/3f744c3c))\n\n- spelling: restart ([commit](https://github.com/Polymer/polymer/commit/58111054))\n\n- spelling: responsive ([commit](https://github.com/Polymer/polymer/commit/d1da7314))\n\n- spelling: resilient ([commit](https://github.com/Polymer/polymer/commit/d45855d9))\n\n- spelling: resetting ([commit](https://github.com/Polymer/polymer/commit/8fb47431))\n\n- spelling: reentrancy ([commit](https://github.com/Polymer/polymer/commit/5ea03d60))\n\n- spelling: readonly ([commit](https://github.com/Polymer/polymer/commit/ff294a90))\n\n- spelling: prototype ([commit](https://github.com/Polymer/polymer/commit/bbe54cc2))\n\n- spelling: protocols ([commit](https://github.com/Polymer/polymer/commit/83df6dad))\n\n- spelling: properties ([commit](https://github.com/Polymer/polymer/commit/bb74d2da))\n\n- spelling: preferring ([commit](https://github.com/Polymer/polymer/commit/00e0567e))\n\n- spelling: polyfill ([commit](https://github.com/Polymer/polymer/commit/ce0ca630))\n\n- spelling: parameterize ([commit](https://github.com/Polymer/polymer/commit/141cefe3))\n\n- spelling: omit ([commit](https://github.com/Polymer/polymer/commit/e3b04e51))\n\n- spelling: offset ([commit](https://github.com/Polymer/polymer/commit/ea0acb0d))\n\n- spelling: notification ([commit](https://github.com/Polymer/polymer/commit/ee741143))\n\n- spelling: name ([commit](https://github.com/Polymer/polymer/commit/159803a7))\n\n- spelling: multiple ([commit](https://github.com/Polymer/polymer/commit/602ee780))\n\n- spelling: loaded ([commit](https://github.com/Polymer/polymer/commit/f4529864))\n\n- spelling: jquery ([commit](https://github.com/Polymer/polymer/commit/88ce972d))\n\n- spelling: javascript ([commit](https://github.com/Polymer/polymer/commit/f1f7f669))\n\n- spelling: instead ([commit](https://github.com/Polymer/polymer/commit/c4be7f60))\n\n- spelling: initial ([commit](https://github.com/Polymer/polymer/commit/3862ce0a))\n\n- spelling: increments ([commit](https://github.com/Polymer/polymer/commit/8bda7f93))\n\n- spelling: identify ([commit](https://github.com/Polymer/polymer/commit/17678e1a))\n\n- spelling: github ([commit](https://github.com/Polymer/polymer/commit/0781b322))\n\n- spelling: getting ([commit](https://github.com/Polymer/polymer/commit/c1d7c3e8))\n\n- spelling: function ([commit](https://github.com/Polymer/polymer/commit/b9b22854))\n\n- spelling: falsy ([commit](https://github.com/Polymer/polymer/commit/d472919a))\n\n- spelling: enqueuing ([commit](https://github.com/Polymer/polymer/commit/96c8ed81))\n\n- spelling: element ([commit](https://github.com/Polymer/polymer/commit/d4e54c72))\n\n- spelling: effective ([commit](https://github.com/Polymer/polymer/commit/139edd00))\n\n- spelling: doesn't ([commit](https://github.com/Polymer/polymer/commit/aa35d779))\n\n- spelling: does ([commit](https://github.com/Polymer/polymer/commit/01f943d9))\n\n- spelling: disappearing ([commit](https://github.com/Polymer/polymer/commit/508c005a))\n\n- spelling: deserialized ([commit](https://github.com/Polymer/polymer/commit/2acbf5df))\n\n- spelling: customize ([commit](https://github.com/Polymer/polymer/commit/0a0ac248))\n\n- spelling: containing ([commit](https://github.com/Polymer/polymer/commit/2b09e75c))\n\n- spelling: components ([commit](https://github.com/Polymer/polymer/commit/e11d4d6b))\n\n- spelling: collection ([commit](https://github.com/Polymer/polymer/commit/38645c08))\n\n- spelling: children ([commit](https://github.com/Polymer/polymer/commit/c30c5d03))\n\n- spelling: changed ([commit](https://github.com/Polymer/polymer/commit/1579bf36))\n\n- spelling: behavior ([commit](https://github.com/Polymer/polymer/commit/65f27655))\n\n- spelling: attribute ([commit](https://github.com/Polymer/polymer/commit/d8f3f57d))\n\n- spelling: attached ([commit](https://github.com/Polymer/polymer/commit/adc4f0e1))\n\n- spelling: asynchronous ([commit](https://github.com/Polymer/polymer/commit/6c59f53b))\n\n- Explicitly set display none on dom-* elements (#4821) ([commit](https://github.com/Polymer/polymer/commit/65859b1c))\n\n- Publish DomBind in Polymer. scope ([commit](https://github.com/Polymer/polymer/commit/60054350))\n\n- Fix missing semi-colons in test folder ([commit](https://github.com/Polymer/polymer/commit/72a59f77))\n\n- Enable ESLint 'semi' rule ([commit](https://github.com/Polymer/polymer/commit/75c6fff7))\n\n- [ci skip] update package-lock ([commit](https://github.com/Polymer/polymer/commit/ca1ce196))\n\n- [ci skip] Add license headers to externs ([commit](https://github.com/Polymer/polymer/commit/f4a9e06e))\n\n- Polymer.Path.get accepts both a string path or an Array path, so functions that call this should allow for either as well. Already changed for Polymer.prototype.push here: ([commit](https://github.com/Polymer/polymer/commit/42ce5a88))\n\n- lint with closure as well ([commit](https://github.com/Polymer/polymer/commit/cc649e97))\n\n- Update closure compiler to support polymer pass v2 ([commit](https://github.com/Polymer/polymer/commit/a4591abc))\n\n- Revert \"Adds `restamp` mode to dom-repeat.\" ([commit](https://github.com/Polymer/polymer/commit/d439960a))\n\n- Add test to verify that importHref can be called twice ([commit](https://github.com/Polymer/polymer/commit/6ce904b3))\n\n- Fix compiling with Polymer({}) calls ([commit](https://github.com/Polymer/polymer/commit/d937d5fe))\n\n- Remove double space ([commit](https://github.com/Polymer/polymer/commit/bbf0e7c8))\n\n- Add development workflow-related files to gitignore (#4612) ([commit](https://github.com/Polymer/polymer/commit/d5c2629f))\n\n- Allow arbitrary whitespace in CSS imports ([commit](https://github.com/Polymer/polymer/commit/5c250d44))\n\n- Fix dom-module API docs with static `import` function ([commit](https://github.com/Polymer/polymer/commit/9f7df4cf))\n\n- [ci skip] update externs more from #4776 ([commit](https://github.com/Polymer/polymer/commit/c20b6574))\n\n- imported css modules should always be before element's styles ([commit](https://github.com/Polymer/polymer/commit/679a49e4))\n\n- Update closure annotation for Polymer.prototype.push ([commit](https://github.com/Polymer/polymer/commit/eb170cbb))\n\n- Fixed formatting. ([commit](https://github.com/Polymer/polymer/commit/48fac922))\n\n- Fix formatting of code in API docs (#4771) ([commit](https://github.com/Polymer/polymer/commit/eb406c71))\n\n- Lint clean. ([commit](https://github.com/Polymer/polymer/commit/4095e12d))\n\n- Separate scripts that modify configuration properties, as their ordering constraints are unusual. ([commit](https://github.com/Polymer/polymer/commit/49dbacb6))\n\n- test: convert XNestedRepeat to use an inlined string template. ([commit](https://github.com/Polymer/polymer/commit/c89155ba))\n\n- Don't rely on  implicitly creating a global,  does not. ([commit](https://github.com/Polymer/polymer/commit/28ed27e0))\n\n- Refer to Gestures.recognizers consistently. ([commit](https://github.com/Polymer/polymer/commit/3555b458))\n\n- Make test work in strict mode. ([commit](https://github.com/Polymer/polymer/commit/328ce594))\n\n- In tests, explicitly write to window when creating a new global for clarity. ([commit](https://github.com/Polymer/polymer/commit/674d4685))\n\n- [ci skip] remove duplicate definition for __dataHost in externs ([commit](https://github.com/Polymer/polymer/commit/5ab9032c))\n\n- [ci skip] update polymer-build and run-sequence ([commit](https://github.com/Polymer/polymer/commit/0c6aa882))\n\n- Fix tests in non-Chrome browsers ([commit](https://github.com/Polymer/polymer/commit/5a54c32b))\n\n- Better distinguish param name from namespaced name ([commit](https://github.com/Polymer/polymer/commit/a3d6e56b))\n\n- use wct 6 npm package ([commit](https://github.com/Polymer/polymer/commit/fbe8dcc4))\n\n- add mixin class instance properties to externs ([commit](https://github.com/Polymer/polymer/commit/34d22acd))\n\n- Add sanitizeDOMValue to settings.html ([commit](https://github.com/Polymer/polymer/commit/4d730e16))\n\n- Remove reference to Polymer._toOverride, it seems like an incomplete feature/part of the test. ([commit](https://github.com/Polymer/polymer/commit/981a7600))\n\n- Update custom-style API doc ([commit](https://github.com/Polymer/polymer/commit/52a7328e))\n\n- Use customElements.get rather than referring to the global for Polymer.DomModule ([commit](https://github.com/Polymer/polymer/commit/bb202378))\n\n- Add import of dom-module to file that uses it. ([commit](https://github.com/Polymer/polymer/commit/dbedcfc0))\n\n- Do not assign to a readonly property on window ([commit](https://github.com/Polymer/polymer/commit/b64e4862))\n\n- [ci skip] Fix documentation in PropertyAccessors ([commit](https://github.com/Polymer/polymer/commit/0f695d90))\n\n- [ci skip] fix closure warning ([commit](https://github.com/Polymer/polymer/commit/2e7dc00b))\n\n- Fix event path for tap event on touch ([commit](https://github.com/Polymer/polymer/commit/50bf45c3))\n\n- [ci skip] Update changelog ([commit](https://github.com/Polymer/polymer/commit/466624ae))\n\n- Update web-component-tester to stable version ([commit](https://github.com/Polymer/polymer/commit/ae78564c))\n\n- Disable closure linting until the count is driven down to a reasonable level ([commit](https://github.com/Polymer/polymer/commit/6335b24f))\n\n- Adds `restamp` mode to dom-repeat. ([commit](https://github.com/Polymer/polymer/commit/6cebeace))\n\n## [v2.0.2](https://github.com/Polymer/polymer/tree/v2.0.2) (2017-07-14)\n- remove broken npm script ([commit](https://github.com/Polymer/polymer/commit/27c67125))\n\n- depend on webcomponentsjs 1.0.2 ([commit](https://github.com/Polymer/polymer/commit/d522de0f))\n\n- cleanup and update npm dependencies ([commit](https://github.com/Polymer/polymer/commit/4176c6c2))\n\n- Update LegacyElementMixin.distributeContent ([commit](https://github.com/Polymer/polymer/commit/2daf9de2))\n\n- Remove crufty test ([commit](https://github.com/Polymer/polymer/commit/c96350b4))\n\n- [ci skip] remove one new closure warning for updating closure ([commit](https://github.com/Polymer/polymer/commit/0cb560a4))\n\n- Meaningful closure fixes from @ChadKillingsworth ([commit](https://github.com/Polymer/polymer/commit/88043077))\n\n- [ci skip] clean up mixin fn and regen externs ([commit](https://github.com/Polymer/polymer/commit/72022f27))\n\n- address some concerns from kschaaf ([commit](https://github.com/Polymer/polymer/commit/44653813))\n\n- zero warnings left ([commit](https://github.com/Polymer/polymer/commit/3e14a1d8))\n\n- [ci skip] Fix link closing quotes. ([commit](https://github.com/Polymer/polymer/commit/d1ad0c33))\n\n- Remove @suppress {missingProperties} ([commit](https://github.com/Polymer/polymer/commit/2efccb95))\n\n- Annotate Debouncer summary. (#4691) ([commit](https://github.com/Polymer/polymer/commit/806119ae))\n\n- Fix typo in templatize.html ([commit](https://github.com/Polymer/polymer/commit/de181d6e))\n\n- Move Debouncer memberof annotation to right place, and add a summary. (#4690) ([commit](https://github.com/Polymer/polymer/commit/77f06712))\n\n- remove PolymerPropertyEffects type, inline DataTrigger and DataEffect types ([commit](https://github.com/Polymer/polymer/commit/7612df67))\n\n- remove polymer-element dependency introduced by a merge conflict ([commit](https://github.com/Polymer/polymer/commit/3b7eedb8))\n\n- update closure log ([commit](https://github.com/Polymer/polymer/commit/344ebb4c))\n\n- remove dommodule imports ([commit](https://github.com/Polymer/polymer/commit/fc886306))\n\n- Create style-gather.html ([commit](https://github.com/Polymer/polymer/commit/73fbbb45))\n\n- README: fix typo ([commit](https://github.com/Polymer/polymer/commit/5355252a))\n\n- Remove unused `__needFullRefresh` ([commit](https://github.com/Polymer/polymer/commit/bdbbfa19))\n\n- Fixes #4650: if an observed path changes, the repeat should render but in addition, the path should be notified. This is necessary since “mutableData” is optional. ([commit](https://github.com/Polymer/polymer/commit/22d27aa0))\n\n- last two stragglers ([commit](https://github.com/Polymer/polymer/commit/9bd89203))\n\n- fix eslint warnings ([commit](https://github.com/Polymer/polymer/commit/ba720124))\n\n- Down to 30ish warnings, need PolymerPass v2 ([commit](https://github.com/Polymer/polymer/commit/de87c585))\n\n- Add lib/utils/settings.html to hold legacy settings and rootPath ([commit](https://github.com/Polymer/polymer/commit/3183e3f7))\n\n- Fix typo in dom-repeat.html ([commit](https://github.com/Polymer/polymer/commit/d6941a34))\n\n- guard all dommodule references ([commit](https://github.com/Polymer/polymer/commit/c3866a59))\n\n- add more missing imports ([commit](https://github.com/Polymer/polymer/commit/8c71456d))\n\n- Add mixin.html import to gesture-event-listeners.html ([commit](https://github.com/Polymer/polymer/commit/352dc33a))\n\n- more fixes ([commit](https://github.com/Polymer/polymer/commit/872e1c27))\n\n- rebaseline warnings with NTI specific warnings disabled, for now ([commit](https://github.com/Polymer/polymer/commit/abc229e5))\n\n- Fix parsing for argument whitespace. Fixes #4643. ([commit](https://github.com/Polymer/polymer/commit/a29d8876))\n\n- Upgrade babel-preset-babili to include RegExp fix from https://github.com/babel/babili/pull/490 ([commit](https://github.com/Polymer/polymer/commit/308cae6e))\n\n- Not an RC anymore ([commit](https://github.com/Polymer/polymer/commit/8290002b))\n\n- Just ensure content frag from _contentForTemplate is inert. Edge does not seem to always use the exact same owner document for templates. ([commit](https://github.com/Polymer/polymer/commit/b73caea0))\n\n- Fix typo in prop of FlattenedNodesObserver ([commit](https://github.com/Polymer/polymer/commit/57fe7dca))\n\n- [ci skip] Update Changelog ([commit](https://github.com/Polymer/polymer/commit/e03b2cce))\n\n- Fix some ElementMixin warnings. ([commit](https://github.com/Polymer/polymer/commit/c0a816f6))\n\n- Fix template.assetpath with typedef ([commit](https://github.com/Polymer/polymer/commit/ec3e948d))\n\n- fix dom-module related errors ([commit](https://github.com/Polymer/polymer/commit/07443645))\n\n- Fix fn binding error ([commit](https://github.com/Polymer/polymer/commit/bc504f64))\n\n- Reduce closure warnings in PropertyAccessors ([commit](https://github.com/Polymer/polymer/commit/3591be8b))\n\n- reduce closure warnings in TemplateStamp ([commit](https://github.com/Polymer/polymer/commit/c34ef0b2))\n\n- [ci skip] parameterize entries for closure task ([commit](https://github.com/Polymer/polymer/commit/3a80ad8f))\n\n- [ci skip] generating externs should be explicit ([commit](https://github.com/Polymer/polymer/commit/a8a57bf5))\n\n- Avoid firstElementChild on DocFrag for IE11 ([commit](https://github.com/Polymer/polymer/commit/02e31d78))\n\n- update externs for merge, update dependencies ([commit](https://github.com/Polymer/polymer/commit/e927bc9a))\n\n- Fix impl of _contentForTemplate. Add template-stamp tests. Fixes #4597 ([commit](https://github.com/Polymer/polymer/commit/06190c9d))\n\n- ensure latest closure, stay on polymer-build 1.1 until warnings can be ignored ([commit](https://github.com/Polymer/polymer/commit/7abd7037))\n\n- @mixes -> @appliesMixin ([commit](https://github.com/Polymer/polymer/commit/1f21ab1a))\n\n- @polymerMixin/@polymerMixinClass -> @mixinFunction/@mixinClass ([commit](https://github.com/Polymer/polymer/commit/f7e8021e))\n\n- @polymerElement -> @customElement/@polymer ([commit](https://github.com/Polymer/polymer/commit/231b21c0))\n\n- fix lint error ([commit](https://github.com/Polymer/polymer/commit/e5de1782))\n\n- remove all \"global this\" warnings ([commit](https://github.com/Polymer/polymer/commit/c0ddc60b))\n\n- remove `TemplateStamp`’s implicit dependency on `_initializeProperties` ([commit](https://github.com/Polymer/polymer/commit/f821e46a))\n\n- fix typing for Polymer.Element ([commit](https://github.com/Polymer/polymer/commit/0b152938))\n\n- inline cachingMixin into deduplicatingMixin ([commit](https://github.com/Polymer/polymer/commit/c3da5073))\n\n- initialize properties in `_initializeProperties` rather than `constructor` (allows work to be done before `_initializeProperties` and is needed for proto/instance property initialization . ([commit](https://github.com/Polymer/polymer/commit/f15e4ee6))\n\n- LegacyElementMixin to `@unrestricted` ([commit](https://github.com/Polymer/polymer/commit/c1eda7af))\n\n- set `isAttached` constructor (for closure) but set to undefined so not picked up as proto property (avoids initial binding value) ([commit](https://github.com/Polymer/polymer/commit/6a995a23))\n\n- Fix dedupingMixin ([commit](https://github.com/Polymer/polymer/commit/2c9ffac3))\n\n- Fix more closure warnings ([commit](https://github.com/Polymer/polymer/commit/f04d6311))\n\n- Fix more closure warnings ([commit](https://github.com/Polymer/polymer/commit/d0f78122))\n\n- Fix more closure warnings. ([commit](https://github.com/Polymer/polymer/commit/0c3e3c5f))\n\n- Fix more closure warnings. ([commit](https://github.com/Polymer/polymer/commit/b686cd77))\n\n- Fix more closure warnings. ([commit](https://github.com/Polymer/polymer/commit/0b22959f))\n\n- Fix more closure warnings. ([commit](https://github.com/Polymer/polymer/commit/2627e63a))\n\n- slighly better typing for mixin function ([commit](https://github.com/Polymer/polymer/commit/b3dfd38e))\n\n- gesture fixes ([commit](https://github.com/Polymer/polymer/commit/346e2d57))\n\n- Fix more closure warnings. ([commit](https://github.com/Polymer/polymer/commit/fa9823f7))\n\n- Fix some closure warnings. ([commit](https://github.com/Polymer/polymer/commit/f1a14982))\n\n- Fix some closure warnings. ([commit](https://github.com/Polymer/polymer/commit/51855541))\n\n- automate generating closure externs ([commit](https://github.com/Polymer/polymer/commit/89b12301))\n\n- Fix some closure warnings. ([commit](https://github.com/Polymer/polymer/commit/37abc4e3))\n\n- fix some closure warnings. ([commit](https://github.com/Polymer/polymer/commit/80f54421))\n\n## [v2.0.1](https://github.com/Polymer/polymer/tree/v2.0.1) (2017-05-25)\n- [ci skip] Prepare 2.0.1 ([commit](https://github.com/Polymer/polymer/commit/061b1048))\n\n- Improve comment more ([commit](https://github.com/Polymer/polymer/commit/39877086))\n\n- Improve comment ([commit](https://github.com/Polymer/polymer/commit/fa1469a9))\n\n- Add comment. ([commit](https://github.com/Polymer/polymer/commit/250067b3))\n\n- * Improve clarity: change `__dataInitialized` to `__dataReady` * When `_flushClients` is called, ensure that clients are always enabled or flushed as appropriate. This ensures that (1) clients that are enabled before the host is enabled flush properly, and (2) clients that are stamped but not enabled properly enable when the host flushes. ([commit](https://github.com/Polymer/polymer/commit/8e8692f7))\n\n- Fix typo in  runBindingEffect documentation ([commit](https://github.com/Polymer/polymer/commit/6bd8dcfa))\n\n- Fixes #4601. Client elements can be readied that have already enabled properties. This can happen when templatize is used to create instances with no properties. In this case, in order for properties to flush properly to clients, clients must be flushed. ([commit](https://github.com/Polymer/polymer/commit/06df53d9))\n\n- [ci skip] Update Changelog ([commit](https://github.com/Polymer/polymer/commit/c4e516f6))\n\n## [v2.0.0](https://github.com/Polymer/polymer/tree/v2.0.0) (2017-05-15)\n- [ci skip] bump version to 2.0.0 ([commit](https://github.com/Polymer/polymer/commit/712230fc))\n\n- [ci skip] Update Changelog ([commit](https://github.com/Polymer/polymer/commit/21ee3b4d))\n\n## [v2.0.0-rc.9](https://github.com/Polymer/polymer/tree/v2.0.0-rc.9) (2017-05-12)\n- [ci skip] Add alacarte usage smoke tests. ([commit](https://github.com/Polymer/polymer/commit/e54bc5f8))\n\n- [skip ci] doc fixes ([commit](https://github.com/Polymer/polymer/commit/b943aa0d))\n\n- Docs and slight renaming. ([commit](https://github.com/Polymer/polymer/commit/4eb252fe))\n\n- Add tests. ([commit](https://github.com/Polymer/polymer/commit/1f83fd7c))\n\n- Move hostStack to property-effects and make readyClients explicit ([commit](https://github.com/Polymer/polymer/commit/c7a81ea8))\n\n- Turn on accessors (via __dataInitialized) only after clients have completely flushed. ([commit](https://github.com/Polymer/polymer/commit/2f1e964c))\n\n- Adds `_enableProperties` as a new entry point that must be called to turn on properties. Prevents a bug where `_readyClients` can be called twice. ([commit](https://github.com/Polymer/polymer/commit/c6f9b315))\n\n- [ci skip] Fix doc createPropertyEffect -> addPropertyEffect ([commit](https://github.com/Polymer/polymer/commit/90e8cd95))\n\n- [ci skip] Update Changelog ([commit](https://github.com/Polymer/polymer/commit/448149d2))\n\n## [v2.0.0-rc.8](https://github.com/Polymer/polymer/tree/v2.0.0-rc.8) (2017-05-11)\n- Add test for boolean dynamicFn ([commit](https://github.com/Polymer/polymer/commit/03d21ce8))\n\n- Accept boolean or object map for dynamicFns ([commit](https://github.com/Polymer/polymer/commit/f197ce24))\n\n- update dependencies for v1 polyfills ([commit](https://github.com/Polymer/polymer/commit/d9b5b8f9))\n\n- Null the links when unbinding. ([commit](https://github.com/Polymer/polymer/commit/42230437))\n\n- Dedupe API docs. ([commit](https://github.com/Polymer/polymer/commit/e97a6eb7))\n\n- Move setup to suiteSetup ([commit](https://github.com/Polymer/polymer/commit/d5b282fa))\n\n- Uncomment previous tests ([commit](https://github.com/Polymer/polymer/commit/55b2d160))\n\n- Add tests ([commit](https://github.com/Polymer/polymer/commit/0f4ebf62))\n\n- [ci skip] port gen-changelog from 1.x ([commit](https://github.com/Polymer/polymer/commit/24dd897d))\n\n- Add static API for creating property fx and minor code refactoring. ([commit](https://github.com/Polymer/polymer/commit/7497065a))\n\n- [ci skip] remove bower.json version, add npm devDependencies & np publish config ([commit](https://github.com/Polymer/polymer/commit/6b6092e0))\n\n- Fix comment. ([commit](https://github.com/Polymer/polymer/commit/6f1dde76))\n\n- Fixes #4585. Data notifications do not flush host if host has not initialized clients. This preserves the Polymer 1.x guarantee that client dom is fully “readied” when data observers run. ([commit](https://github.com/Polymer/polymer/commit/3b6981d4))\n\n- Ensure no warnings for dynamic fns. Fixes #4575 ([commit](https://github.com/Polymer/polymer/commit/d72baf9d))\n\n- Corrected minor Method comments ([commit](https://github.com/Polymer/polymer/commit/8a2aeb65))\n\n- Removes the `disable-upgrade` feature from Polymer 2.0. Due to #4550, the feature has a flaw for native ES6 classes and would be better implemented as either a mixin or patch to `customElements.define`. ([commit](https://github.com/Polymer/polymer/commit/972b2bab))\n\n- Fix jsBin link. ([commit](https://github.com/Polymer/polymer/commit/811c334e))\n\n- Ensure tags in markdown are backtracked. Short-term stopgap to ensure they are not rendered in HTML. ([commit](https://github.com/Polymer/polymer/commit/e90ef30d))\n\n- Clean up gulpfile ([commit](https://github.com/Polymer/polymer/commit/764448c9))\n\n- bump wct version ([commit](https://github.com/Polymer/polymer/commit/bafa1ecd))\n\n- Disabling `lint-closure` until the error count is driven to 0 ([commit](https://github.com/Polymer/polymer/commit/c98e3799))\n\n- fix test failures on safari 9 and chrome 41 w/focus event ([commit](https://github.com/Polymer/polymer/commit/0b00f2d9))\n\n- update debounce example. ([commit](https://github.com/Polymer/polymer/commit/5be7ec99))\n\n- Fixes #4553, #4554 ([commit](https://github.com/Polymer/polymer/commit/36792f94))\n\n- save closure warnings to \"closure.log\" file ([commit](https://github.com/Polymer/polymer/commit/25cfc882))\n\n- use shadycss externs directly, now only 498 warnings ([commit](https://github.com/Polymer/polymer/commit/c21a63db))\n\n- add gulp task to lint for closure warnings ([commit](https://github.com/Polymer/polymer/commit/4e782741))\n\n## [v2.0.0-rc.7](https://github.com/Polymer/polymer/tree/v2.0.0-rc.7) (2017-04-19)\n- Add more tests. ([commit](https://github.com/Polymer/polymer/commit/73df8c5b))\n\n- Update jsBin template for 2.0 ([commit](https://github.com/Polymer/polymer/commit/4a2db9ca))\n\n- [ci skip] Update link to jsBin template for 2.0. ([commit](https://github.com/Polymer/polymer/commit/0aeb3170))\n\n- Move computeLinkedPaths out of hot path and into sync setter. ([commit](https://github.com/Polymer/polymer/commit/d722cb9c))\n\n- [ci skip] Add note re: purpose of test ([commit](https://github.com/Polymer/polymer/commit/7ecbf258))\n\n- Fix test for fallback \\_readyClients. Fixes #4547 ([commit](https://github.com/Polymer/polymer/commit/85184e8b))\n\n- Process paths regardless of accessor, & loop on computeLinkedPaths. Fixes #4542 ([commit](https://github.com/Polymer/polymer/commit/e2d17020))\n\n## [v2.0.0-rc.6](https://github.com/Polymer/polymer/tree/v2.0.0-rc.6) (2017-04-17)\n- [ci skip] Fix API docs ([commit](https://github.com/Polymer/polymer/commit/5a4427bf))\n\n- Guard against overwriting bound values with hasOwnProperty. Fixes #4540 ([commit](https://github.com/Polymer/polymer/commit/4c023740))\n\n- [ci skip] reduce warnings ([commit](https://github.com/Polymer/polymer/commit/00f9e3eb))\n\n- fix globals for goog.reflect.objectProperty -> JSCompiler_renameProperty swap ([commit](https://github.com/Polymer/polymer/commit/8867fde5))\n\n- [ci skip] remove outdated externs file ([commit](https://github.com/Polymer/polymer/commit/626a085d))\n\n- lint and compile successfully ([commit](https://github.com/Polymer/polymer/commit/a2fa1005))\n\n- update dependencies ([commit](https://github.com/Polymer/polymer/commit/36603bc4))\n\n- Rename `setPrivate` -> `setReadOnly` ([commit](https://github.com/Polymer/polymer/commit/521ed3de))\n\n- Add `setPrivate` arg to `setProperties` ([commit](https://github.com/Polymer/polymer/commit/e6e4803f))\n\n- Never accidental test change ([commit](https://github.com/Polymer/polymer/commit/28c15caa))\n\n- Remove unused @method ([commit](https://github.com/Polymer/polymer/commit/6d636138))\n\n- Standardize @return, @param, type case. ([commit](https://github.com/Polymer/polymer/commit/8cab18b1))\n\n- Fix jsdoc warnings. ([commit](https://github.com/Polymer/polymer/commit/dab794b2))\n\n- jsdoc fixes. ([commit](https://github.com/Polymer/polymer/commit/38a13f66))\n\n- Fix jsdoc issues. ([commit](https://github.com/Polymer/polymer/commit/86d2eebc))\n\n- Fix jsdoc issues. ([commit](https://github.com/Polymer/polymer/commit/8a11c8c3))\n\n- Enable error on jsdoc mistake. ([commit](https://github.com/Polymer/polymer/commit/72a454e9))\n\n- fix @license comments & shadycss imports. Remove custom style from externs ([commit](https://github.com/Polymer/polymer/commit/59350ad4))\n\n- closure advanced compilation ([commit](https://github.com/Polymer/polymer/commit/eea1ca23))\n\n## [v2.0.0-rc.5](https://github.com/Polymer/polymer/tree/v2.0.0-rc.5) (2017-04-13)\n- Eliminate rest args for better perf on stable chrome. ([commit](https://github.com/Polymer/polymer/commit/fa67457c))\n\n- Fix perf regressions. ([commit](https://github.com/Polymer/polymer/commit/86e35e3a))\n\n- Move second tap test to the correct spot. ([commit](https://github.com/Polymer/polymer/commit/6e4b87c1))\n\n- Add GestureEventListeners to dom-bind. ([commit](https://github.com/Polymer/polymer/commit/4f628fd9))\n\n- Add more comments ([commit](https://github.com/Polymer/polymer/commit/d0bd96d4))\n\n- [ci skip] Fix comment. ([commit](https://github.com/Polymer/polymer/commit/becd1d3b))\n\n- alias another way ([commit](https://github.com/Polymer/polymer/commit/d297047e))\n\n- use chrome beta ([commit](https://github.com/Polymer/polymer/commit/0724f187))\n\n- Add more HTMLImports.whenReady ([commit](https://github.com/Polymer/polymer/commit/bc713187))\n\n- Address feedback from review: * Refactor `_bindTemplate` to remove problematic `hasCreatedAccessors` * Remove vestigial `dom` from `_bindTemplate` call * Rename `_unstampTemplate` to `_removeBoundDom` * Add `infoIndex` to `nodeInfo` (and renamed parent & index) * Add test to ensure runtime accessors created for new props in runtime stamped template * Changed custom binding test to use different prop names * Added test for #first count after removing bound dom ([commit](https://github.com/Polymer/polymer/commit/b9fafb7e))\n\n- Fix lint error. ([commit](https://github.com/Polymer/polymer/commit/dff5f2bc))\n\n- Ensure prototype wasn't affected by runtime effects. ([commit](https://github.com/Polymer/polymer/commit/bf2dbe0a))\n\n- Add tests for adding/removing runtime property effects. ([commit](https://github.com/Polymer/polymer/commit/14711067))\n\n- Added tests for custom parsing, effects, and binding. ([commit](https://github.com/Polymer/polymer/commit/1cf955b9))\n\n- Add initial runtime stamping tests. ([commit](https://github.com/Polymer/polymer/commit/eb6ab63e))\n\n- Fix changelog generation ([commit](https://github.com/Polymer/polymer/commit/8c103d98))\n\n- Address feedback based on review. * PropertyAccessors must call `_flushProperties` to enable * Avoid tearing off oldProps (unnecessary) * Add `addBinding` docs * Merge notifyListeners into `setupBindings` * Add comment re: path-bindings not being overridable * Remove `dom` argument from `_bindTemplate` * Rename `_stampBoundTemplate` back to `_stampTemplate` ([commit](https://github.com/Polymer/polymer/commit/6af84c45))\n\n- Put $ on dom, and assign to element as needed. Eliminate _templateInfo reference. ([commit](https://github.com/Polymer/polymer/commit/03bed19d))\n\n- Fix _hasAccessor for readOnly. Collapse addBinding & addBindingEffects ([commit](https://github.com/Polymer/polymer/commit/396c102c))\n\n- Improvements to binding API: - Adds override points for _parseBindings and _evaluateBinding - Adds support for runtime template binding - Moves ready(), _hasAccessor tracking, and instance property swizzle at ready time to PropertyAccessors ([commit](https://github.com/Polymer/polymer/commit/ea4e7d97))\n\n## [v2.0.0-rc.4](https://github.com/Polymer/polymer/tree/v2.0.0-rc.4) (2017-04-12)\n- fix lint error ([commit](https://github.com/Polymer/polymer/commit/e397c434))\n\n- Only style elements with templates ([commit](https://github.com/Polymer/polymer/commit/2356f7b8))\n\n- [ci skip] note safari bugs ([commit](https://github.com/Polymer/polymer/commit/ef90168b))\n\n- Various Safari 10.1 fixes ([commit](https://github.com/Polymer/polymer/commit/dea052a2))\n\n- Add `@memberof` annotation for Polymer.Debouncer ([commit](https://github.com/Polymer/polymer/commit/352878d5))\n\n- Import mutable-data.html in dom-bind ([commit](https://github.com/Polymer/polymer/commit/bbc0373c))\n\n- Correct changelog version title ([commit](https://github.com/Polymer/polymer/commit/9555ca34))\n\n- Fix readme. ([commit](https://github.com/Polymer/polymer/commit/bbfea905))\n\n- tighten up custom-style-late test ([commit](https://github.com/Polymer/polymer/commit/2106f656))\n\n- Fixes #4478 by adding a better warning for attributes that cannot deserialize from JSON. ([commit](https://github.com/Polymer/polymer/commit/dba28c06))\n\n- Adds back the `beforeRegister` method. Users can no longer set the `is` property in this method; however, dynamic property effects can still be installed here. ([commit](https://github.com/Polymer/polymer/commit/7639cf81))\n\n- Fixes #4447. Re-introduce the `hostStack` in order to maintain “client before host” ordering when `_flushProperties` is called before `connectedCallback` (e.g. as Templatize does). ([commit](https://github.com/Polymer/polymer/commit/8467a696))\n\n- Fix custom-style-late tests ([commit](https://github.com/Polymer/polymer/commit/caafef79))\n\n- Add test for ensuring complicated mixin ordering is correct ([commit](https://github.com/Polymer/polymer/commit/6d663354))\n\n- move lazy-upgrade out to separate mixins repo ([commit](https://github.com/Polymer/polymer/commit/deb5a9a5))\n\n- Only check bounding client rect on clicks that target elements ([commit](https://github.com/Polymer/polymer/commit/af37d04c))\n\n- Adds tests from https://github.com/Polymer/polymer/pull/4099. The other changes from the PR are no longer needed. ([commit](https://github.com/Polymer/polymer/commit/c5710666))\n\n- clean up code, factor processing lazy candidates, better docs ([commit](https://github.com/Polymer/polymer/commit/189a2083))\n\n- Update templatize.html ([commit](https://github.com/Polymer/polymer/commit/2abfe09e))\n\n- Doc fix (correct callback name) ([commit](https://github.com/Polymer/polymer/commit/57d22f4c))\n\n- Fixed templatize typo ([commit](https://github.com/Polymer/polymer/commit/b6b43f36))\n\n- Work around IE/Edge bug with :not([attr]) selectors ([commit](https://github.com/Polymer/polymer/commit/c3036232))\n\n- Remove support for lazy-upgrade inside dom-if and dom-repeat ([commit](https://github.com/Polymer/polymer/commit/1b4a9781))\n\n- Fix image in README ([commit](https://github.com/Polymer/polymer/commit/b860594a))\n\n- Remove useless id check on mixins ([commit](https://github.com/Polymer/polymer/commit/8c1a5765))\n\n- move dom-change listener for lazy-upgrade before `super.ready()` ([commit](https://github.com/Polymer/polymer/commit/ba60b820))\n\n- [ci skip] Update doc ([commit](https://github.com/Polymer/polymer/commit/f87790d6))\n\n- [ci skip] Update doc ([commit](https://github.com/Polymer/polymer/commit/b9774801))\n\n- Add API docs. ([commit](https://github.com/Polymer/polymer/commit/1eb0df49))\n\n- nodeInfo -> nodeInfoList ([commit](https://github.com/Polymer/polymer/commit/eed67504))\n\n- Updates based on PR feedback. API docs in progress. ([commit](https://github.com/Polymer/polymer/commit/627352db))\n\n- * ensure element cannot return to “disabled” state after upgrading. * ensure nested `beforeNextRender` calls always go before the next render * ensure nested `afterNextRender` are called after additional renders ([commit](https://github.com/Polymer/polymer/commit/e9c58add))\n\n- Fixes #4437. Ensure `_registered` is called 1x for each element class using `LegacyElementMixin`. Ensure that a behaviors’s `registered` method is called for any extending class. ([commit](https://github.com/Polymer/polymer/commit/de09d730))\n\n- Separate binding-specific code from template stamp. Expose override points. ([commit](https://github.com/Polymer/polymer/commit/e95afeb1))\n\n- Use webcomponents-lite for test ([commit](https://github.com/Polymer/polymer/commit/50ae3bb7))\n\n- add lazy-upgrade tests ([commit](https://github.com/Polymer/polymer/commit/71b70aaa))\n\n- make a mixin for lazy upgrading ([commit](https://github.com/Polymer/polymer/commit/9891e484))\n\n- implements `disable-upgrade` attribute which prevents readying an element until the attribute is removed. ([commit](https://github.com/Polymer/polymer/commit/a222078e))\n\n## [v2.0.0-rc.3](https://github.com/Polymer/polymer/tree/v2.0.0-rc.3) (2017-03-15)\n- add properties, behaviors, observers, hostAttributes, listeners on prototype ([commit](https://github.com/Polymer/polymer/commit/93cf3246))\n\n- [skip ci] update test comments ([commit](https://github.com/Polymer/polymer/commit/bb52071b))\n\n- better comment ([commit](https://github.com/Polymer/polymer/commit/a081e669))\n\n- get behaviors only from prototypes ([commit](https://github.com/Polymer/polymer/commit/8bac5c60))\n\n- behaviors ONLY on the prototype ([commit](https://github.com/Polymer/polymer/commit/444c043c))\n\n- add instance behaviors ([commit](https://github.com/Polymer/polymer/commit/4bf7bdd7))\n\n- [ci skip] minor doc edits. ([commit](https://github.com/Polymer/polymer/commit/4ae65ba2))\n\n- [ci skip] expand range of dependencies to all rcs ([commit](https://github.com/Polymer/polymer/commit/46c10465))\n\n## [v2.0.0-rc.2](https://github.com/Polymer/polymer/tree/v2.0.0-rc.2) (2017-03-07)\n- another test fix. ([commit](https://github.com/Polymer/polymer/commit/d9418e1a))\n\n- fix behavior warn test. ([commit](https://github.com/Polymer/polymer/commit/4439436f))\n\n- update to latest webcomponents rc. ([commit](https://github.com/Polymer/polymer/commit/46219a39))\n\n- move mutable data mixin to be loaded by polymer.html ([commit](https://github.com/Polymer/polymer/commit/7cebe120))\n\n- Fix 4387. Ensure `dom-change` fired with `composed: true`. ([commit](https://github.com/Polymer/polymer/commit/3e683297))\n\n- Allow hybrid elements (like iron-list) to make template instances with mutable data ([commit](https://github.com/Polymer/polymer/commit/ea392e3f))\n\n- Don't override the goog namespace if it already exists ([commit](https://github.com/Polymer/polymer/commit/b30deb22))\n\n- Use correct version ([commit](https://github.com/Polymer/polymer/commit/3b7d4484))\n\n- Fix spelling error ([commit](https://github.com/Polymer/polymer/commit/c14ea57f))\n\n- [ci skip] Fix note re: transpilation ([commit](https://github.com/Polymer/polymer/commit/8fd1b212))\n\n- [ci skip] Remove obsolete note re: pre-upgrade attribute vs. property priority ([commit](https://github.com/Polymer/polymer/commit/3dd776fe))\n\n- [ci skip] Fix note re: attached ([commit](https://github.com/Polymer/polymer/commit/b67736ec))\n\n- [ci skip] Add back intro README content from 1.x, updated to 2.x syntax. ([commit](https://github.com/Polymer/polymer/commit/1235f449))\n\n## [v2.0.0-rc.1](https://github.com/Polymer/polymer/tree/v2.0.0-rc.1) (2017-03-06)\n\n<!-- the changelog tool broke, so this is ported from https://www.polymer-project.org/2.0/docs/release-notes#v-2-0-0-rc.1 -->\nThe following notable changes have been made since the 2.0 Preview announcement.\n\n-   The `config` getter on element classes has been replaced by individual `properties` and\n    `observers` getters, more closely resembling the 1.x syntax.\n\n    ```js\n    static get properties() {\n      return {\n        aProp: String,\n        bProp: Number\n      }\n    }\n    static get observers() {\n      return [\n        '_observeStuff(aProp,bProp)'\n      ]\n    }\n    ```\n\n-   1.x-style dirty checking has been reinstated for better performance. An optional mixin is\n    available for elements to skip dirty checking of objects and arrays, which may be more easy to\n    integrate with some state management systems. For details, see\n    [Using the MutableData mixin](devguide/data-system#mutable-data) in Data system concepts.\n\n-   Support for dynamically-created `custom-style` elements has been added.\n\n-   Support for the external style sheet syntax, `<link rel=\"import\" type=\"css\">` has\n    been added. This was deprecated in 1.x, but will be retained until an alternate solution is\n    available for importing unprocessed CSS.\n\n-   New properties `rootPath` and `basePath` were added to `Polymer.Element` to allow authors\n    to configure how URLs are rewritten inside templates. For details, see the\n    [Update URLs in templates](./upgrade#urls-in-templates) in the Upgrade guide.\n\n\n## [v1.9.1-dev](https://github.com/Polymer/polymer/tree/v1.9.1-dev) (2017-04-17)\n- Remove use of ES6 API. ([commit](https://github.com/Polymer/polymer/commit/96010657))\n\n- Remove use of ES6 API. ([commit](https://github.com/Polymer/polymer/commit/646dce69))\n\n- Ensure optimization uses hybrid parentNode ([commit](https://github.com/Polymer/polymer/commit/b7f00992))\n\n- Use local `parentNode` ([commit](https://github.com/Polymer/polymer/commit/2e4290f8))\n\n- Capture hybridDomRepeat. ([commit](https://github.com/Polymer/polymer/commit/ee3b9a69))\n\n- Fix dom-if detachment ([commit](https://github.com/Polymer/polymer/commit/2722532b))\n\n- Add dom-if test for add/remove. ([commit](https://github.com/Polymer/polymer/commit/a2825650))\n\n- Add test for add & remove ([commit](https://github.com/Polymer/polymer/commit/4c87e1d9))\n\n- Add 2.x hybrid affordances for stamping template content. Fixes #4536 ([commit](https://github.com/Polymer/polymer/commit/53053eb4))\n\n- Fix lint ([commit](https://github.com/Polymer/polymer/commit/f29104f2))\n\n- Make tests more strict. ([commit](https://github.com/Polymer/polymer/commit/ea65a6d0))\n\n- Use `_importPath` in `resolveUrl` so it available early. Fixes #4532 ([commit](https://github.com/Polymer/polymer/commit/1a7d3b11))\n\n- [ci skip] update Changelog ([commit](https://github.com/Polymer/polymer/commit/3ce4e176))\n\n## [v1.9.0-dev](https://github.com/Polymer/polymer/tree/v1.9.0-dev) (2017-04-13)\n- [ci skip] skip looking in build log, again ([commit](https://github.com/Polymer/polymer/commit/1d282c7f))\n\n- [ci skip] backport changelog fixes ([commit](https://github.com/Polymer/polymer/commit/d6a7ac71))\n\n- * allow setting `rootPath` * disallow setting `importPath` (this is supported in 2.x but not 1.x) ([commit](https://github.com/Polymer/polymer/commit/ac067652))\n\n- Add `importPath` and `rootPath` to support 2.x hybrid compatible elements. ([commit](https://github.com/Polymer/polymer/commit/daaf460a))\n\n- [ci skip] Update Changelog ([commit](https://github.com/Polymer/polymer/commit/80c899f4))\n\n- Add missing semicolon after variable assignment ([commit](https://github.com/Polymer/polymer/commit/afb21c8f))\n\n- Update PRIMER.md ([commit](https://github.com/Polymer/polymer/commit/4d66a353))\n\n## [v1.8.1-dev](https://github.com/Polymer/polymer/tree/v1.8.1-dev) (2017-02-27)\n- Exclude SD polyfill tests for Edge due to lack of workarounds for Edge DocFrag bugs. ([commit](https://github.com/Polymer/polymer/commit/de45ba02))\n\n- [ci skip] Update comment to include reference to problem browser. ([commit](https://github.com/Polymer/polymer/commit/72f21fe6))\n\n- Check documentElement instead of body to guarantee it's there. ([commit](https://github.com/Polymer/polymer/commit/a0ad3bbe))\n\n- add tests ([commit](https://github.com/Polymer/polymer/commit/20de9287))\n\n- Adds a setting `preserveStyleIncludes` which, when used with a shadow dom targeted css build and native custom properties, will copy styles into the Shadow DOM template rather than collapsing them into a single style. This will (1) allow the browser to optimize parsing of shared styles because they remain intact, (2) reduce the size of the css build resources when shared styles are used since they are not pre-collapsed. This option does perform registration runtime work to add included styles to element templates. ([commit](https://github.com/Polymer/polymer/commit/2315547e))\n\n- Fix test failures by feature detecting instance `properties` accessors. Can't rely on `__proto__` on IE10, but that browser doesn't need to avoid `properties`. ([commit](https://github.com/Polymer/polymer/commit/f2a12cb1))\n\n- Read properties off of proto during configuration. ([commit](https://github.com/Polymer/polymer/commit/a68c0b3e))\n\n- remove cruft. ([commit](https://github.com/Polymer/polymer/commit/632f0e47))\n\n- Ensure disable-upgrade elements are not \"configured\". Fixes #4302 ([commit](https://github.com/Polymer/polymer/commit/b36915f6))\n\n- change lastresponse to last-response in dom-bind example ([commit](https://github.com/Polymer/polymer/commit/4427b0b6))\n\n- [ci skip] Update Changelog ([commit](https://github.com/Polymer/polymer/commit/2d804a28))\n\n## [v1.8.0-dev](https://github.com/Polymer/polymer/tree/v1.8.0-dev) (2017-02-06)\n- Add comment. ([commit](https://github.com/Polymer/polymer/commit/a42cb209))\n\n- Only keep `disable-upgrade` attribute if it is an attribute binding. ([commit](https://github.com/Polymer/polymer/commit/62e9b84b))\n\n- spacing. ([commit](https://github.com/Polymer/polymer/commit/5030c1b9))\n\n- Update webcomponentsjs dependency ([commit](https://github.com/Polymer/polymer/commit/ca7dbb84))\n\n- Change `isInert` to `disable-upgrade` and feature is now supported only via the `disable-upgrade` attribute. ([commit](https://github.com/Polymer/polymer/commit/f8f903cf))\n\n- Add tests for `is-inert` ([commit](https://github.com/Polymer/polymer/commit/e1561f65))\n\n- Prevent annotator from removing the `is-inert` attribute. ([commit](https://github.com/Polymer/polymer/commit/91925148))\n\n- fixes for users of Polymer.Class ([commit](https://github.com/Polymer/polymer/commit/0f53bef4))\n\n- Add support for `isInert` to allow elements to boot up in an inert state. e.g. `<x-foo is-inert></x-foo>`. Setting `xFoo.isInert = false` causes the element to boot up. ([commit](https://github.com/Polymer/polymer/commit/ca3f59d3))\n\n- Small typos updated ([commit](https://github.com/Polymer/polymer/commit/bc023648))\n\n- work around older firefox handling of the \"properties\" property on HTMLElement prototype ([commit](https://github.com/Polymer/polymer/commit/13f36c7f))\n\n- improve comments ([commit](https://github.com/Polymer/polymer/commit/c76ba5b9))\n\n- Add comments. Behavior fast copy flag changed to `_noAccessors`. ([commit](https://github.com/Polymer/polymer/commit/52ea6002))\n\n- Fix tests on IE10 and simplify constructor shortcut. ([commit](https://github.com/Polymer/polymer/commit/e588f1f5))\n\n- Make dom-module work on older Safari. ([commit](https://github.com/Polymer/polymer/commit/73b62a63))\n\n- micro-optimizations: (1) favor mixin over extends where possible, (2) unroll behavior lifecycle calls, (3) avoid creating a custom constructor when not used, (4) provide `_skipDefineProperty` setting on behaviors which copies properties via assignment rather than `copyOwnProperty` ([commit](https://github.com/Polymer/polymer/commit/a1c1285d))\n\n- Ensure done. ([commit](https://github.com/Polymer/polymer/commit/08753237))\n\n- Test positive case of suppressBindingNotifications ([commit](https://github.com/Polymer/polymer/commit/1b19b784))\n\n- Add notifyDomBind to dom-bind. ([commit](https://github.com/Polymer/polymer/commit/ad7f91d6))\n\n- Test Polymer.Settings inside test. ([commit](https://github.com/Polymer/polymer/commit/4b286f19))\n\n- Revert unnecessary change. ([commit](https://github.com/Polymer/polymer/commit/dcde6d4c))\n\n- Fix test lint issue. ([commit](https://github.com/Polymer/polymer/commit/26c669ce))\n\n- Add global flags to suppress unnecessary notification events. Fixes #4262. * `Polymer.Settings.suppressTemplateNotifications `- disables `dom-change` and `rendered-item-count` events from `dom-if`, `dom-repeat`, and `don-bind`. Users can opt back into `dom-change` events by setting the `notify-dom-change` attribute (`notifyDomChange: true` property) to `dom-if`/`don-repeat` instances. * `Polymer.Settings.suppressBindingNotifications` - disables notify effects when propagating data downward via bindings. Generally these are never useful unless users are explicitly doing something like `<my-el foo=\"{{foo}} on-foo-changed=\"{{handleFoo}}\">` or calling `addEventListener('foo-changed', ...)` on an element where `foo` is bound (we attempted to make this the default some time back but needed to revert it when we found via https://github.com/Polymer/polymer/issues/3077 that users were indeed doing this).  Users that avoid these patterns can enjoy the potentially significant benefit of suppressing unnecessary events during downward data flow by opting into this flag. ([commit](https://github.com/Polymer/polymer/commit/83e14c43))\n\n- Fix `strip-whitespace` for nested templates. ([commit](https://github.com/Polymer/polymer/commit/a3b75eb3))\n\n- [ci skip] update changelog v1.7.1 ([commit](https://github.com/Polymer/polymer/commit/03e22a1c))\n\n- Close backtick in ISSUE_TEMPLATE.md ([commit](https://github.com/Polymer/polymer/commit/b0dea8bc))\n\n## [v1.7.1-dev](https://github.com/Polymer/polymer/tree/v1.7.1-dev) (2016-12-14)\n- Remove dependency on WebComponents for IE detection ([commit](https://github.com/Polymer/polymer/commit/650c16a9))\n\n- Make sure text nodes are distributed when translating slot to content ([commit](https://github.com/Polymer/polymer/commit/87e312f1))\n\n- always use the document listener ([commit](https://github.com/Polymer/polymer/commit/5ddcb8d1))\n\n- Add tests for no-gesture interop ([commit](https://github.com/Polymer/polymer/commit/4be7e9f6))\n\n- fix lint error ([commit](https://github.com/Polymer/polymer/commit/9c8eaa9d))\n\n- Use document-wide passive touch listener to update ghostclick blocker target ([commit](https://github.com/Polymer/polymer/commit/947172f8))\n\n- only need to recalc if styleProperties missing ([commit](https://github.com/Polymer/polymer/commit/5bfe2792))\n\n- simpler implementation, only recompute when using shim variables ([commit](https://github.com/Polymer/polymer/commit/5231d87f))\n\n- [ci skip] update travis.yml from 2.0 ([commit](https://github.com/Polymer/polymer/commit/1a9c5c8c))\n\n- Always update style properties when calling getComputedStyleValue ([commit](https://github.com/Polymer/polymer/commit/fb8575c6))\n\n- Add tests ([commit](https://github.com/Polymer/polymer/commit/29de0055))\n\n- Fix #4123: Memory leak when using `importHref` ([commit](https://github.com/Polymer/polymer/commit/132010ea))\n\n- Prevent _showHideChildren from being called on placeholders. ([commit](https://github.com/Polymer/polymer/commit/0468c60a))\n\n- fix broken link to Google JavaScript syle guide in documentation ([commit](https://github.com/Polymer/polymer/commit/376d146f))\n\n- Better explanation thanks to @kevinpschaaf ([commit](https://github.com/Polymer/polymer/commit/0dae8f0d))\n\n- [ci skip] fix changelog title ([commit](https://github.com/Polymer/polymer/commit/16712cb6))\n\n- [ci skip] Update Changelog for 1.7.0 ([commit](https://github.com/Polymer/polymer/commit/d6af21b5))\n\n- Resolving issue #1745 with Polymer docs ([commit](https://github.com/Polymer/polymer/commit/bb875275))\n\n- fixed broken tests/missing web components ([commit](https://github.com/Polymer/polymer/commit/f2b01e34))\n\n- 3430 - ie memory leak fixes - disable event caching, fixed resolver url adding to root doc, and weak map ie issues ([commit](https://github.com/Polymer/polymer/commit/a6e66f92))\n\n- Briefly explain how to split element definition ([commit](https://github.com/Polymer/polymer/commit/c6462286))\n\n- Fix copy&pasted comment ([commit](https://github.com/Polymer/polymer/commit/d595c0cc))\n\n## [v1.7.0](https://github.com/Polymer/polymer/tree/v1.7.0) (2016-09-28)\n- Fix IE style cache performance ([commit](https://github.com/Polymer/polymer/commit/d08b694))\n\n- no need for :root to be first in the selector ([commit](https://github.com/Polymer/polymer/commit/63433c8))\n\n- fix tests on !chrome browsers ([commit](https://github.com/Polymer/polymer/commit/7ce981b))\n\n- Translate `:root` to `:host > *` for element styles ([commit](https://github.com/Polymer/polymer/commit/fea64b9))\n\n- Define checkRoot only once ([commit](https://github.com/Polymer/polymer/commit/a49b366))\n\n- Fix normalizeRootSelector ([commit](https://github.com/Polymer/polymer/commit/c2278a0))\n\n- Comment on using the ast walker to replace selector ([commit](https://github.com/Polymer/polymer/commit/9658665))\n\n- update travis config ([commit](https://github.com/Polymer/polymer/commit/c00687a))\n\n- Transform ::slotted() to ::content ([commit](https://github.com/Polymer/polymer/commit/541fdfb))\n\n- Test on native shadow DOM also. ([commit](https://github.com/Polymer/polymer/commit/11afc1f))\n\n- Reorder. ([commit](https://github.com/Polymer/polymer/commit/cbae058))\n\n- Remove unused. ([commit](https://github.com/Polymer/polymer/commit/92d1d8a))\n\n- Add fallback support/test. ([commit](https://github.com/Polymer/polymer/commit/037abdd))\n\n- A little more dry. ([commit](https://github.com/Polymer/polymer/commit/6fd0e1f))\n\n- Use name. ([commit](https://github.com/Polymer/polymer/commit/4aa8da2))\n\n- Support default slot semantics. ([commit](https://github.com/Polymer/polymer/commit/d458dd3))\n\n- Remove opt-in. Exclude content from copy. ([commit](https://github.com/Polymer/polymer/commit/41e5dc0))\n\n- Make sure click events can always trigger tap, even on touch only devices ([commit](https://github.com/Polymer/polymer/commit/02441ca))\n\n- Add support for slot->content transformation. Need to bikeshed opt-in attribute (currently \"auto-content\") ([commit](https://github.com/Polymer/polymer/commit/ebf31ca))\n\n- Support more expressive `:root` and `html` selectors ([commit](https://github.com/Polymer/polymer/commit/2a8f21a))\n\n- Fix typo ([commit](https://github.com/Polymer/polymer/commit/192eb56))\n\n- test for mixins in custom-style ordering ([commit](https://github.com/Polymer/polymer/commit/37646f7))\n\n- Do not insert semicolon when fixing var() syntax ([commit](https://github.com/Polymer/polymer/commit/0a338a7))\n\n- Make sure mixins are applied no matter the ordering of definition ([commit](https://github.com/Polymer/polymer/commit/9daea3d))\n\n- Update gulp-eslint to 3.x ([commit](https://github.com/Polymer/polymer/commit/8b89f02))\n\n- Fixes #3676: retain `<style>` in `<template preserve-content/>` ([commit](https://github.com/Polymer/polymer/commit/8a4c00c))\n\n- [ci skip] Update Changelog for v1.6.1 ([commit](https://github.com/Polymer/polymer/commit/ec04461))\n\n- Apply to _marshalArgs. ([commit](https://github.com/Polymer/polymer/commit/b2cd932))\n\n- Rename Path.head() to Path.root(). ([commit](https://github.com/Polymer/polymer/commit/77808d9))\n\n- Use head in templatizer ([commit](https://github.com/Polymer/polymer/commit/478978d))\n\n- Modify _annotationPathEffect ([commit](https://github.com/Polymer/polymer/commit/852aba0))\n\n- Use isDescendant ([commit](https://github.com/Polymer/polymer/commit/b9944fe))\n\n- Use isDeep ([commit](https://github.com/Polymer/polymer/commit/5627a55))\n\n- Replace _fixPath. ([commit](https://github.com/Polymer/polymer/commit/6d1dd88))\n\n- Replace _modelForPath. ([commit](https://github.com/Polymer/polymer/commit/b02eda0))\n\n- Replace _patchMatchesEffect. ([commit](https://github.com/Polymer/polymer/commit/6ad9295))\n\n- Add path library. ([commit](https://github.com/Polymer/polymer/commit/0320763))\n\n- Revert \"Fix _patchMatchesEffect. (#3631)\" ([commit](https://github.com/Polymer/polymer/commit/a64f227))\n\n## [v1.6.1](https://github.com/Polymer/polymer/tree/v1.6.1) (2016-08-01)\n- Property Shim needs to handle build output from apply shim ([commit](https://github.com/Polymer/polymer/commit/d726a51))\n\n- Do not resolve urls with leading slash and other protocols ([commit](https://github.com/Polymer/polymer/commit/94f95ec))\n\n- Mark that non-inheritable properties being set to `inherit` is not supported ([commit](https://github.com/Polymer/polymer/commit/0a2b31e))\n\n- Put `getInitialValueForProperty` on ApplyShim ([commit](https://github.com/Polymer/polymer/commit/0489ccf))\n\n- Skip `initial` and `inherit` on IE 10 and 11 ([commit](https://github.com/Polymer/polymer/commit/63c3bfb))\n\n- Handle mixins with property values of inherit and initial ([commit](https://github.com/Polymer/polymer/commit/c7571e5))\n\n- Split tests for use-before-create and reusing mixin names for variables ([commit](https://github.com/Polymer/polymer/commit/8de1bec))\n\n- Make sure we don't populate the mixin map for every variable ([commit](https://github.com/Polymer/polymer/commit/6265ade))\n\n- [apply shim] Track dependencies for mixins before creation ([commit](https://github.com/Polymer/polymer/commit/2cab461))\n\n- [property shim] Make sure \"initial\" and \"inherit\" behave as they would natively ([commit](https://github.com/Polymer/polymer/commit/0887dba))\n\n- fix lint issue. ([commit](https://github.com/Polymer/polymer/commit/95eadbd))\n\n- Fixes #3801. Ensure style host calculates custom properties before element. This ensures the scope's styles are prepared to be inspected by the element for matching rules. ([commit](https://github.com/Polymer/polymer/commit/5967f2d))\n\n- Clean up custom-style use of apply shim ([commit](https://github.com/Polymer/polymer/commit/0859803))\n\n- gate comparing css text on using native css properties ([commit](https://github.com/Polymer/polymer/commit/8fcb5f6))\n\n- Only invalidate mixin if it defines new properties ([commit](https://github.com/Polymer/polymer/commit/b27f842))\n\n- Make __currentElementProto optional for build tool ([commit](https://github.com/Polymer/polymer/commit/64d41e6))\n\n- Rerun Apply Shim when mixins with consumers are redefined ([commit](https://github.com/Polymer/polymer/commit/498e23f))\n\n- updateNativeStyles should only remove styles set by updateNativeStyles ([commit](https://github.com/Polymer/polymer/commit/831be4f))\n\n- [ci skip] add smoke test for scope caching with custom-style ([commit](https://github.com/Polymer/polymer/commit/43955ea))\n\n- Remove unused arg. ([commit](https://github.com/Polymer/polymer/commit/95cd415))\n\n- Remove dirty check for custom events; unnecessary after #3678. Fixes #3677. ([commit](https://github.com/Polymer/polymer/commit/92a9398))\n\n- Use _configValue to avoid setting readOnly. Add tests. ([commit](https://github.com/Polymer/polymer/commit/36467fa))\n\n- Missing piece to fixing #3094 ([commit](https://github.com/Polymer/polymer/commit/694b35e))\n\n- Opt in to \"even lazier\" behavior by setting `lazyRegister` to \"max\". This was done to preserve compatibility with the existing feature. Specifically, when \"max\" is used, setting `is` in `beforeRegister` and defining `factoryImpl` may only be done on an element's prototype and not its behaviors. In addition, the element's `beforeRegister` is called *before* its behaviors' `beforeRegisters` rather than *after* as in the normal case. ([commit](https://github.com/Polymer/polymer/commit/b271a88))\n\n- Replace 'iff' with 'if and only if' ([commit](https://github.com/Polymer/polymer/commit/f7659eb))\n\n- Fix test in IE10. ([commit](https://github.com/Polymer/polymer/commit/fb95dc8))\n\n- cleanup check for sourceCapabilities ([commit](https://github.com/Polymer/polymer/commit/4c44fb7))\n\n- Fix #3786 by adding a `noUrlSettings` flag to Polymer.Settings ([commit](https://github.com/Polymer/polymer/commit/8a26759))\n\n- Fix mouse input delay on systems with a touchscreen ([commit](https://github.com/Polymer/polymer/commit/ed4c18a))\n\n- Ensure properties override attributes at upgrade time. Fixes #3779. ([commit](https://github.com/Polymer/polymer/commit/f2938ec))\n\n- Refresh cache'd styles contents in IE 10 and 11 ([commit](https://github.com/Polymer/polymer/commit/80be0df))\n\n- change travis config ([commit](https://github.com/Polymer/polymer/commit/1256301))\n\n- Fix css shady build mistakenly matching root rules as host rules ([commit](https://github.com/Polymer/polymer/commit/5dfb9c9))\n\n- [ci skip] update changelog for v1.6.0 ([commit](https://github.com/Polymer/polymer/commit/d8bab9c))\n\n- Make lazyRegister have 'even lazier' behavior such that behaviors are not mixed in until first-instance time. ([commit](https://github.com/Polymer/polymer/commit/9676d6d))\n\n- need takeRecords in complex var example ([commit](https://github.com/Polymer/polymer/commit/b40561b))\n\n- add reduced test case ([commit](https://github.com/Polymer/polymer/commit/26fe9b9))\n\n- Replace VAR_MATCH regex with a simple state machine / callback ([commit](https://github.com/Polymer/polymer/commit/4ebec15))\n\n- Expose an `lazierRegister` flag to defer additional work until first create time. This change requires that a behavior not implement a custom constructor or set the element's `is` property. ([commit](https://github.com/Polymer/polymer/commit/5c5b18e))\n\n- Improve type signatures: `Polymer.Base.extend` and `Polymer.Base.mixin` ([commit](https://github.com/Polymer/polymer/commit/8382aa7))\n\n- Fix for changing property to the same value ([commit](https://github.com/Polymer/polymer/commit/66e6e22))\n\n- Include iron-component-page in devDependencies ([commit](https://github.com/Polymer/polymer/commit/639d5d8))\n\n- Ensure fromAbove in _forwardParentProp. ([commit](https://github.com/Polymer/polymer/commit/072dcff))\n\n## [v1.6.0](https://github.com/Polymer/polymer/tree/v1.6.0) (2016-06-29)\n- Fix test to account for pseudo element differences x-browser. ([commit](https://github.com/Polymer/polymer/commit/54a462d))\n\n- Restore functionality of selectors like `:host(.foo)::after`. ([commit](https://github.com/Polymer/polymer/commit/ff88e17))\n\n- add comment. ([commit](https://github.com/Polymer/polymer/commit/e770343))\n\n- re-support selectors like `:host[inline]` since this was previously supported under shady-dom. ([commit](https://github.com/Polymer/polymer/commit/4e51ef6))\n\n- fix linting ([commit](https://github.com/Polymer/polymer/commit/4817d61))\n\n- Add test for not matching `x-foox-bar` given `:host(x-bar)` used inside `x-foo` ([commit](https://github.com/Polymer/polymer/commit/4e08fa1))\n\n- fix test in IE/FF. ([commit](https://github.com/Polymer/polymer/commit/ec111f1))\n\n- simplify :host fixup ([commit](https://github.com/Polymer/polymer/commit/c3355fd))\n\n- Fixes #3739: correctly shim `:host(.element-name)` as `element-name.element-name`. ([commit](https://github.com/Polymer/polymer/commit/997240a))\n\n- Fixes #3734: address HI/CE timing issue in importHref. Fixes upgrade time dependencies of scripts on previous elements in async imports. ([commit](https://github.com/Polymer/polymer/commit/84662b9))\n\n- Ensure element scope selectors are updated correctly when updateStyles is called when element is not in dom. ([commit](https://github.com/Polymer/polymer/commit/6d90480))\n\n- add comment. ([commit](https://github.com/Polymer/polymer/commit/620e59f))\n\n- remove unneeded flag. ([commit](https://github.com/Polymer/polymer/commit/b5b8a2a))\n\n- Fixes #3730 and inspired by (https://github.com/Polymer/polymer/pull/3585) ([commit](https://github.com/Polymer/polymer/commit/ab431ed))\n\n- custom-style triggers updateStyles if root scope (StyleDefaults) has style properties when the custom-style is created. ([commit](https://github.com/Polymer/polymer/commit/4852f6c))\n\n- Fix _patchMatchesEffect. (#3631) ([commit](https://github.com/Polymer/polymer/commit/b78e5af))\n\n- Fixes #3555. Ensure selectors including `::content` without a prefix … (#3721) ([commit](https://github.com/Polymer/polymer/commit/1058896))\n\n- Fixes #3530. When `updateStyles` is called and an element is not attached, invalidate its styling so that when it is attached, its custom properties will be updated. ([commit](https://github.com/Polymer/polymer/commit/ae4a07e))\n\n- Make sure effect functions receive latest values ([commit](https://github.com/Polymer/polymer/commit/34b2c79))\n\n- [ci skip] data binding edge case smoke test ([commit](https://github.com/Polymer/polymer/commit/a54c1f2))\n\n- Use `whenReady` to apply custom styles. ([commit](https://github.com/Polymer/polymer/commit/129488b))\n\n- Use firefox 46 for testing ([commit](https://github.com/Polymer/polymer/commit/fbe5b0f))\n\n- Need to wait until render to test. ([commit](https://github.com/Polymer/polymer/commit/92293f9))\n\n- address feedback ([commit](https://github.com/Polymer/polymer/commit/4dc780a))\n\n- Fix lint, use query params instead of duplicate file. ([commit](https://github.com/Polymer/polymer/commit/e4880d9))\n\n- Ensure custom styles updated after adding custom-style async. Fixes #3705. ([commit](https://github.com/Polymer/polymer/commit/f770438))\n\n- Store cacheablility on the scope ([commit](https://github.com/Polymer/polymer/commit/bc9519e))\n\n- fix decorateStyles with custom-style ([commit](https://github.com/Polymer/polymer/commit/57a6769))\n\n- Do not scope cache elements with media rules, :host(), or :host-context() selectors ([commit](https://github.com/Polymer/polymer/commit/5c3b917))\n\n- Support preventDefault() on touch (#3693) ([commit](https://github.com/Polymer/polymer/commit/b9c874e))\n\n- Shim CSS Mixins in terms of CSS Custom Properties (#3587) ([commit](https://github.com/Polymer/polymer/commit/6c0acef))\n\n- [ci skip] update changelog ([commit](https://github.com/Polymer/polymer/commit/adef722))\n\n## [v1.5.0](https://github.com/Polymer/polymer/tree/v1.5.0) (2016-05-31)\n- Fix test in Firefox that was hacked to work in Canary (instead filed https://bugs.chromium.org/p/chromium/issues/detail?id=614198). ([commit](https://github.com/Polymer/polymer/commit/1e2aed5))\n\n- remove unneeded argument ([commit](https://github.com/Polymer/polymer/commit/4a99b83))\n\n- slight optimization, avoid work if no cssText is set. ([commit](https://github.com/Polymer/polymer/commit/ce0bf86))\n\n- More efficient fix for #3661. Re-uses cached style element that needs to be replaced in the document rather than creating a new one. ([commit](https://github.com/Polymer/polymer/commit/63f91ae))\n\n- Fixes #3661: ensure that cached style points to the applied style for Shady DOM styling. This ensures that the cache can be used to determine if a style needs to be applied to the document and prevents extra unnecessary styles from being added. This could happen when a property cascaded to a nested element and updateStyles was called after properties have changed. ([commit](https://github.com/Polymer/polymer/commit/717fc3a))\n\n- Fix flakey attached/detached timing test. ([commit](https://github.com/Polymer/polymer/commit/04da868))\n\n- remove HTML comment ([commit](https://github.com/Polymer/polymer/commit/d339b28))\n\n- add more style[include] doc ([commit](https://github.com/Polymer/polymer/commit/b8fd12d))\n\n- Update the package.json name to match the actual npm published package. (#3570) ([commit](https://github.com/Polymer/polymer/commit/e57eb49))\n\n- Remove unused event cache store (#3591) ([commit](https://github.com/Polymer/polymer/commit/364ede9))\n\n- [ci skip] sudo should be \"required\" ([commit](https://github.com/Polymer/polymer/commit/c0e0a73))\n\n- transition to travis trusty images ([commit](https://github.com/Polymer/polymer/commit/b7c0b1f))\n\n- fine, console.dir then ([commit](https://github.com/Polymer/polymer/commit/c8cb3be))\n\n- fix ie missing console.table for stubbing ([commit](https://github.com/Polymer/polymer/commit/6d39644))\n\n- Support the devtools console.log api (multiple strings) for polymer logging ([commit](https://github.com/Polymer/polymer/commit/909ee82))\n\n- Compute and use correct annotation value during config ([commit](https://github.com/Polymer/polymer/commit/1b02e96))\n\n- Set propertyName on parent props for config phase. ([commit](https://github.com/Polymer/polymer/commit/d9c03a4))\n\n- Refactorings around how computational expressions get their arguments ([commit](https://github.com/Polymer/polymer/commit/677f10c))\n\n- Fix safari 7 again ([commit](https://github.com/Polymer/polymer/commit/b30f962))\n\n- Expose public API to reset mouse cancelling for testing touch ([commit](https://github.com/Polymer/polymer/commit/18bf9d4))\n\n- Delay detached callback with the same strategy as attached callback ([commit](https://github.com/Polymer/polymer/commit/7a244fa))\n\n- [ci skip] Add missing dom5 devDependency ([commit](https://github.com/Polymer/polymer/commit/5e2050a))\n\n- Don't use `translate` as a method for testing ([commit](https://github.com/Polymer/polymer/commit/f80346f))\n\n- Only fix prototype when registering at first create time. ([commit](https://github.com/Polymer/polymer/commit/7ad2bff))\n\n- Fixes #3525: Makes lazy registration compatible with platforms (like IE10) on which a custom element's prototype must be simulated. ([commit](https://github.com/Polymer/polymer/commit/4834651))\n\n- make sure gulp-cli 1 is used ([commit](https://github.com/Polymer/polymer/commit/29067ca))\n\n- Ensure Annotator recognizes dynamic fn as dependency for parent props. ([commit](https://github.com/Polymer/polymer/commit/15ff463))\n\n- [ci skip] Update CHANGELOG ([commit](https://github.com/Polymer/polymer/commit/223aa34))\n\n- Enabling caching of node_modules on Travis ([commit](https://github.com/Polymer/polymer/commit/6b6ec5d))\n\n- Fix undefined class attribute in undefined template scope ([commit](https://github.com/Polymer/polymer/commit/e21c59e))\n\n- Use a parser based html minification ([commit](https://github.com/Polymer/polymer/commit/0536e35))\n\n- Call _notifyPath instead of notifyPath in templatizer ([commit](https://github.com/Polymer/polymer/commit/067b7ed))\n\n- Keep it real for notifyPath. ([commit](https://github.com/Polymer/polymer/commit/40a1f79))\n\n- Null debounced callback to set for GC. ([commit](https://github.com/Polymer/polymer/commit/f366c1c))\n\n## [v1.4.0](https://github.com/Polymer/polymer/tree/v1.4.0) (2016-03-18)\n- Fast check in createdCallback to see if registration has finished. ([commit](https://github.com/Polymer/polymer/commit/a3fce19))\n\n- even more lazy: defer template lookup and style collection until finish register time. ([commit](https://github.com/Polymer/polymer/commit/103f790))\n\n- fix lint errors. ([commit](https://github.com/Polymer/polymer/commit/d7a2baa))\n\n- * turn on lazy registration via `Polymer.Settings.lazyRegister` * ensure registration finished by calling `Element.prototype.ensureRegisterFinished()` ([commit](https://github.com/Polymer/polymer/commit/31c785d))\n\n- remove crufty smoke test. ([commit](https://github.com/Polymer/polymer/commit/3dd1b61))\n\n- fix lint issues ([commit](https://github.com/Polymer/polymer/commit/0447228))\n\n- Change `forceRegister` to `eagerRegister` and add `Polymer.Settings.eagerRegister` flag. ([commit](https://github.com/Polymer/polymer/commit/f6597ec))\n\n- Add `forceRegister` flag to force an element to fully register when `Polymer` is called. Normally, some work is deferred until the first element instance is created. ([commit](https://github.com/Polymer/polymer/commit/d53323d))\n\n- Call registered no prototype. ([commit](https://github.com/Polymer/polymer/commit/812db6a))\n\n- Lazy register features we can be deferred until first instance. This is an optimization which can speed up page load time when elements are registered but not needed at time of first paint/interaction ([commit](https://github.com/Polymer/polymer/commit/31702ff))\n\n- Do not reflect uppercase properties ([commit](https://github.com/Polymer/polymer/commit/72d35e0))\n\n- Make sure event.path is an array ([commit](https://github.com/Polymer/polymer/commit/2dfdd7b))\n\n- fix testing failures on assert.notInclude of null ([commit](https://github.com/Polymer/polymer/commit/8066919))\n\n- [ci skip] update changelog ([commit](https://github.com/Polymer/polymer/commit/58e6713))\n\n## [v1.3.1](https://github.com/Polymer/polymer/tree/v1.3.1) (2016-03-02)\n- Fix lint errors. ([commit](https://github.com/Polymer/polymer/commit/44d06f1))\n\n- Add test. ([commit](https://github.com/Polymer/polymer/commit/02660c1))\n\n- Fix lint error. ([commit](https://github.com/Polymer/polymer/commit/e2c5f9e))\n\n- Ensure that dom-bind always waits until DOMContentLoaded to render. This ensures a script can install api on the dom-bind prior to it rendering. Previously dom-bind waited for first render, but an early parser yield can make this occur unexpectedly early. ([commit](https://github.com/Polymer/polymer/commit/cc0e9df))\n\n- Refine fix for #3461 so that the decision to apply a static or property stylesheet relies on the same info. ([commit](https://github.com/Polymer/polymer/commit/ff96f9e))\n\n- Clean the .eslintignore ([commit](https://github.com/Polymer/polymer/commit/04d06a5))\n\n- [ci skip] Add header for those asking questions ([commit](https://github.com/Polymer/polymer/commit/9d6111c))\n\n- Fixes #3461: Only avoid creating a statically scoped stylesheet when properties are consumed in an element, properly excluding properties produced as a result of consumption. ([commit](https://github.com/Polymer/polymer/commit/e26a806))\n\n- tweaks to new README ([commit](https://github.com/Polymer/polymer/commit/809352d))\n\n- [ci skip] Update Changelog ([commit](https://github.com/Polymer/polymer/commit/4f3f463))\n\n- Updated the README.md for a non-technical user to understand ([commit](https://github.com/Polymer/polymer/commit/0729cef))\n\n## [v1.3.0](https://github.com/Polymer/polymer/tree/v1.3.0) (2016-02-22)\n- [ci skip] Add instructions to pull request template ([commit](https://github.com/Polymer/polymer/commit/933c920))\n\n- [ci skip] markdown fail ([commit](https://github.com/Polymer/polymer/commit/a8e01e2))\n\n- [ci skip] Add instructions to issue template ([commit](https://github.com/Polymer/polymer/commit/ace0f72))\n\n- Make sure to configure properties on polymer elements that do not have property effects. ([commit](https://github.com/Polymer/polymer/commit/f93c3e5))\n\n- Fix lint errors. ([commit](https://github.com/Polymer/polymer/commit/5ac5ee7))\n\n- Add comment. Ensure Date deserializes to String for correctness. ([commit](https://github.com/Polymer/polymer/commit/69c7087))\n\n- Serialize before deserialize when configuring attrs. Fixes #3433. ([commit](https://github.com/Polymer/polymer/commit/ec85582))\n\n- Restrict early property set to properties that have accessors. This allows users to set properties in `created` which are listed in `properties` but which have no accessor. ([commit](https://github.com/Polymer/polymer/commit/4cfb245))\n\n- fix crlf once and for all ([commit](https://github.com/Polymer/polymer/commit/6c5afe5))\n\n- fix test linting from #3350 ([commit](https://github.com/Polymer/polymer/commit/37f7157))\n\n- Use the new .github folder for issue and pull request templates ([commit](https://github.com/Polymer/polymer/commit/58529c2))\n\n- [ci skip] Use https for jsbin ([commit](https://github.com/Polymer/polymer/commit/3e33fd4))\n\n- [ci skip] Add issue and pr template ([commit](https://github.com/Polymer/polymer/commit/cc1ef9a))\n\n- Update to gulp-eslint v2 ([commit](https://github.com/Polymer/polymer/commit/dca0dda))\n\n- fix lint errors ([commit](https://github.com/Polymer/polymer/commit/7da9a38))\n\n- Minor fixes based on review. ([commit](https://github.com/Polymer/polymer/commit/f2c1d4a))\n\n- Undo fix on IE10 where the custom elements polyfill's mixin strategy makes this unfeasible. ([commit](https://github.com/Polymer/polymer/commit/ef629f4))\n\n- Update comments. ([commit](https://github.com/Polymer/polymer/commit/b870fe0))\n\n- Add test that late resolved functions don't warn ([commit](https://github.com/Polymer/polymer/commit/0037c53))\n\n- Add support for properties defined in a behavior. ([commit](https://github.com/Polymer/polymer/commit/b6abf26))\n\n- Generalized approach supporting compute and observers ([commit](https://github.com/Polymer/polymer/commit/f4486a2))\n\n- Proper implementation ([commit](https://github.com/Polymer/polymer/commit/3c12178))\n\n- Support dynamic functions for computed annotations. ([commit](https://github.com/Polymer/polymer/commit/3f1bc4e))\n\n- ordering issue for when assert is defined in native html imports ([commit](https://github.com/Polymer/polymer/commit/d81f6bc))\n\n- Lint the tests ([commit](https://github.com/Polymer/polymer/commit/e5063ca))\n\n- Add support for one-of attribute selector while not breaking support for general sibling combinator. Fixes #3023. Fix taken from #3067. ([commit](https://github.com/Polymer/polymer/commit/5a493d8))\n\n- Fix bindings with special characters ([commit](https://github.com/Polymer/polymer/commit/d385873))\n\n- [ci skip] move linting into before_script stage ([commit](https://github.com/Polymer/polymer/commit/1b5fc9a))\n\n- Fix lint error and uncomment test. ([commit](https://github.com/Polymer/polymer/commit/c00c47f))\n\n- Add test for overriding property based :host selector from outside. ([commit](https://github.com/Polymer/polymer/commit/71c41ed))\n\n- Add comment and fix typo ([commit](https://github.com/Polymer/polymer/commit/b0e16f0))\n\n- Ensure _propertySetter is installed first. Fixes #3063 ([commit](https://github.com/Polymer/polymer/commit/6362f60))\n\n- Disable tap gesture when track gesture is firing for ancestor node ([commit](https://github.com/Polymer/polymer/commit/6f2c1fc))\n\n- Fix parsing of parenthesis in default of variable declaration ([commit](https://github.com/Polymer/polymer/commit/926d0e5))\n\n- Rename _mapRule to _mapRuleOntoParent ([commit](https://github.com/Polymer/polymer/commit/cd42595))\n\n- Test with ESLint enabled ([commit](https://github.com/Polymer/polymer/commit/acdfc1e))\n\n- Make behaviors array unique ([commit](https://github.com/Polymer/polymer/commit/4cde38a))\n\n- Use deserialize from the node. ([commit](https://github.com/Polymer/polymer/commit/a3641e2))\n\n- Actually execute case-map ([commit](https://github.com/Polymer/polymer/commit/d84d75b))\n\n- [ci skip] .eslintrc is deprecated, add .json suffix ([commit](https://github.com/Polymer/polymer/commit/c7554d9))\n\n- Make the test more look like a spec ([commit](https://github.com/Polymer/polymer/commit/db7c324))\n\n- Configure attr's with property effects. More robust fix for #3288. ([commit](https://github.com/Polymer/polymer/commit/0f55d1d))\n\n- Use ESLint for Polymer ([commit](https://github.com/Polymer/polymer/commit/f3c4bb1))\n\n- Add test suite for effects order ([commit](https://github.com/Polymer/polymer/commit/56df8f7))\n\n- Fix negation when a negated binding is changed ([commit](https://github.com/Polymer/polymer/commit/21383a3))\n\n- Add unit test suite for CaseMap ([commit](https://github.com/Polymer/polymer/commit/ee9a600))\n\n- Fixes for IE style ordering issue. ([commit](https://github.com/Polymer/polymer/commit/162f81e))\n\n- Fixes #3326. Changes inspired by #3276 and #3344 ([commit](https://github.com/Polymer/polymer/commit/b5ba9a8))\n\n- Fix for getters/setters for property become inaccessible when property set on element before it is ready ([commit](https://github.com/Polymer/polymer/commit/ecd9b09))\n\n- Non-destructive `@keyframes` rule transformation. ([commit](https://github.com/Polymer/polymer/commit/b9f2482))\n\n- Fix test regression from PR 3289 ([commit](https://github.com/Polymer/polymer/commit/5205d6a))\n\n- Move test and add to runner. ([commit](https://github.com/Polymer/polymer/commit/aeb44de))\n\n- make isDebouncerActive actually return a bool ([commit](https://github.com/Polymer/polymer/commit/dee9b98))\n\n- Lint the javascript code with eslint ([commit](https://github.com/Polymer/polymer/commit/f7d2bdf))\n\n- i suck at git ([commit](https://github.com/Polymer/polymer/commit/b40f639))\n\n- Fix for scoping when class is not specified on element (null was prepended instead of empty string) ([commit](https://github.com/Polymer/polymer/commit/24e9fc7))\n\n- Using constant rather than plain `:host` and `::content`, also create regexp object only once ([commit](https://github.com/Polymer/polymer/commit/c6c28f5))\n\n- Eliminate the need to write `:host ::content` instead of just `::content`, while keeping the same processing under the hood ([commit](https://github.com/Polymer/polymer/commit/d9f3dda))\n\n- Fix: There is no effect of kind 'computedAnnotation' ([commit](https://github.com/Polymer/polymer/commit/06cd560))\n\n- fix test case in 5d17efc ([commit](https://github.com/Polymer/polymer/commit/4a9ef8e))\n\n- add test for 3326 ([commit](https://github.com/Polymer/polymer/commit/854fdbf))\n\n- [ci skip] update CHANGELOG ([commit](https://github.com/Polymer/polymer/commit/3d2cb71))\n\n- Exclude attribute bindings from configuration. Fixes #3288. ([commit](https://github.com/Polymer/polymer/commit/246ea72))\n\n- Doubled `Polymer.CaseMap.dashToCamelCase` performance with simplified and once compiled RegExp. 5 times faster `Polymer.CaseMap.camelToDashCase` using simplified replace part, simplified and once compiled RegExp. ([commit](https://github.com/Polymer/polymer/commit/90938e3))\n\n- Update PRIMER.md ([commit](https://github.com/Polymer/polymer/commit/bb4d558))\n\n- Unit tests ([commit](https://github.com/Polymer/polymer/commit/de371bb))\n\n- Allow newlines in computed binding argument list ([commit](https://github.com/Polymer/polymer/commit/b745f45))\n\n- Remove redundant assign to window.Polymer ([commit](https://github.com/Polymer/polymer/commit/b2f8e8f))\n\n- parentProps should not override argument based props ([commit](https://github.com/Polymer/polymer/commit/898fe89))\n\n## [v1.2.4](https://github.com/Polymer/polymer/tree/v1.2.4) (2016-01-27)\n- Fixes #3337. When a doc fragment is added, only update the invalidation state of the insertion point list of the shadyRoot IFF it is not already invalid. This fixes an issue that was detected when an a doc fragment that did not include an insertion point was added after one that did but before distribution. ([commit](https://github.com/Polymer/polymer/commit/d26b003))\n\n- fix build output with new vulcanize ([commit](https://github.com/Polymer/polymer/commit/c317711))\n\n- Revert style properties change from fd5778470551f677c2aa5827398681abb1994a88 ([commit](https://github.com/Polymer/polymer/commit/0a0b580))\n\n- Fix shadow dom test. ([commit](https://github.com/Polymer/polymer/commit/6b83911))\n\n- Add shadow root support. (tests broken) ([commit](https://github.com/Polymer/polymer/commit/4b7da35))\n\n- Ensure dom-if moved into doc fragment is torn down. Fixes #3324 ([commit](https://github.com/Polymer/polymer/commit/6c4f5d5))\n\n- improve test. ([commit](https://github.com/Polymer/polymer/commit/d70c40a))\n\n- Update comment. ([commit](https://github.com/Polymer/polymer/commit/aa14687))\n\n- In addition to fragments, also handle non-distributed elements more completely. ([commit](https://github.com/Polymer/polymer/commit/fe2699e))\n\n- Simplify fix for fragment children management. ([commit](https://github.com/Polymer/polymer/commit/713377e))\n\n- Fix test under polyfill. ([commit](https://github.com/Polymer/polymer/commit/25da63d))\n\n- Ensure fragments added via Polymer.dom always have elements removed, even when distribution does not select those elements. ([commit](https://github.com/Polymer/polymer/commit/101eb3d))\n\n- Fixes #3321. Only let dom-repeat insert elements in attached if it has been previously detached; correctly avoid re-adding children in document fragments to an element's logical linked list if they are already there. ([commit](https://github.com/Polymer/polymer/commit/9f2464d))\n\n- Ugh ([commit](https://github.com/Polymer/polymer/commit/172d93c))\n\n- Fixes #3308. Use an explicit undefined check to test if logical tree information exists. ([commit](https://github.com/Polymer/polymer/commit/9106398))\n\n- add test ([commit](https://github.com/Polymer/polymer/commit/b1ea014))\n\n- use class attribute in applyElementScopeSelector ([commit](https://github.com/Polymer/polymer/commit/07d8c06))\n\n- Remove reference to _composedChildren ([commit](https://github.com/Polymer/polymer/commit/9f85acd))\n\n- Fix typo in documentation for set() ([commit](https://github.com/Polymer/polymer/commit/aa47515))\n\n- Fix typo in dom-tree-api ([commit](https://github.com/Polymer/polymer/commit/ae98a7c))\n\n- Correct use of document.contains to document.documentElement.contains on IE. ([commit](https://github.com/Polymer/polymer/commit/0e74810))\n\n- Ensure querySelector always returns `null` when a node is not found. Also optimize querySelector such that the matcher halts on the first result. ([commit](https://github.com/Polymer/polymer/commit/b9e5cce))\n\n- Fixes #3295. Only cache a false-y result for an element's owner shady root iff the element is currently in the document. ([commit](https://github.com/Polymer/polymer/commit/6e16619))\n\n- Use local references to wrapper functions; add test element tree to native shadow tests; reorder test elements. ([commit](https://github.com/Polymer/polymer/commit/47ee2ca))\n\n- Remove leftover garbage line ([commit](https://github.com/Polymer/polymer/commit/d7567b7))\n\n- Removes the case where activeElement could be in the light DOM of a ShadowRoot. ([commit](https://github.com/Polymer/polymer/commit/e848af8))\n\n- DOM API implementation of `activeElement`. ([commit](https://github.com/Polymer/polymer/commit/2984576))\n\n- Remove call to `wrap` in deepContains ([commit](https://github.com/Polymer/polymer/commit/4cbdef7))\n\n- Fixes #3270. ([commit](https://github.com/Polymer/polymer/commit/7d0485b))\n\n- Include more styling tests under ShadowDOM. Fix custom-style media query test to work under both shadow/shady. ([commit](https://github.com/Polymer/polymer/commit/33a24bb))\n\n- Remove duplicate code related to dom traversal in Polymer.dom. ([commit](https://github.com/Polymer/polymer/commit/555252b))\n\n- Fix parsing of minimized css output also for mixins ([commit](https://github.com/Polymer/polymer/commit/87d02e0))\n\n- Set position to relative to make Safari to succeed top/bottom tests ([commit](https://github.com/Polymer/polymer/commit/94f505a))\n\n- Fix parsing of minimized css output ([commit](https://github.com/Polymer/polymer/commit/f92f9ff))\n\n- Fix for `Polymer.dom(...)._query()` method doesn't exist which causes `Polymer.updateStyles()` to fail ([commit](https://github.com/Polymer/polymer/commit/0eea7a6))\n\n- Minor factoring of dom patching. ([commit](https://github.com/Polymer/polymer/commit/8c95014))\n\n- use destination insertion points when calculating the path ([commit](https://github.com/Polymer/polymer/commit/3f8b6ee))\n\n- Store all dom tree data in `__dom` private storage; implement composed patching via a linked list. ([commit](https://github.com/Polymer/polymer/commit/9a3bead))\n\n- Modernize the build ([commit](https://github.com/Polymer/polymer/commit/2b69bb1))\n\n- Add more globals to whitelist for safari ([commit](https://github.com/Polymer/polymer/commit/82b2443))\n\n- Shady patching: patch element accessors in composed tree; fixes HTMLImports polyfill support. ([commit](https://github.com/Polymer/polymer/commit/d135fef))\n\n- remove unused code; minor changes based on review. ([commit](https://github.com/Polymer/polymer/commit/c3fbd10))\n\n- added polymer-mini and polymer-micro to main ([commit](https://github.com/Polymer/polymer/commit/da5d781))\n\n- Updates the patch-don experiment to work with recent changes. ([commit](https://github.com/Polymer/polymer/commit/b9e6859))\n\n- Fixes #3113 ([commit](https://github.com/Polymer/polymer/commit/fadd455))\n\n- Polymer.dom: when adding a node, only remove the node from its existing location if it's not a fragment and has a parent. ([commit](https://github.com/Polymer/polymer/commit/9915627))\n\n- Consistently use TreeApi.Composed api for composed dom manipulation; use TreeApi.Logical methods to get node leaves. Avoid making a Polymer.dom when TreeApi.Logical can provide the needed info. ([commit](https://github.com/Polymer/polymer/commit/5033fdb))\n\n- Produce nicer error on malformed observer ([commit](https://github.com/Polymer/polymer/commit/0e248f5))\n\n- Deduplicate setup and verifying in notify-path test suite ([commit](https://github.com/Polymer/polymer/commit/68707ad))\n\n- more explicit tests for debouncer wait and no-wait behavior ([commit](https://github.com/Polymer/polymer/commit/8ef7bac))\n\n- speed up microtask testing ([commit](https://github.com/Polymer/polymer/commit/9bef4c0))\n\n- ensure isDebouncerActive returns a Boolean ([commit](https://github.com/Polymer/polymer/commit/3916493))\n\n- add more debouncer tests ([commit](https://github.com/Polymer/polymer/commit/0206852))\n\n- remove dead debounce test assertion ([commit](https://github.com/Polymer/polymer/commit/9b898c2))\n\n- Factoring of distribution logic in both add and remove cases. ([commit](https://github.com/Polymer/polymer/commit/8272d5e))\n\n- Minor typo in docs: call the debounce callback ([commit](https://github.com/Polymer/polymer/commit/02c5c79))\n\n- Correct test to avoid using `firstElementChild` on a documentFragment since it is not universally supported. ([commit](https://github.com/Polymer/polymer/commit/dfa6a44))\n\n- Remove all TODOs ([commit](https://github.com/Polymer/polymer/commit/6467ae1))\n\n- Revert \"Add .gitattributes to solve line endings cross-OS (merge after other PRs)\" ([commit](https://github.com/Polymer/polymer/commit/b6b8293))\n\n- Make renderedItemCount readOnly & add tests. ([commit](https://github.com/Polymer/polymer/commit/e39d5ba))\n\n- Revert \"Fix parsing of minimized css output\" ([commit](https://github.com/Polymer/polymer/commit/d3145e8))\n\n- Custom setProperty for bindings to hidden textNodes. Fixes #3157. ([commit](https://github.com/Polymer/polymer/commit/c6be10d))\n\n- Ensure dom-if in host does not restamp when host detaches. Fixes #3125. ([commit](https://github.com/Polymer/polymer/commit/bb85e2b))\n\n- Avoid making a copy of childNodes when a dom fragment is inserted in the logical tree. ([commit](https://github.com/Polymer/polymer/commit/dcbafbf))\n\n- Slightly faster `findAnnotatedNodes` ([commit](https://github.com/Polymer/polymer/commit/43fc853))\n\n- Add .gitattributes to solve line endings cross-OS ([commit](https://github.com/Polymer/polymer/commit/94c2bc2))\n\n- Ensure literals are excluded from parent props. Fixes #3128. Fixes #3121. ([commit](https://github.com/Polymer/polymer/commit/526fa3c))\n\n- Fix parsing of minimized css output ([commit](https://github.com/Polymer/polymer/commit/d458690))\n\n- Disable chunked dom-repeat tests on IE due to CI rAF flakiness. ([commit](https://github.com/Polymer/polymer/commit/7fe5e2b))\n\n- Add comment. ([commit](https://github.com/Polymer/polymer/commit/d8ecd45))\n\n- Make Polymer.dom.flush reentrant-safe. Fixes #3115. ([commit](https://github.com/Polymer/polymer/commit/644105a))\n\n- Fixes #3108. Moves `debounce` functionality from polymer-micro to polymer-mini. The functionality belongs at the mini tier and was never actually functional in micro. ([commit](https://github.com/Polymer/polymer/commit/3df4ef2))\n\n- Clarify this is for IE. ([commit](https://github.com/Polymer/polymer/commit/63782fa))\n\n- Patch rAF to setTimeout to reduce flakiness on CI. ([commit](https://github.com/Polymer/polymer/commit/35abadc))\n\n- added missing semicolons, removed some unused variables ([commit](https://github.com/Polymer/polymer/commit/00ed797))\n\n- ?Node ([commit](https://github.com/Polymer/polymer/commit/9385891))\n\n- Remove closures holding element references after mouseup/touchend ([commit](https://github.com/Polymer/polymer/commit/811f766))\n\n- set class attribute instead of using classname ([commit](https://github.com/Polymer/polymer/commit/690838a))\n\n- Include wildcard character in identifier. Fixes #3084. ([commit](https://github.com/Polymer/polymer/commit/c36d6c1))\n\n- Revert fromAbove in applyEffectValue. Add test. Fixes #3077. ([commit](https://github.com/Polymer/polymer/commit/156122c))\n\n- loosen isLightDescendant's @param type to Node ([commit](https://github.com/Polymer/polymer/commit/c635797))\n\n- Put beforeRegister in the behaviorProperties. ([commit](https://github.com/Polymer/polymer/commit/445b6cd))\n\n- ES5 strict doesn't like function declarations inside inner blocks. ([commit](https://github.com/Polymer/polymer/commit/51d3fa6))\n\n- Fixes #3065: Add dom-repeat.renderedItemCount property ([commit](https://github.com/Polymer/polymer/commit/b589f70))\n\n- Minor factoring; ensure base properties set on instance. ([commit](https://github.com/Polymer/polymer/commit/da15ff0))\n\n- Fix typos. ([commit](https://github.com/Polymer/polymer/commit/c12d3ed))\n\n- Simplify more. ([commit](https://github.com/Polymer/polymer/commit/186e053))\n\n- Improvements to regex. ([commit](https://github.com/Polymer/polymer/commit/a3d17d5))\n\n- Give dom-repeat#_targetFrameTime a type ([commit](https://github.com/Polymer/polymer/commit/adad9ce))\n\n- [skip ci] update travis config to firefox latest ([commit](https://github.com/Polymer/polymer/commit/608ce9f))\n\n- Add a couple of tests. ([commit](https://github.com/Polymer/polymer/commit/108b7f9))\n\n- Suppress warnings and expected errors in test suite ([commit](https://github.com/Polymer/polymer/commit/92d6fcb))\n\n- Use linked-list for element tree traversal. Factor Polymer.DomApi into shadow/shady modules. ([commit](https://github.com/Polymer/polymer/commit/306cc81))\n\n- Avoid throwing with invalid keys/paths. Fixes #3018. ([commit](https://github.com/Polymer/polymer/commit/5076ee0))\n\n- Use stricter binding parsing for efficiency and correctness.  Fixes #2705. ([commit](https://github.com/Polymer/polymer/commit/04cd184))\n\n- Simpler travis config ([commit](https://github.com/Polymer/polymer/commit/68b457d))\n\n- [ci skip] Update Changelog ([commit](https://github.com/Polymer/polymer/commit/7e7600a))\n\n- Fix for incorrect CSS selectors specificity as reported in #2531 Fix for overriding mixin properties, fixes #1873 Added awareness from `@apply()` position among other rules so that it is preserved after CSS variables/mixing substitution. `Polymer.StyleUtil.clearStyleRules()` method removed as it is not used anywhere. Some unused variables removed. Typos, unused variables and unnecessary escaping in regexps corrected. Tests added. ([commit](https://github.com/Polymer/polymer/commit/fd57784))\n\n- Fix for method parsing in computed binding ([commit](https://github.com/Polymer/polymer/commit/c2e43d3))\n\n- Fix doc typo. ([commit](https://github.com/Polymer/polymer/commit/8886c2c))\n\n- Filtering causes unexpected issues ([commit](https://github.com/Polymer/polymer/commit/df22564))\n\n- Fix using value$ on input element ([commit](https://github.com/Polymer/polymer/commit/05a1e95))\n\n- added missing semicolons, removed some unused variables ([commit](https://github.com/Polymer/polymer/commit/338574d))\n\n## [v1.2.3](https://github.com/Polymer/polymer/tree/v1.2.3) (2015-11-16)\n- Call decorate instead of bootstrap for template prepping ([commit](https://github.com/Polymer/polymer/commit/e2a2cfd))\n\n- Fix global leak test. Necessary due to changes to test harness. ([commit](https://github.com/Polymer/polymer/commit/134766f))\n\n- Defer property application only when a custom-style is first created. ([commit](https://github.com/Polymer/polymer/commit/4bf0e13))\n\n- Update comment. ([commit](https://github.com/Polymer/polymer/commit/27e1dcd))\n\n- Simplify custom-style property deferment. ([commit](https://github.com/Polymer/polymer/commit/a970493))\n\n- [ci skip] update changelog ([commit](https://github.com/Polymer/polymer/commit/98acb3a))\n\n- Fixes #2692. Ensures that custom-style properties are applied async but before next render so that all properties are defined before any are consumed by custom-styles. Also refines dom-module's early upgrade code so that it does not affect other elements (corrects for example, custom-styles upgrading before expected). ([commit](https://github.com/Polymer/polymer/commit/b829f2a))\n\n- Remove undesired full-stop from outputs ([commit](https://github.com/Polymer/polymer/commit/68d5c55))\n\n- Fix Formatting ([commit](https://github.com/Polymer/polymer/commit/724e1bc))\n\n## [v1.2.2](https://github.com/Polymer/polymer/tree/v1.2.2) (2015-11-12)\n- use local reference for wrap. ([commit](https://github.com/Polymer/polymer/commit/b15e5b9))\n\n- Add Polymer.DomApi.wrap ([commit](https://github.com/Polymer/polymer/commit/6cf974a))\n\n- For correctness, bind listeners must use a property's current value rather than its passed value. ([commit](https://github.com/Polymer/polymer/commit/aca404f))\n\n- Explicitly making an element's `_template` falsy is now considered an allowable setting. This means the element stamps no content, doesn't collect any styles, and avoids looking up a dom-module. This helps address #2708 and the 5 elements Polymer registers that have no template have been set with `_template: null`. ([commit](https://github.com/Polymer/polymer/commit/b905a37))\n\n- Make test work under native Shadow DOM. ([commit](https://github.com/Polymer/polymer/commit/4f9c2bd))\n\n- In `_notifyListener`, only use `e.detail` if the event has a detail. This is necessary for `::eventName` compatibility where `eventName` is a native event like `change`. ([commit](https://github.com/Polymer/polymer/commit/3ece552))\n\n- Fix TOC re: host event listeners. ([commit](https://github.com/Polymer/polymer/commit/ce32459))\n\n- Fix compound bindings with braces in literals ([commit](https://github.com/Polymer/polymer/commit/561b28b))\n\n- Re-enable listeners of the form 'a.b' (todo: make this more efficient). ([commit](https://github.com/Polymer/polymer/commit/139257b))\n\n- Avoid stomping on property objects when mixing behaviors. ([commit](https://github.com/Polymer/polymer/commit/ec4d313))\n\n- Update test to avoid template polyfill issues. ([commit](https://github.com/Polymer/polymer/commit/fa96ff3))\n\n- Ensure parent node exists when stamping. Fixes #2685. ([commit](https://github.com/Polymer/polymer/commit/62f2d2a))\n\n- Add global leak test to runner. ([commit](https://github.com/Polymer/polymer/commit/dc2255c))\n\n- Add global leak test. ([commit](https://github.com/Polymer/polymer/commit/7f71b4c))\n\n- Fix typo that prevented correct functioning of Polymer.dom under Shadow DOM and add tests to catch. ([commit](https://github.com/Polymer/polymer/commit/cdc9fde))\n\n- maintain compatibility with older `_notifyChange` arguments. ([commit](https://github.com/Polymer/polymer/commit/f5aec30))\n\n- Weird assignment fix ([commit](https://github.com/Polymer/polymer/commit/9e6f77a))\n\n- add comment. ([commit](https://github.com/Polymer/polymer/commit/f2d5f44))\n\n- For efficiency, use cached events in data system, for property and path changes. ([commit](https://github.com/Polymer/polymer/commit/da71dfe))\n\n- Fixes #2690 ([commit](https://github.com/Polymer/polymer/commit/d8b78d4))\n\n- change after render method to `Polymer.RenderStatus.afterNextRender` ([commit](https://github.com/Polymer/polymer/commit/8949c04))\n\n- When effect values are applied via bindings, use fromAbove gambit to avoid unnecessary wheel spinning. (This is now possible since we have fast lookup for readOnly where we want to avoid doing the set at all). ([commit](https://github.com/Polymer/polymer/commit/c520907))\n\n- do readOnly check for configured properties where they are handed down, rather than when they are consumed. ([commit](https://github.com/Polymer/polymer/commit/24bcedb))\n\n- Minor cleanup. ([commit](https://github.com/Polymer/polymer/commit/0b21506))\n\n- Avoid creating unnecessary placeholders for full refresh. ([commit](https://github.com/Polymer/polymer/commit/996289a))\n\n- Simplify ([commit](https://github.com/Polymer/polymer/commit/c5e1135))\n\n- Fix typo. ([commit](https://github.com/Polymer/polymer/commit/680c56d))\n\n- Update docs. ([commit](https://github.com/Polymer/polymer/commit/352ccbe))\n\n- _removeInstance -> _detachAndRemoveInstance ([commit](https://github.com/Polymer/polymer/commit/ba7a16f))\n\n- Remove limit & chunkCount API. Refactor insert/remove. ([commit](https://github.com/Polymer/polymer/commit/f447c0e))\n\n- add back deepContains (got removed incorrectly in merge). ([commit](https://github.com/Polymer/polymer/commit/d53ab57))\n\n- fix line endings. ([commit](https://github.com/Polymer/polymer/commit/0233d6d))\n\n- revert host attributes ordering change optimization as it was not worth the trouble (barely measurable and more cumbersome impl). ([commit](https://github.com/Polymer/polymer/commit/f9894a0))\n\n- rename host functions fix typos afterFirstRender is now raf+setTimeout dom-repeat: remove cruft ([commit](https://github.com/Polymer/polymer/commit/d82840b))\n\n- Fix Gestures when using SD polyfill ([commit](https://github.com/Polymer/polymer/commit/96e4bfa))\n\n- Fix for multiple consequent spaces present in CSS selectors, fixes #2670 ([commit](https://github.com/Polymer/polymer/commit/ecddb56))\n\n- avoid configuration work when unnecessary ([commit](https://github.com/Polymer/polymer/commit/e0fbfbe))\n\n- lazily create effect objects so we can more easily abort processing. avoid forEach ([commit](https://github.com/Polymer/polymer/commit/66df196))\n\n- provides support for memoizing pathFn on effect; only process effects/listeners if they exist. ([commit](https://github.com/Polymer/polymer/commit/a2376b6))\n\n- memoize pathFn on effect (note: notifyPath change made in previous commit); avoid forEach. ([commit](https://github.com/Polymer/polymer/commit/d93340a))\n\n- Avoid using .slice and .forEach ([commit](https://github.com/Polymer/polymer/commit/d2c02a9))\n\n- Added support for short unicode escape sequences, fixes #2650 ([commit](https://github.com/Polymer/polymer/commit/2c87145))\n\n- Fix for BEM-like CSS selectors under media queries, fixes #2639. Small optimization for produced CSS (empty rules produced semicolon before, now empty string). ([commit](https://github.com/Polymer/polymer/commit/35c89f1))\n\n- Fix parsing of custom properties with 'var' in value ([commit](https://github.com/Polymer/polymer/commit/61abfbd))\n\n- Clean up cruft. ([commit](https://github.com/Polymer/polymer/commit/59c27fa))\n\n- Add tests and fix issues. ([commit](https://github.com/Polymer/polymer/commit/e99e5fa))\n\n- dom-repeat chunked/throttled render API ([commit](https://github.com/Polymer/polymer/commit/e9aebd7))\n\n- Fix formatting. ([commit](https://github.com/Polymer/polymer/commit/56734a7))\n\n- Add notes on running unit tests. ([commit](https://github.com/Polymer/polymer/commit/492f310))\n\n- Corrected method name. Fixes #2649. ([commit](https://github.com/Polymer/polymer/commit/5168604))\n\n- Fix typos in more efficient array copying. ([commit](https://github.com/Polymer/polymer/commit/53f3a7d))\n\n- Adds `Polymer.RenderStatus.afterFirstRender` method. Call to perform tasks after an element first renders. ([commit](https://github.com/Polymer/polymer/commit/71b5c2a))\n\n- More efficient array management in Polymer.DomApi. ([commit](https://github.com/Polymer/polymer/commit/320d5c7))\n\n- Fixes #2652 ([commit](https://github.com/Polymer/polymer/commit/e35c4e9))\n\n- [ci skip] update changelog ([commit](https://github.com/Polymer/polymer/commit/0dc69df))\n\n- Fix whitespace around bindings. ([commit](https://github.com/Polymer/polymer/commit/d7d0ed6))\n\n- Add support for `strip-whitespace`. Should fix #2511. ([commit](https://github.com/Polymer/polymer/commit/35a1b94))\n\n- Improve efficiency of attribute configuration. ([commit](https://github.com/Polymer/polymer/commit/f7d86e9))\n\n- Remove use of Function.bind ([commit](https://github.com/Polymer/polymer/commit/25aab8b))\n\n- fix typos. ([commit](https://github.com/Polymer/polymer/commit/5fb20da))\n\n- Re-use data change events. Remove unused/undocumented listener object specific node listening feature. ([commit](https://github.com/Polymer/polymer/commit/8bdedf3))\n\n- Add flattened properties to dom-bind, templatizer, optimize by 'liming properties that are protected/private and not readOnly from list. ([commit](https://github.com/Polymer/polymer/commit/2ba08ec))\n\n- Use flattened list of properties for fast access during configuration and attribute->property ([commit](https://github.com/Polymer/polymer/commit/acdd242))\n\n- Assemble effect strings at prototype time. ([commit](https://github.com/Polymer/polymer/commit/4745e8f))\n\n- Fallback to string lookup to fix support for extra effects. ([commit](https://github.com/Polymer/polymer/commit/d3c4611))\n\n- Fix typo. ([commit](https://github.com/Polymer/polymer/commit/ead9adb))\n\n- Correct NodeList copying. ([commit](https://github.com/Polymer/polymer/commit/1d29e19))\n\n- Avoid Polymer.dom.setAttribute when unneeded. ([commit](https://github.com/Polymer/polymer/commit/9c5a404))\n\n- More efficient iteration. ([commit](https://github.com/Polymer/polymer/commit/23a9a06))\n\n- Avoid forEach ([commit](https://github.com/Polymer/polymer/commit/ebeaf80))\n\n- Copy dom NodeList faster than slice. ([commit](https://github.com/Polymer/polymer/commit/8cad475))\n\n- Avoid function lookup by string. ([commit](https://github.com/Polymer/polymer/commit/e2674bc))\n\n- Add test for parsing multi-line css comments ([commit](https://github.com/Polymer/polymer/commit/6f21ae6))\n\n## [v1.2.1](https://github.com/Polymer/polymer/tree/v1.2.1) (2015-10-29)\n- Fix test for SD polyfill ([commit](https://github.com/Polymer/polymer/commit/dd8b3e9))\n\n- Add pre-condition check for completeness. ([commit](https://github.com/Polymer/polymer/commit/89304dc))\n\n- Find non distributed children with deepContains ([commit](https://github.com/Polymer/polymer/commit/8e6f55a))\n\n- Ensure outer paths aren't forwarded to instance props. Fixes #2556. ([commit](https://github.com/Polymer/polymer/commit/01273e9))\n\n- Add `Polymer.dom.deepContains` ([commit](https://github.com/Polymer/polymer/commit/279bf63))\n\n- [ci skip] Update CHANGELOG ([commit](https://github.com/Polymer/polymer/commit/e1f83d2))\n\n- isLightDescendant should return false for self ([commit](https://github.com/Polymer/polymer/commit/a0debf4))\n\n- Fix for mixins declaration with space before colon. Allow any space character or even `{` and `}` (before and after capturing pattern correspondingly) as pattern boundaries instead of new lines only. In minified sources there might be no space, semicolon or line start, so we need to account that as well. ([commit](https://github.com/Polymer/polymer/commit/883aa5c))\n\n## [v1.2.0](https://github.com/Polymer/polymer/tree/v1.2.0) (2015-10-22)\n- A simpler travis config ([commit](https://github.com/Polymer/polymer/commit/3338b67))\n\n- Fix #2587: When Polymer.dom(el).appendChild(node) is called, cleanup work must be performed on the existing parent of node. This change fixes a missing case in this cleanup work: if the existing parent has a observer via `Polymer.dom(parent).observeNodes`, it needs to be notified that node is being removed even if the node does not have specific logical info. For example, if an observed node has no Shady DOM and has a child that is removed. A test for this case was added. ([commit](https://github.com/Polymer/polymer/commit/0d4f418))\n\n- add fancy travis status badge to the readme ([commit](https://github.com/Polymer/polymer/commit/e29fca8))\n\n- Do not configure compound property/attribute binding if literal if empty. Fixes #2583. ([commit](https://github.com/Polymer/polymer/commit/ca4724a))\n\n- Update .travis.yml ([commit](https://github.com/Polymer/polymer/commit/ef366c5))\n\n- Remove web-component-tester cache. ([commit](https://github.com/Polymer/polymer/commit/4ae23ce))\n\n- Fix IE10 regressions. Fixes #2582 * Copy attribute list before modifying it * Fall back to document for current document if no currentScript ([commit](https://github.com/Polymer/polymer/commit/ee65e68))\n\n- Allow _atEndOfMicrotask to be patchable. ([commit](https://github.com/Polymer/polymer/commit/e2d8446))\n\n- contributing copy fixup ([commit](https://github.com/Polymer/polymer/commit/ed22c50))\n\n- Update CONTRIBUTING.md ([commit](https://github.com/Polymer/polymer/commit/0c21efc))\n\n- Add travis config ([commit](https://github.com/Polymer/polymer/commit/6fb7684))\n\n- Factor into functions. ([commit](https://github.com/Polymer/polymer/commit/b2117dc))\n\n- Fix deepEqual on Safari 9 due to Safari enumeration bug. ([commit](https://github.com/Polymer/polymer/commit/445d603))\n\n- ensure distribution observers see all changes that can come from attributes under native Shadow DOM; +minor factoring ([commit](https://github.com/Polymer/polymer/commit/344f5cc))\n\n- Add <content>.getDistributedNodes observation. Refactor flush. ([commit](https://github.com/Polymer/polymer/commit/8b1face))\n\n- Add docs ([commit](https://github.com/Polymer/polymer/commit/0ede79a))\n\n- Make shadow attribute tracking automatic based on detecting a <content select> that depends on attributes; add tests. ([commit](https://github.com/Polymer/polymer/commit/54911a7))\n\n- Add comments. ([commit](https://github.com/Polymer/polymer/commit/758c483))\n\n- Fix typo. ([commit](https://github.com/Polymer/polymer/commit/74a87a0))\n\n- Replace _compoundInitializationEffect with statically-initialized literals in the template for attributes & textContent, and by configuring literal values of properties in _configureAnnotationReferences. ([commit](https://github.com/Polymer/polymer/commit/2f1bd31))\n\n- Simplify change tracking by always dirty checking at the observer level. Under Shadow DOM, use a deep MO to watch for attributes. ([commit](https://github.com/Polymer/polymer/commit/669acaa))\n\n- Fix URL to component.kitchen ([commit](https://github.com/Polymer/polymer/commit/d9af504))\n\n- Update the Google+ community link ([commit](https://github.com/Polymer/polymer/commit/c6684e5))\n\n- Fixes from review. ([commit](https://github.com/Polymer/polymer/commit/a300862))\n\n- Remove compound binding limitation from primer. ([commit](https://github.com/Polymer/polymer/commit/b1c1b35))\n\n- Exclude compound bindings from configure; revisit later. ([commit](https://github.com/Polymer/polymer/commit/1035e2d))\n\n- Apply effect value from compound parts. ([commit](https://github.com/Polymer/polymer/commit/c30ac10))\n\n- Store binding parts in notes. ([commit](https://github.com/Polymer/polymer/commit/1026498))\n\n- Fix missing var ([commit](https://github.com/Polymer/polymer/commit/68edb83))\n\n- Add radix for correctness. ([commit](https://github.com/Polymer/polymer/commit/a79f012))\n\n- Separate public & private get, flip conditions, add notifyPath API. ([commit](https://github.com/Polymer/polymer/commit/97503ec))\n\n- Fix typo in comments. ([commit](https://github.com/Polymer/polymer/commit/e59dbef))\n\n- Improvements to path API. Fixes #2509. * Allows `set` to take paths with array #keys * Allows `notifyPath` to take paths with array indices * Exposes public notifySplices API ([commit](https://github.com/Polymer/polymer/commit/10021cc))\n\n- Fix merge issue. ([commit](https://github.com/Polymer/polymer/commit/85c23e1))\n\n- Denote keys with # to disambiguate from index. Fixes #2007. ([commit](https://github.com/Polymer/polymer/commit/85d8a3a))\n\n- update CHANGELOG to 1.1.5 ([commit](https://github.com/Polymer/polymer/commit/b2b23c4))\n\n- make tests work on polyfill. ([commit](https://github.com/Polymer/polymer/commit/9ff2ee4))\n\n- add `observeNodes` tests. ([commit](https://github.com/Polymer/polymer/commit/bd90b57))\n\n- Add optional attribute tracking to support better distributed node notifications under shadow dom. ([commit](https://github.com/Polymer/polymer/commit/8242a98))\n\n- Add `Polymer.dom().notifyObservers` method to 'kick' observers, for example, when attributes change under Shadow DOM. ([commit](https://github.com/Polymer/polymer/commit/07261e4))\n\n- Add mutation tracking for distributedNodes. ([commit](https://github.com/Polymer/polymer/commit/b11f86b))\n\n- Factor dom-api's into separate helpers. ([commit](https://github.com/Polymer/polymer/commit/effedcb))\n\n- Adds `Polymer.dom(element).observeChildren(callback)` api ([commit](https://github.com/Polymer/polymer/commit/6499e83))\n\n- Adds `getEffectiveChildNodes`, `getEffectiveChildren`, `getEffectiveTextContent` ([commit](https://github.com/Polymer/polymer/commit/f34fb45))\n\n## [v1.1.5](https://github.com/Polymer/polymer/tree/v1.1.5) (2015-10-08)\n- Simplify ([commit](https://github.com/Polymer/polymer/commit/79dfe1f))\n\n- Clean up templatizer _pathEffectorImpl. ([commit](https://github.com/Polymer/polymer/commit/1a89bcf))\n\n- Add issue link. ([commit](https://github.com/Polymer/polymer/commit/e4c2433))\n\n- Missing var keyword ([commit](https://github.com/Polymer/polymer/commit/45fcbcf))\n\n- Make sure we only actually call _listen once ([commit](https://github.com/Polymer/polymer/commit/837e9b8))\n\n- Add templatizer tests.  Fix issues from tests. ([commit](https://github.com/Polymer/polymer/commit/2d97cd7))\n\n- Use 'value' in place of 'object' when referring to detail. ([commit](https://github.com/Polymer/polymer/commit/f17be35))\n\n- Allow any type, not just objects, as the detail for fire. ([commit](https://github.com/Polymer/polymer/commit/ec59f57))\n\n- Make model param of stamp method optional. ([commit](https://github.com/Polymer/polymer/commit/a2e1e64))\n\n- add test to ensure unlisten events do not fire ([commit](https://github.com/Polymer/polymer/commit/bf2f694))\n\n- add tests ([commit](https://github.com/Polymer/polymer/commit/900d82b))\n\n- Only one real listener per `listen` call ([commit](https://github.com/Polymer/polymer/commit/8bd380a))\n\n- add util method for shadow children ([commit](https://github.com/Polymer/polymer/commit/1e9110a))\n\n- Add notify-path API to templatized template. Fixes #2505. ([commit](https://github.com/Polymer/polymer/commit/2e086fe))\n\n- Parent property values should come from template. Fixes #2504. ([commit](https://github.com/Polymer/polymer/commit/23c883b))\n\n- Added note about including a clear repro case. ([commit](https://github.com/Polymer/polymer/commit/e18f009))\n\n- added request to submit an issue before sending a PR ([commit](https://github.com/Polymer/polymer/commit/6ed836f))\n\n- update CHANGELOG to 1.1.4 ([commit](https://github.com/Polymer/polymer/commit/c2b7c31))\n\n## [v1.1.4](https://github.com/Polymer/polymer/tree/v1.1.4) (2015-09-25)\n- :memo: Update description ([commit](https://github.com/Polymer/polymer/commit/6afb8be))\n\n- :art: Use npm command bin lookup ([commit](https://github.com/Polymer/polymer/commit/84258d4))\n\n- :grapes: Add missing test dependency ([commit](https://github.com/Polymer/polymer/commit/5726b8e))\n\n- Reset handlers queue after finished replaying events ([commit](https://github.com/Polymer/polymer/commit/76a5f17))\n\n- Update the README.md to Polymer 1.1 ([commit](https://github.com/Polymer/polymer/commit/40c455a))\n\n- Add note on arrayDelete with array vs. path ([commit](https://github.com/Polymer/polymer/commit/d2b71a5))\n\n- Add unlinkPath tests. ([commit](https://github.com/Polymer/polymer/commit/bee110b))\n\n- Update changelog ([commit](https://github.com/Polymer/polymer/commit/573ca29))\n\n- Remove dead code; add tests. ([commit](https://github.com/Polymer/polymer/commit/ab85884))\n\n- Allow multiple paths to be linked using linkPath. Fixes #2048 ([commit](https://github.com/Polymer/polymer/commit/b221dbe))\n\n- Fix docs for stamp method ([commit](https://github.com/Polymer/polymer/commit/8adbe60))\n\n- http to https for jsbin ([commit](https://github.com/Polymer/polymer/commit/d842435))\n\n- Typo ([commit](https://github.com/Polymer/polymer/commit/d558c0d))\n\n- Fix typos in PRIMER.md ([commit](https://github.com/Polymer/polymer/commit/cf793f4))\n\n## [v1.1.3](https://github.com/Polymer/polymer/tree/v1.1.3) (2015-09-04)\n- Fixes #2403 ([commit](https://github.com/Polymer/polymer/commit/a6694b7))\n\n- Only try to decrement gesture dependency counter if dependency exists ([commit](https://github.com/Polymer/polymer/commit/8886e8c))\n\n- update changelog with v1.1.2 ([commit](https://github.com/Polymer/polymer/commit/d3a7c93))\n\n- prepare v1.1.2 ([commit](https://github.com/Polymer/polymer/commit/e78be4f))\n\n## [v1.1.2](https://github.com/Polymer/polymer/tree/v1.1.2) (2015-08-28)\n- Improve composed parent tracking. ([commit](https://github.com/Polymer/polymer/commit/4d15789))\n\n- move the mixing-in of behaviors so that it happens before `register` behaviors are invoked ([commit](https://github.com/Polymer/polymer/commit/637367c))\n\n- Fixes #2378 ([commit](https://github.com/Polymer/polymer/commit/a9f081b))\n\n- Fixes #2356: issue a warning and don't throw an exception when a style include cannot be found. Fixes #2357: include data now comes before any textContent in a style element. ([commit](https://github.com/Polymer/polymer/commit/a16ada1))\n\n- remove unneeded protection code for extends. ([commit](https://github.com/Polymer/polymer/commit/8eada87))\n\n- Add test ([commit](https://github.com/Polymer/polymer/commit/47ff0e8))\n\n- add test for `registered` behavior affecting a value then used by features ([commit](https://github.com/Polymer/polymer/commit/230528c))\n\n- add tests for new Polymer() argument support (and make Base tests aware of new abstract method `_desugarBehaviors`) ([commit](https://github.com/Polymer/polymer/commit/9734a3a))\n\n- invoke `registration` behavior before registering features, so behaviors can alter features, this requires calling behavior flattening as part of prototype desugaring instead of as part of behavior prep, so the flattened list is available early ([commit](https://github.com/Polymer/polymer/commit/6224dc3))\n\n- do `registered` behaviors before invoking `registerFeatures` so `registered` can affect properties used by features (ref #2329) ([commit](https://github.com/Polymer/polymer/commit/61d611c))\n\n- specifically create `Polymer` object on `window` to satisfy strict mode (fixes #2363) ([commit](https://github.com/Polymer/polymer/commit/a75133d))\n\n- Remove forceUpgraded check in dom-module.import ([commit](https://github.com/Polymer/polymer/commit/b85b641))\n\n- Fixes #2341: branch Polymer.dom to use native dom methods under Shadow DOM for: appendChild, insertBefore, removeChild, replaceChild, cloneNode. ([commit](https://github.com/Polymer/polymer/commit/9b1f706))\n\n- Fixes #2334: when composing nodes in shady dom, check if a node is where we expect it to be before removing it from its distributed position. We do this because the node may have been moved by Polymer.dom in a way that triggered distribution of its previous location. The node is already where it needs to be so removing it from its parent when it's no longer distributed is destructive. ([commit](https://github.com/Polymer/polymer/commit/4ea69c2))\n\n- use cached template annotations when possible ([commit](https://github.com/Polymer/polymer/commit/b0733d3))\n\n- fix comment typos ([commit](https://github.com/Polymer/polymer/commit/a0a3e0c))\n\n- Update changelog with v1.1.1 release ([commit](https://github.com/Polymer/polymer/commit/12fa867))\n\n## [v1.1.1](https://github.com/Polymer/polymer/tree/v1.1.1) (2015-08-20)\n- Fixes #2263: ensure custom-style can parse variable definitions in supported selectors (e.g. /deep/) without exception due to unknown css. ([commit](https://github.com/Polymer/polymer/commit/894492b))\n\n- Fixes #2311, #2323: when elements are removed from their previous position when they are added elsewhere, make sure to remove them from composed, not logical parent. ([commit](https://github.com/Polymer/polymer/commit/3d93116))\n\n- Update Changelog ([commit](https://github.com/Polymer/polymer/commit/039ef93))\n\n- Add selectedItem property ([commit](https://github.com/Polymer/polymer/commit/d65acd0))\n\n- Add test for large splice ([commit](https://github.com/Polymer/polymer/commit/c967583))\n\n- Use numeric sort when removing dom-repeat instances ([commit](https://github.com/Polymer/polymer/commit/fccbd8a))\n\n- Fixes #2267: properly find dom-module for mixed case elements ([commit](https://github.com/Polymer/polymer/commit/76c58b8))\n\n- Fixes #2304: avoid trying to read style data from imports that did not load. ([commit](https://github.com/Polymer/polymer/commit/0d1f206))\n\n- Avoid saving logical info on parent when a content is added inside a fragment + slight factoring. ([commit](https://github.com/Polymer/polymer/commit/36072be))\n\n- Fixes #2276: avoid losing logical information and simplify logical tree handling ([commit](https://github.com/Polymer/polymer/commit/ee61627))\n\n- Moved check earlier. Added test for negative literal. ([commit](https://github.com/Polymer/polymer/commit/1a87ab4))\n\n- Fixes #2253: refine logical tree check and populate parents of insertion points with logical info only if necessary. Fixes #2283: when a node is removed, we need to potentially distribute not only its host but also its parent. ([commit](https://github.com/Polymer/polymer/commit/6619f6c))\n\n- Support for negative numbers in computed bindings ([commit](https://github.com/Polymer/polymer/commit/fc53f50))\n\n## [v1.1.0](https://github.com/Polymer/polymer/tree/v1.1.0) (2015-08-13)\n- Add comment. ([commit](https://github.com/Polymer/polymer/commit/337b54a))\n\n- Add tests for key splice fix. ([commit](https://github.com/Polymer/polymer/commit/4bc055b))\n\n- Fixes #2251: resolve imported stylesheets against correct document. ([commit](https://github.com/Polymer/polymer/commit/68af666))\n\n- Reduce keySplices to minimum change set before notifying. Fixes #2261 ([commit](https://github.com/Polymer/polymer/commit/f74d072))\n\n- Make `clearSelection` public. ([commit](https://github.com/Polymer/polymer/commit/7497729))\n\n- Add logical info iff an element being added is an insertion point; do not add logical info for any element in a shady root. ([commit](https://github.com/Polymer/polymer/commit/45cb150))\n\n- Make `clearSelection` public. ([commit](https://github.com/Polymer/polymer/commit/d55be7d))\n\n- Fixes #2235. Manages logical information in shady distribution more directly by capturing it explicitly when needed and not whenever distribution is run. ([commit](https://github.com/Polymer/polymer/commit/21500fb))\n\n- ensure path fixup is applied correctly to styles in templates. ([commit](https://github.com/Polymer/polymer/commit/b22f3cd))\n\n- Based on feedback, change `module` to `include` in custom-style and dom-module style marshaling. ([commit](https://github.com/Polymer/polymer/commit/f469129))\n\n- Document custom-style module property. ([commit](https://github.com/Polymer/polymer/commit/398d9f7))\n\n- Add comment. ([commit](https://github.com/Polymer/polymer/commit/4e640c7))\n\n- Add tests and require `module` to be on `style` elements. ([commit](https://github.com/Polymer/polymer/commit/58d3c3b))\n\n- `custom-style` supports `module` property that accepts a `dom-module` containing style data. `don-module` style data may be specified inside `<template>` elements and style elements also support module attribute for referencing additional modules containing style data. ([commit](https://github.com/Polymer/polymer/commit/3734c4d))\n\n- don-module no longer needs to eagerly upgrade custom elements since the web components polyfills do this automatically. ([commit](https://github.com/Polymer/polymer/commit/051e1bf))\n\n## [v1.0.9](https://github.com/Polymer/polymer/tree/v1.0.9) (2015-08-07)\n- Remove undocumented return value. ([commit](https://github.com/Polymer/polymer/commit/1764d0c))\n\n- Add default, update docs. ([commit](https://github.com/Polymer/polymer/commit/ca267a5))\n\n- Add tests for isSelected. ([commit](https://github.com/Polymer/polymer/commit/15d63ef))\n\n- Default selected to empty array. Add isSelected API. ([commit](https://github.com/Polymer/polymer/commit/d4e7140))\n\n- Fixes #2218: match style properties against scope transformed selector (not property unique selector) ([commit](https://github.com/Polymer/polymer/commit/c9e9062))\n\n- Remove notify for items (unnecessary). ([commit](https://github.com/Polymer/polymer/commit/a370860))\n\n- Uncomment line. ([commit](https://github.com/Polymer/polymer/commit/b25330b))\n\n- Give toggle a default. ([commit](https://github.com/Polymer/polymer/commit/db9bda5))\n\n- Use multi-prop observer; default selected to null. ([commit](https://github.com/Polymer/polymer/commit/ba4bf38))\n\n- Add tests. Reset selection on items/multi change. Remove async. ([commit](https://github.com/Polymer/polymer/commit/5bca55b))\n\n- Property matching must check non-transformed rule selector. ([commit](https://github.com/Polymer/polymer/commit/5b9a5ce))\n\n- Make _itemsChanged depend on multi. ([commit](https://github.com/Polymer/polymer/commit/1b21397))\n\n- Make sure mouse position is not a factor for .click() in IE 10 ([commit](https://github.com/Polymer/polymer/commit/1a2fb4d))\n\n- Always trigger tap for synthetic click events ([commit](https://github.com/Polymer/polymer/commit/1eef1a7))\n\n- Fixes #2193: Implements workaround for https://code.google.com/p/chromium/issues/detail?id=516550 by adding Polymer.RenderStatus.whenReady and using it to defer `attached` ([commit](https://github.com/Polymer/polymer/commit/2bffc4c))\n\n- Fix polyfill templates ([commit](https://github.com/Polymer/polymer/commit/d78c934))\n\n- Use `_clientsReadied` to avoid missing attribute->property sets in ready. ([commit](https://github.com/Polymer/polymer/commit/165f716))\n\n- Make propagation of attribute changes at configure time more efficient ([commit](https://github.com/Polymer/polymer/commit/b269c1d))\n\n- add offsetParent smoke tests ([commit](https://github.com/Polymer/polymer/commit/0b2cfae))\n\n- Fixes #1673: ensure instance effects exist before marshaling attributes. ([commit](https://github.com/Polymer/polymer/commit/7c83df5))\n\n- Fix typo. ([commit](https://github.com/Polymer/polymer/commit/97944e4))\n\n- Clarify `fire` option defaults. Fixes #2180 ([commit](https://github.com/Polymer/polymer/commit/7c3e516))\n\n- Add cross-reference for API docs. Fixes #2180 ([commit](https://github.com/Polymer/polymer/commit/9bdcc3b))\n\n- Updated utils & removed fn signatures; defer to API docs. Fixes #2180 ([commit](https://github.com/Polymer/polymer/commit/b9b86d5))\n\n- Update core- to iron-ajax in PRIMER.md  as in Polymer/docs#1276, Polymer/docs#1275 ([commit](https://github.com/Polymer/polymer/commit/e99358a))\n\n- Update core- to iron-ajax in jsdoc for dom-bind  as in Polymer/docs#1276, Polymer/docs#1275 ([commit](https://github.com/Polymer/polymer/commit/07327c0))\n\n- Make properties replacement robust against properties which start with a leading `;` ([commit](https://github.com/Polymer/polymer/commit/3ea0333))\n\n- Fixes #2154: ensure Polymer.dom always sees wrapped nodes when ShadowDOM polyfill is in use. ([commit](https://github.com/Polymer/polymer/commit/fc90aa0))\n\n- Use css parser's property stripping code in custom-style. ([commit](https://github.com/Polymer/polymer/commit/756ef1b))\n\n- Deduplicate track/untrack document event listener logic ([commit](https://github.com/Polymer/polymer/commit/53037d4))\n\n- Automatically filter mouseevents without the left mouse button ([commit](https://github.com/Polymer/polymer/commit/bbc3b57))\n\n- Fixes #2113: ensures custom-style rules that use @apply combined with defining properties apply correctly. ([commit](https://github.com/Polymer/polymer/commit/69a4aa5))\n\n- Correct & simplify per spec. ([commit](https://github.com/Polymer/polymer/commit/7b8b7fd))\n\n- Clean up logic. ([commit](https://github.com/Polymer/polymer/commit/d4deb5d))\n\n- More loosely match expression function names ([commit](https://github.com/Polymer/polymer/commit/6cfa759))\n\n- Fix link to direct to Cross-scope styling ([commit](https://github.com/Polymer/polymer/commit/f9c58bc))\n\n- Update behaviors order.  Fixes #2144. ([commit](https://github.com/Polymer/polymer/commit/2a51661))\n\n- Cache style.display & textContent and re-apply on true. Fixes #2037 ([commit](https://github.com/Polymer/polymer/commit/2611285))\n\n- Fixes #2118: force element `is` to be lowercase: mixing case causes confusion and breaks style shimming for type extensions. ([commit](https://github.com/Polymer/polymer/commit/c8905f9))\n\n- Allow array API's accept string & negative args. Fixes #2062. Brings the API more in line with native splice, etc. ([commit](https://github.com/Polymer/polymer/commit/7e2ceeb))\n\n- Fix #2107: improve binding expression parser to match valid javascript property names. ([commit](https://github.com/Polymer/polymer/commit/7560130))\n\n## [v1.0.8](https://github.com/Polymer/polymer/tree/v1.0.8) (2015-07-23)\n- Disable tracking if scrolling ([commit](https://github.com/Polymer/polymer/commit/ee5177d))\n\n- Fixes #2125: adds a register method to dom-module to support imperative creation. ([commit](https://github.com/Polymer/polymer/commit/861f4aa))\n\n- Move recognizer reset into start of event flow ([commit](https://github.com/Polymer/polymer/commit/a7495f7))\n\n- Fixed small typo on PRIMER.md ([commit](https://github.com/Polymer/polymer/commit/bc40821))\n\n- remove alternate calculation for _rootDataHost ([commit](https://github.com/Polymer/polymer/commit/26663cd))\n\n- Don't call `dom-change` when detached. ([commit](https://github.com/Polymer/polymer/commit/bdb8fa3))\n\n- Fix typo. ([commit](https://github.com/Polymer/polymer/commit/65911bd))\n\n- Improve code formatting. ([commit](https://github.com/Polymer/polymer/commit/3968c84))\n\n- Up flush MAX to 100 and add overflow warning. ([commit](https://github.com/Polymer/polymer/commit/8bcc416))\n\n- Fixes #1998: add api doc for `customStyle` property ([commit](https://github.com/Polymer/polymer/commit/91577c9))\n\n- Handle commentnodes correctly for textContent and innerHTML ([commit](https://github.com/Polymer/polymer/commit/6d56d2b))\n\n- Fixes #2098: don't accept undefined values as initial config ([commit](https://github.com/Polymer/polymer/commit/1a5c391))\n\n- Remove key check; int check should guarantee key. ([commit](https://github.com/Polymer/polymer/commit/dbf833e))\n\n- Add unit tests. ([commit](https://github.com/Polymer/polymer/commit/bc4b142))\n\n- Allow setting non-index array properties. Fixes #2096. ([commit](https://github.com/Polymer/polymer/commit/f8cad94))\n\n- update tests. ([commit](https://github.com/Polymer/polymer/commit/8922323))\n\n- added `render` method to dom-bind which can be called when async imports are used; documented template render functions ([commit](https://github.com/Polymer/polymer/commit/348896a))\n\n- Fixes #2039: Polymer.dom.flush now triggers Custom Elements polyfill mutations and includes an api (`Polymer.dom.addDebouncer(debouncer)`) for adding debouncers which should run at flush time. Template rendering debouncers are placed in the flush list. ([commit](https://github.com/Polymer/polymer/commit/89a767c))\n\n- Fixes #2010, fixes #1818: Shady dom mutations which trigger additional mutations are now successfully enqueued. ([commit](https://github.com/Polymer/polymer/commit/a26247b))\n\n- debounce returns debouncer. ([commit](https://github.com/Polymer/polymer/commit/fb52120))\n\n- Update index.html ([commit](https://github.com/Polymer/polymer/commit/119df98))\n\n## [v1.0.7](https://github.com/Polymer/polymer/tree/v1.0.7) (2015-07-16)\n- Replace placeholders backwards to simplify. ([commit](https://github.com/Polymer/polymer/commit/5eda235))\n\n- Remove unnecessary keys bookkeeping. ([commit](https://github.com/Polymer/polymer/commit/3e02bfd))\n\n- Minor tweaks to comments, internal API consistency. ([commit](https://github.com/Polymer/polymer/commit/82958d4))\n\n- Always use placeholders; fix insertion reference bug. ([commit](https://github.com/Polymer/polymer/commit/4a45d4f))\n\n- Simplify. ([commit](https://github.com/Polymer/polymer/commit/4eda393))\n\n- Rename variables for clarity. ([commit](https://github.com/Polymer/polymer/commit/15c1241))\n\n- Fix reuse logic to handle multiple mutations in same turn. Fixes #2009. ([commit](https://github.com/Polymer/polymer/commit/1bf5f6d))\n\n- Be more explicit. ([commit](https://github.com/Polymer/polymer/commit/a6bd5a5))\n\n- Add Polymer.instanceof & isInstance. Fixes #2083. ([commit](https://github.com/Polymer/polymer/commit/7954f93))\n\n- Fixes #2081: make Polymer.dom(element).getDistributedNodes and Polymer.dom(element).getDestinationInsertionPoints() always return at least an empty array (was generating exception under Shadow DOM); make element.getContentChildNodes and element.getContentChildren always return at least an empty array when a selector is passed that does not find a <content>  (was generating exception under Shadow DOM) ([commit](https://github.com/Polymer/polymer/commit/f966381))\n\n- Fixes #2077: workaround IE text node splitting issue that can make text bindings fail. ([commit](https://github.com/Polymer/polymer/commit/312d11f))\n\n- Fixes #2078: when computing custom style properties, make sure the styling scope is valid when the element is attached to a shadowRoot whose host is not a Polymer element. ([commit](https://github.com/Polymer/polymer/commit/fab2ed7))\n\n- update CHANGELOG for 1.0.6 ([commit](https://github.com/Polymer/polymer/commit/c46ec11))\n\n\\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/GitHub-Changelog-Generator) below*\n## [v1.0.6](https://github.com/Polymer/polymer/tree/v1.0.6) (2015-07-09)\n\n**Fixed issues:**\n\n- Basic support for host-context [\\#1895](https://github.com/Polymer/polymer/issues/1895)\n\n- custom property resolver tripping over some selectors? [\\#1938](https://github.com/Polymer/polymer/issues/1938)\n\n- Parsing compressed CSS does not work [\\#1927](https://github.com/Polymer/polymer/issues/1927)\n\n- Support Polymer.dom().classList.contains [\\#1907](https://github.com/Polymer/polymer/issues/1907)\n\n- Add support for :host-context [\\#1900](https://github.com/Polymer/polymer/issues/1900)\n\n- Grey overlay in mobile Safari [\\#1970](https://github.com/Polymer/polymer/issues/1970)\n\n- `node.unlisten` removes native event listeners too often [\\#1988](https://github.com/Polymer/polymer/issues/1988)\n\n- `notifyPath` doesn't return as its documentation says [\\#1966](https://github.com/Polymer/polymer/issues/1966)\n\n- \"TypeError: Cannot set property 'display' of undefined\" when HTML comment is present inside a dom-if template that evaluates to truthy [\\#1786](https://github.com/Polymer/polymer/issues/1786)\n\n- `dom-repeat` in a falsy `dom-if` should hide newly stamped children [\\#1751](https://github.com/Polymer/polymer/issues/1751)\n\n- Typo in Polymer.mixin API documentation [\\#2001](https://github.com/Polymer/polymer/issues/2001)\n\n- Low-level changes for `iron-list` integration (`fire` & `modelForElement`) [\\#2003](https://github.com/Polymer/polymer/issues/2003)\n\n- Normalized event difference with ShadowDOM and Shady [\\#1921](https://github.com/Polymer/polymer/issues/1921)\n\n- DOM API innerHTML adds only first element [\\#1972](https://github.com/Polymer/polymer/issues/1972)\n\n- with Polymer\\#1.05-update, style-sheets and custom-style-elements are not parsed in my project anymore [\\#1974](https://github.com/Polymer/polymer/issues/1974)\n\n- Expected behavior for importNode,cloneNode [\\#1888](https://github.com/Polymer/polymer/issues/1888)\n\n- \\#1.0.5 computed property function name limitations? [\\#2016](https://github.com/Polymer/polymer/issues/2016)\n\n## [v1.0.5](https://github.com/Polymer/polymer/tree/v1.0.5) (2015-06-25)\n\n**Fixed issues:**\n\n- Bindings to concrete types not propagating correctly from template to collection [\\#1839](https://github.com/Polymer/polymer/issues/1839)\n\n- Setting individual array elements not working [\\#1854](https://github.com/Polymer/polymer/issues/1854)\n\n- `CustomStyle` change has no effect [\\#1851](https://github.com/Polymer/polymer/issues/1851)\n\n- With Shady DOM, `<content>` doesn't get passed to another element inside `dom-if` [\\#1902](https://github.com/Polymer/polymer/issues/1902)\n\n- Provide a convenience method for setting `customStyle` and calling `updateStyles` [\\#1915](https://github.com/Polymer/polymer/issues/1915)\n\n- If an `async` callback throws an error, it's never removed from the callback list [\\#1759](https://github.com/Polymer/polymer/issues/1759)\n\n- `dom-if`: undefined is considered falsy only once [\\#1742](https://github.com/Polymer/polymer/issues/1742)\n\n- Setting `readOnly` AND `computed` on properties [\\#1925](https://github.com/Polymer/polymer/issues/1925)\n\n- `Uncaught TypeError: this.mixin is not a function` [\\#1911](https://github.com/Polymer/polymer/issues/1911)\n\n- `Polymer.Base.async` \"infinite loop\" condition [\\#1933](https://github.com/Polymer/polymer/issues/1933)\n\n- Custom property resolver tripping over some selectors? [\\#1938](https://github.com/Polymer/polymer/issues/1938)\n\n- Annotated attribute binding issues [\\#1874](https://github.com/Polymer/polymer/issues/1874)\n\n- Parsing compressed CSS does not work [\\#1927](https://github.com/Polymer/polymer/issues/1927)\n\n## [v1.0.4](https://github.com/Polymer/polymer/tree/v1.0.4) (2015-06-17)\n\n**Closed issues:**\n\n- Error when i put a paper-input inside a paper-drawer-panel [\\#1893](https://github.com/Polymer/polymer/issues/1893)\n\n- Open the website country restrictions [\\#1885](https://github.com/Polymer/polymer/issues/1885)\n\n- Observers  executed twice if defined in both the properties and the observers array [\\#1884](https://github.com/Polymer/polymer/issues/1884)\n\n- If I set element property before component registered I cannot change it anymore [\\#1882](https://github.com/Polymer/polymer/issues/1882)\n\n- Polymer icon set not scaling with size [\\#1881](https://github.com/Polymer/polymer/issues/1881)\n\n- How binding a JSON in Polymer 1.0 [\\#1878](https://github.com/Polymer/polymer/issues/1878)\n\n- Annotated attribute binding issues [\\#1874](https://github.com/Polymer/polymer/issues/1874)\n\n- Paper Elements don't appear on site [\\#1868](https://github.com/Polymer/polymer/issues/1868)\n\n- \\[1.0\\] Inserted content not toggled when inside dom-if [\\#1862](https://github.com/Polymer/polymer/issues/1862)\n\n- Polymer Catalog -- link-related usability issue [\\#1860](https://github.com/Polymer/polymer/issues/1860)\n\n- Issues with catalog on Chromium 37.0.2062.120, 41.0.2272.76, and Firefox 38.0 [\\#1859](https://github.com/Polymer/polymer/issues/1859)\n\n- documentation bug; search elements [\\#1858](https://github.com/Polymer/polymer/issues/1858)\n\n- can I two way binding a properties type of 'Number' to attribute? [\\#1856](https://github.com/Polymer/polymer/issues/1856)\n\n- 'this' points to Window rather than custom element when called through setTimeOut\\(\\) [\\#1853](https://github.com/Polymer/polymer/issues/1853)\n\n- Cannot define an element in the main document \\(Firefox and Internet explorer\\) [\\#1850](https://github.com/Polymer/polymer/issues/1850)\n\n- Feature: array variable accessor [\\#1849](https://github.com/Polymer/polymer/issues/1849)\n\n- Support for expressions and filters [\\#1847](https://github.com/Polymer/polymer/issues/1847)\n\n- key/value iteration support for template dom-repeat [\\#1846](https://github.com/Polymer/polymer/issues/1846)\n\n- Styling local DOM [\\#1842](https://github.com/Polymer/polymer/issues/1842)\n\n- Polymer bouded property not updating - or getting reset \\(sometimes\\) [\\#1840](https://github.com/Polymer/polymer/issues/1840)\n\n- insertRule\\('body /deep/ myclass' + ' {' + cssText + '}', index\\); throws error in ff and ie [\\#1836](https://github.com/Polymer/polymer/issues/1836)\n\n- this.insertRule\\(\"body /deep/ someclass\", index\\); error [\\#1835](https://github.com/Polymer/polymer/issues/1835)\n\n- \\<core-scaffold\\> 0.5 toolbar background coloring broken [\\#1834](https://github.com/Polymer/polymer/issues/1834)\n\n- Radio buttons break when using border-box [\\#1832](https://github.com/Polymer/polymer/issues/1832)\n\n- polymer 1.0 how to use dom-if ? [\\#1828](https://github.com/Polymer/polymer/issues/1828)\n\n- Remove the undocumented \"find nearest template\" feature when registering [\\#1827](https://github.com/Polymer/polymer/issues/1827)\n\n- Remove `preventDefault` from track [\\#1824](https://github.com/Polymer/polymer/issues/1824)\n\n- Need a way to cancel track and tap from down [\\#1823](https://github.com/Polymer/polymer/issues/1823)\n\n- Computed bindings are not updated when using polymer's this.push to add elements [\\#1822](https://github.com/Polymer/polymer/issues/1822)\n\n-  Two-way bindings to array members not updating when data edited in dom-repeat template \\(bug or feature?\\) [\\#1821](https://github.com/Polymer/polymer/issues/1821)\n\n- Binding undefined does not work as expected [\\#1813](https://github.com/Polymer/polymer/issues/1813)\n\n- Can't declare Boolean attributes with default of true? [\\#1812](https://github.com/Polymer/polymer/issues/1812)\n\n- array-selector doesn't work with `multi` unless `toggle` is specified  [\\#1810](https://github.com/Polymer/polymer/issues/1810)\n\n- Style shim only converts a single ::shadow or /deep/ in a selector [\\#1809](https://github.com/Polymer/polymer/issues/1809)\n\n- Incorrect style for custom CSS properties when extending a native element [\\#1807](https://github.com/Polymer/polymer/issues/1807)\n\n- Document compatibility with browser [\\#1805](https://github.com/Polymer/polymer/issues/1805)\n\n- Unwrapped dom-if causes DOMException [\\#1804](https://github.com/Polymer/polymer/issues/1804)\n\n- \\<template is=dom-if\\> fails to add rows to a table if they contain \\<content\\> [\\#1800](https://github.com/Polymer/polymer/issues/1800)\n\n- Data binding causes infinite loop if value is NaN [\\#1799](https://github.com/Polymer/polymer/issues/1799)\n\n- Issues with polymer 1.0 dom-repeat templates using paper-radio-group and the selected property [\\#1792](https://github.com/Polymer/polymer/issues/1792)\n\n- bind attribute replacement [\\#1790](https://github.com/Polymer/polymer/issues/1790)\n\n- The Shadows sucks [\\#1788](https://github.com/Polymer/polymer/issues/1788)\n\n- Is there a list of Polymer 1.0 elements in the documentations? as it used to be 0.5! [\\#1782](https://github.com/Polymer/polymer/issues/1782)\n\n- Custom style variables for elements added outside of polymer [\\#1781](https://github.com/Polymer/polymer/issues/1781)\n\n- Can I recover the contaminated DOM? [\\#1779](https://github.com/Polymer/polymer/issues/1779)\n\n- \\[1.0\\] Data-binding: Is there any way to do this imperatively? [\\#1778](https://github.com/Polymer/polymer/issues/1778)\n\n- DATA-BINDING [\\#1772](https://github.com/Polymer/polymer/issues/1772)\n\n- \\[1.0\\] polymer attribute used in a string behaving differently from 0.5 [\\#1770](https://github.com/Polymer/polymer/issues/1770)\n\n- \\[1.0.2\\] Setting property treated as idempotent, but isn't [\\#1768](https://github.com/Polymer/polymer/issues/1768)\n\n- official element-table bower package [\\#1767](https://github.com/Polymer/polymer/issues/1767)\n\n- Shopping card polymer element [\\#1766](https://github.com/Polymer/polymer/issues/1766)\n\n- How to create a polymer element from iron-ajax element response [\\#1764](https://github.com/Polymer/polymer/issues/1764)\n\n- iron-collapse is focusable \\(by clicking or tabbing into it\\), which produces a focus outline in browsers [\\#1760](https://github.com/Polymer/polymer/issues/1760)\n\n- dom-repeat data binding: not working as expected [\\#1758](https://github.com/Polymer/polymer/issues/1758)\n\n- \\[1.0.3\\] Do not resolve hash-only urls used for routing [\\#1757](https://github.com/Polymer/polymer/issues/1757)\n\n- \\[1.0.3\\]Cannot start up after upgrade [\\#1754](https://github.com/Polymer/polymer/issues/1754)\n\n- Content nodes in `dom-if` template do not distribute correctly [\\#1753](https://github.com/Polymer/polymer/issues/1753)\n\n- overriding the custom css variables only works for the first dom element on the page [\\#1752](https://github.com/Polymer/polymer/issues/1752)\n\n- paper-checkbox should have an indeterminate state [\\#1749](https://github.com/Polymer/polymer/issues/1749)\n\n- nested dom-repeat with sort attribute shows duplicate entries when adding new items. [\\#1744](https://github.com/Polymer/polymer/issues/1744)\n\n- `attached` handler executed in wrong order in chrome browser. [\\#1743](https://github.com/Polymer/polymer/issues/1743)\n\n- \\[1.0.2\\] '$' is undefined when 'created' is being called  [\\#1728](https://github.com/Polymer/polymer/issues/1728)\n\n- \\[1.0\\] ::before / ::after psudo selectors in a custom-style [\\#1668](https://github.com/Polymer/polymer/issues/1668)\n\n- Need Polymer.Base.unlisten to remove the event listener [\\#1639](https://github.com/Polymer/polymer/issues/1639)\n\n- custom-style sometimes does not apply variables [\\#1637](https://github.com/Polymer/polymer/issues/1637)\n\n- \\[0.9.4\\] Dom-if template doesn't stamp when its content contains a wrapped insertion point [\\#1631](https://github.com/Polymer/polymer/issues/1631)\n\n- With \\<template if=\\> missing how can I have several different styles applied? [\\#1419](https://github.com/Polymer/polymer/issues/1419)\n\n**Merged pull requests:**\n\n- Includes element defaults in the list of own properties by which elements are styled. [\\#1891](https://github.com/Polymer/polymer/pull/1891) ([sorvell](https://github.com/sorvell))\n\n- Style shimming fixes [\\#1857](https://github.com/Polymer/polymer/pull/1857) ([sorvell](https://github.com/sorvell))\n\n- Clear composedNodes when an element upgrades without an insertion point [\\#1845](https://github.com/Polymer/polymer/pull/1845) ([sorvell](https://github.com/sorvell))\n\n- Allow user prevention of `tap` and `track` gestures from `down` [\\#1843](https://github.com/Polymer/polymer/pull/1843) ([azakus](https://github.com/azakus))\n\n- Fix incorrect test for `toggle`. Fixes \\#1810. [\\#1841](https://github.com/Polymer/polymer/pull/1841) ([arthurevans](https://github.com/arthurevans))\n\n- Use var keyword when declaring local variable so it doesn't leak to global scope. [\\#1838](https://github.com/Polymer/polymer/pull/1838) ([trevordixon](https://github.com/trevordixon))\n\n- No implicit template \\(fixes \\#1827\\) [\\#1837](https://github.com/Polymer/polymer/pull/1837) ([sjmiles](https://github.com/sjmiles))\n\n- Fix jsdoc for splice [\\#1820](https://github.com/Polymer/polymer/pull/1820) ([jscissr](https://github.com/jscissr))\n\n- Fix dynamic insertion of wrapped or redistributing content. [\\#1816](https://github.com/Polymer/polymer/pull/1816) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n- Handle NaN correctly in bindings [\\#1811](https://github.com/Polymer/polymer/pull/1811) ([azakus](https://github.com/azakus))\n\n- Fix 1752 [\\#1797](https://github.com/Polymer/polymer/pull/1797) ([sorvell](https://github.com/sorvell))\n\n- Do not apply/notify keySplices if array has not been Collectionified. Fixes \\#1744 [\\#1795](https://github.com/Polymer/polymer/pull/1795) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n- Use gulp-vulcanize concurrently for faster builds [\\#1793](https://github.com/Polymer/polymer/pull/1793) ([azakus](https://github.com/azakus))\n\n- Fixes \\#1757, do not resolve hash-only urls used for routing [\\#1780](https://github.com/Polymer/polymer/pull/1780) ([nippur72](https://github.com/nippur72))\n\n- Add `unlisten` function [\\#1740](https://github.com/Polymer/polymer/pull/1740) ([azakus](https://github.com/azakus))\n\n- Custom style fix [\\#1638](https://github.com/Polymer/polymer/pull/1638) ([sorvell](https://github.com/sorvell))\n\n## [v1.0.3](https://github.com/Polymer/polymer/tree/v1.0.3) (2015-06-05)\n\n**Closed issues:**\n\n- paper-toolbar \\[title\\] conflicts with HTML \\[title\\] [\\#1745](https://github.com/Polymer/polymer/issues/1745)\n\n- Bound data-\\* attributes being stripped from template children [\\#1737](https://github.com/Polymer/polymer/issues/1737)\n\n- Polymer.Base.splice and dom-repeat [\\#1733](https://github.com/Polymer/polymer/issues/1733)\n\n- \\[1.0.0\\] Light DOM being replaced by shady DOM on ready [\\#1732](https://github.com/Polymer/polymer/issues/1732)\n\n- \\[1.0.2\\] Databinding and nested objects [\\#1731](https://github.com/Polymer/polymer/issues/1731)\n\n- Paper-tabs in Flexbox [\\#1730](https://github.com/Polymer/polymer/issues/1730)\n\n- When not including `webcomponentsjs`, a script in `\\<head\\>` after imports will break `unresolved` attribute [\\#1723](https://github.com/Polymer/polymer/issues/1723)\n\n- Create 1.0.x Release [\\#1721](https://github.com/Polymer/polymer/issues/1721)\n\n- RENAME listeners TO events [\\#1719](https://github.com/Polymer/polymer/issues/1719)\n\n- Uncaught TypeError When splicing an array into emptiness [\\#1714](https://github.com/Polymer/polymer/issues/1714)\n\n- Paper-Button references \\<core-icon\\> [\\#1709](https://github.com/Polymer/polymer/issues/1709)\n\n- Events for paper-menu or paper-item [\\#1708](https://github.com/Polymer/polymer/issues/1708)\n\n- Why is there no javascript file? [\\#1707](https://github.com/Polymer/polymer/issues/1707)\n\n- Evergreen browser incompatibility [\\#1706](https://github.com/Polymer/polymer/issues/1706)\n\n- \\[1.0\\] shady dom inserts '\\<content\\>' more than once [\\#1704](https://github.com/Polymer/polymer/issues/1704)\n\n- Issue running Polymer Started Kit 1.0.0 [\\#1703](https://github.com/Polymer/polymer/issues/1703)\n\n- iron-form body data malformed [\\#1702](https://github.com/Polymer/polymer/issues/1702)\n\n- \\[1.0\\] Attached callback is differently resolved on chrome and ff [\\#1699](https://github.com/Polymer/polymer/issues/1699)\n\n- Polymer 1.0 and WebComponents.js [\\#1698](https://github.com/Polymer/polymer/issues/1698)\n\n- \\[dom-if\\] is not as inert as \\<template\\> should be [\\#1695](https://github.com/Polymer/polymer/issues/1695)\n\n- can't use flex inside neon-animated-pages [\\#1694](https://github.com/Polymer/polymer/issues/1694)\n\n- Polymer::Attributes: couldn`t decode Array as JSON [\\#1693](https://github.com/Polymer/polymer/issues/1693)\n\n- Mobile links off homepage dont work [\\#1692](https://github.com/Polymer/polymer/issues/1692)\n\n- Computed property doesn't work in dom-repeat [\\#1691](https://github.com/Polymer/polymer/issues/1691)\n\n- core-animated-pages any plans? [\\#1689](https://github.com/Polymer/polymer/issues/1689)\n\n- Where's paper-dropdown-menu 1.0? [\\#1684](https://github.com/Polymer/polymer/issues/1684)\n\n- \\[1.0\\] dom-repeat observe non-array values [\\#1683](https://github.com/Polymer/polymer/issues/1683)\n\n- Element catalog, google-analytics, docs missing [\\#1681](https://github.com/Polymer/polymer/issues/1681)\n\n- Binding not working for open text [\\#1677](https://github.com/Polymer/polymer/issues/1677)\n\n- Blog link in README.md and CONTRIBUTING.md is wrong [\\#1676](https://github.com/Polymer/polymer/issues/1676)\n\n- Strange lines on polymer site menu [\\#1675](https://github.com/Polymer/polymer/issues/1675)\n\n- Need to parameterize path to fonts [\\#1674](https://github.com/Polymer/polymer/issues/1674)\n\n- How to add dynamic classes in dom-repeat 1.0 [\\#1671](https://github.com/Polymer/polymer/issues/1671)\n\n- Array mutation without using helper methods [\\#1666](https://github.com/Polymer/polymer/issues/1666)\n\n- Wrapping non interpolated strings with span in 1.0 [\\#1664](https://github.com/Polymer/polymer/issues/1664)\n\n- dom-if template got rendered once even if the condition is false [\\#1663](https://github.com/Polymer/polymer/issues/1663)\n\n- Cannot read property 'slice' of undefined on firebase update [\\#1661](https://github.com/Polymer/polymer/issues/1661)\n\n- \\[1.0.2\\] Global leak found in \\_marshalArgs [\\#1660](https://github.com/Polymer/polymer/issues/1660)\n\n- \\[1.0\\] Changes in appendChild from 0.9 to 1.0? [\\#1657](https://github.com/Polymer/polymer/issues/1657)\n\n- Using scroll header panel together with dialog will cause backdrop to cover up dialog [\\#1656](https://github.com/Polymer/polymer/issues/1656)\n\n- Color Extraction [\\#1654](https://github.com/Polymer/polymer/issues/1654)\n\n- using AngularJS with paper elements [\\#1649](https://github.com/Polymer/polymer/issues/1649)\n\n- Gestures event issue - No offsets management [\\#1646](https://github.com/Polymer/polymer/issues/1646)\n\n- \\[0.9\\] event on-blur does not work on paper-input [\\#1634](https://github.com/Polymer/polymer/issues/1634)\n\n- \\[0.9.4\\] Nested dom-if templates show invalid content [\\#1632](https://github.com/Polymer/polymer/issues/1632)\n\n- paper-slider input box overflow. [\\#1611](https://github.com/Polymer/polymer/issues/1611)\n\n- \\[0.9\\] Documentation issue \\(unbind & dispose\\) [\\#1607](https://github.com/Polymer/polymer/issues/1607)\n\n- Better dependency management [\\#1592](https://github.com/Polymer/polymer/issues/1592)\n\n**Merged pull requests:**\n\n- Make \\_\\_styleScoped a one-time optimization. Fixes \\#1733 [\\#1739](https://github.com/Polymer/polymer/pull/1739) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n- Move non-webcomponents script unresolved case to `load` instead of synchronous [\\#1724](https://github.com/Polymer/polymer/pull/1724) ([azakus](https://github.com/azakus))\n\n- Fix for IE. [\\#1717](https://github.com/Polymer/polymer/pull/1717) ([achimnol](https://github.com/achimnol))\n\n- Fix broken link [\\#1688](https://github.com/Polymer/polymer/pull/1688) ([weiland](https://github.com/weiland))\n\n- Fix syntax highlighting [\\#1687](https://github.com/Polymer/polymer/pull/1687) ([weiland](https://github.com/weiland))\n\n- Fixes link license [\\#1685](https://github.com/Polymer/polymer/pull/1685) ([mateusortiz](https://github.com/mateusortiz))\n\n- fixed a little typo [\\#1682](https://github.com/Polymer/polymer/pull/1682) ([fredpedro](https://github.com/fredpedro))\n\n- fix html comment in README.md [\\#1680](https://github.com/Polymer/polymer/pull/1680) ([campersau](https://github.com/campersau))\n\n- Changed to https like other links [\\#1653](https://github.com/Polymer/polymer/pull/1653) ([henricavalcante](https://github.com/henricavalcante))\n\n- dom-if hidden state is \\(this.\\_hideTemplateChildren || !this.if\\). [\\#1635](https://github.com/Polymer/polymer/pull/1635) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n- Re-insert rows when re-attaching. Fixes \\#1498. Fixes \\#1714. [\\#1629](https://github.com/Polymer/polymer/pull/1629) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n## [v1.0.2](https://github.com/Polymer/polymer/tree/v1.0.2) (2015-05-29)\n\n## [v1.0.1](https://github.com/Polymer/polymer/tree/v1.0.1) (2015-05-29)\n\n**Implemented enhancements:**\n\n- using javascript core functions [\\#1641](https://github.com/Polymer/polymer/issues/1641)\n\n**Fixed bugs:**\n\n- \\[1.0\\] Tap gesture does not trigger when calling `this.click` in IE10 [\\#1640](https://github.com/Polymer/polymer/issues/1640)\n\n**Closed issues:**\n\n- Logic for tap distance should be \"both axes within TAP\\_DISTANCE\" [\\#1652](https://github.com/Polymer/polymer/issues/1652)\n\n- Site is not looking good in Mac Chrome Versión 43.0.2357.81 \\(64-bit\\)  [\\#1650](https://github.com/Polymer/polymer/issues/1650)\n\n- Different result is shown. [\\#1647](https://github.com/Polymer/polymer/issues/1647)\n\n- Wrong end tag name in README.md [\\#1645](https://github.com/Polymer/polymer/issues/1645)\n\n- on-tap doesn't trigger on checkbox 0.5 [\\#1586](https://github.com/Polymer/polymer/issues/1586)\n\n**Merged pull requests:**\n\n- I want to put a space before Jim. [\\#1648](https://github.com/Polymer/polymer/pull/1648) ([yutori](https://github.com/yutori))\n\n- Fixes link url [\\#1643](https://github.com/Polymer/polymer/pull/1643) ([zenorocha](https://github.com/zenorocha))\n\n- Fixes typo [\\#1642](https://github.com/Polymer/polymer/pull/1642) ([zenorocha](https://github.com/zenorocha))\n\n- updated readme and added contributing file [\\#1628](https://github.com/Polymer/polymer/pull/1628) ([tjsavage](https://github.com/tjsavage))\n\n## [v1.0.0](https://github.com/Polymer/polymer/tree/v1.0.0) (2015-05-27)\n\n**Closed issues:**\n\n- \\[0.9.4\\] Data binding works only for \"id\" attribute? [\\#1633](https://github.com/Polymer/polymer/issues/1633)\n\n- \\[0.9\\] when I move a dom-repeat element from one parent to another, the items will gone [\\#1498](https://github.com/Polymer/polymer/issues/1498)\n\n## [v0.9.4](https://github.com/Polymer/polymer/tree/v0.9.4) (2015-05-27)\n\n**Closed issues:**\n\n- Polymer.version undefined in 0.9 [\\#1625](https://github.com/Polymer/polymer/issues/1625)\n\n**Merged pull requests:**\n\n- Add back Polymer.version string [\\#1626](https://github.com/Polymer/polymer/pull/1626) ([azakus](https://github.com/azakus))\n\n## [v0.9.3](https://github.com/Polymer/polymer/tree/v0.9.3) (2015-05-26)\n\n**Closed issues:**\n\n- Property values that contain a `:` inside a mixin. [\\#1623](https://github.com/Polymer/polymer/issues/1623)\n\n- \\[0.9.2\\] dom-repeat issues in 0.9.2 [\\#1615](https://github.com/Polymer/polymer/issues/1615)\n\n- \\[0.9.1, 0.9.2\\] Polymer.dom\\(\\).appendChild\\(\\) no longer working [\\#1612](https://github.com/Polymer/polymer/issues/1612)\n\n- \\[0.9\\] \"dom-if\" not binding to an object's boolean property [\\#1606](https://github.com/Polymer/polymer/issues/1606)\n\n- \\[0.9\\] Custom attributes on elements not working \\(original: iron-icon styling troubles\\) [\\#1604](https://github.com/Polymer/polymer/issues/1604)\n\n- Blog down https://blog.polymer-project.org/  [\\#1603](https://github.com/Polymer/polymer/issues/1603)\n\n- Improve error message if observer is missing [\\#1538](https://github.com/Polymer/polymer/issues/1538)\n\n- \\[0.9\\] New gulp build hangs until enter key is pressed [\\#1519](https://github.com/Polymer/polymer/issues/1519)\n\n- \\[0.8\\] better error when bound change handler is missing [\\#1206](https://github.com/Polymer/polymer/issues/1206)\n\n**Merged pull requests:**\n\n- Fixes url's in style mixins. [\\#1624](https://github.com/Polymer/polymer/pull/1624) ([sorvell](https://github.com/sorvell))\n\n- Initialize \\_config with values set before creating accessors. [\\#1618](https://github.com/Polymer/polymer/pull/1618) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n- Update docs.  Add warnings. [\\#1614](https://github.com/Polymer/polymer/pull/1614) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n- Refactor build process [\\#1613](https://github.com/Polymer/polymer/pull/1613) ([azakus](https://github.com/azakus))\n\n## [v0.9.2](https://github.com/Polymer/polymer/tree/v0.9.2) (2015-05-25)\n\n**Fixed bugs:**\n\n- Default values for custom variables  [\\#1543](https://github.com/Polymer/polymer/issues/1543)\n\n**Closed issues:**\n\n- \\[0.9.1\\] Regression in styling with custom css mixins [\\#1601](https://github.com/Polymer/polymer/issues/1601)\n\n- Dynamic distribution fails when using SD polyfill and host is nested in another host and has filtering insertion points [\\#1595](https://github.com/Polymer/polymer/issues/1595)\n\n- Custom properties defined on `:host` shouldn't override document styles. [\\#1555](https://github.com/Polymer/polymer/issues/1555)\n\n**Merged pull requests:**\n\n- Native xstyle fix [\\#1605](https://github.com/Polymer/polymer/pull/1605) ([sorvell](https://github.com/sorvell))\n\n- Xstyle 1555 [\\#1602](https://github.com/Polymer/polymer/pull/1602) ([sorvell](https://github.com/sorvell))\n\n## [v0.9.1](https://github.com/Polymer/polymer/tree/v0.9.1) (2015-05-23)\n\n**Implemented enhancements:**\n\n- Array helpers don't notify length change [\\#1573](https://github.com/Polymer/polymer/issues/1573)\n\n- \\[0.9.0-rc.1\\] Method expression without arguments is not invoked [\\#1516](https://github.com/Polymer/polymer/issues/1516)\n\n- \\[0.8\\] Polymer.dom\\(\\) should expose innerHTML and textContent [\\#1429](https://github.com/Polymer/polymer/issues/1429)\n\n- How do you cancel job1 completely before its timeout value occur? [\\#1374](https://github.com/Polymer/polymer/issues/1374)\n\n- \\[0.8\\] Feature request: computed properties in x-repeat [\\#1337](https://github.com/Polymer/polymer/issues/1337)\n\n**Fixed bugs:**\n\n- Computed properties with no dependencies generate a syntax error [\\#1348](https://github.com/Polymer/polymer/issues/1348)\n\n- \\[0.8\\] host-context improperly shimmed [\\#1346](https://github.com/Polymer/polymer/issues/1346)\n\n**Closed issues:**\n\n- Tap event not firing the first time after tracking another element [\\#1590](https://github.com/Polymer/polymer/issues/1590)\n\n- domReady [\\#1587](https://github.com/Polymer/polymer/issues/1587)\n\n- Content tag does not work inside dom-if template [\\#1584](https://github.com/Polymer/polymer/issues/1584)\n\n- /deep/ css selector not work in chrome browser [\\#1583](https://github.com/Polymer/polymer/issues/1583)\n\n- Under native ShadowDOM \"dom-if\" doesn't stamp out the content even when \"if\" property is true [\\#1582](https://github.com/Polymer/polymer/issues/1582)\n\n- Iron-Input hint not turning into label on ChromeBook apps [\\#1581](https://github.com/Polymer/polymer/issues/1581)\n\n- Binding text remains in \\<input value=\"{{value::input}}\"\\> on IE10 [\\#1578](https://github.com/Polymer/polymer/issues/1578)\n\n- \\[0.9\\] Extends delays/breaks polymer element setup [\\#1575](https://github.com/Polymer/polymer/issues/1575)\n\n- \\[0.9\\] Gesture event throws exception when dragged outside document [\\#1574](https://github.com/Polymer/polymer/issues/1574)\n\n- dom-repeat filter/sort needs to be able to observe parent scope [\\#1572](https://github.com/Polymer/polymer/issues/1572)\n\n- Logical Operators doesn't work anymore in 0.9 [\\#1568](https://github.com/Polymer/polymer/issues/1568)\n\n- Reposted from Angular Issue \\#1723: Unable to define correct CSS @Rules when CSS shimming is enabled [\\#1566](https://github.com/Polymer/polymer/issues/1566)\n\n- \\[0.9.0\\] Problem putting a dom-if template in a light DOM when the component's \\<content\\> itself is wrapped in a dom-if [\\#1565](https://github.com/Polymer/polymer/issues/1565)\n\n- hypergrid is a polymer custom component [\\#1561](https://github.com/Polymer/polymer/issues/1561)\n\n- serializeValueToAttribute returns undefined [\\#1559](https://github.com/Polymer/polymer/issues/1559)\n\n- Offsetting core drawer panel [\\#1557](https://github.com/Polymer/polymer/issues/1557)\n\n- \\[0.9\\] How to dynamically import elements? [\\#1554](https://github.com/Polymer/polymer/issues/1554)\n\n- Release process should have change log [\\#1553](https://github.com/Polymer/polymer/issues/1553)\n\n- \\[0.9\\] on-click=\"kickAction\\(\\)\" [\\#1552](https://github.com/Polymer/polymer/issues/1552)\n\n- Layout functionality in 0.9 [\\#1551](https://github.com/Polymer/polymer/issues/1551)\n\n- \\[0.9\\] hostAttributes: Noooooooo! [\\#1549](https://github.com/Polymer/polymer/issues/1549)\n\n- \\[0.9\\] hidden$=\"{{isHidden}}\" vs hidden=$\"{{isHidden}}\" [\\#1548](https://github.com/Polymer/polymer/issues/1548)\n\n- seems that case sensitive properties doesn't work [\\#1547](https://github.com/Polymer/polymer/issues/1547)\n\n- webcomponents loading order [\\#1544](https://github.com/Polymer/polymer/issues/1544)\n\n- Data-binding to native DOM element inside of auto-binding template invokes style scoping [\\#1542](https://github.com/Polymer/polymer/issues/1542)\n\n- 0.9 zip file nearly empty [\\#1541](https://github.com/Polymer/polymer/issues/1541)\n\n- Polymer.dom\\(parent\\).querySelector polyfill is broken in 0.8 [\\#1540](https://github.com/Polymer/polymer/issues/1540)\n\n- Imported resource from origin 'file://' has been blocked from loading by Cross-Origin Resource Sharing policy: Received an invalid response. Origin 'null' is therefore not allowed access. [\\#1535](https://github.com/Polymer/polymer/issues/1535)\n\n- \\[0.9.0-rc.1\\] Cannot set property 'touchAction' of undefinedGestures.setTouchAction [\\#1533](https://github.com/Polymer/polymer/issues/1533)\n\n- Could I disable the two-way binding? [\\#1529](https://github.com/Polymer/polymer/issues/1529)\n\n- \\[0.9\\] Can't override the css property if the property is already set on the host via custom property [\\#1525](https://github.com/Polymer/polymer/issues/1525)\n\n- \\[0.5.6\\] Hang in loading polymer [\\#1524](https://github.com/Polymer/polymer/issues/1524)\n\n- \\[0.0.9-rc.1\\] Array changes event is not delivered [\\#1523](https://github.com/Polymer/polymer/issues/1523)\n\n- \\[0.9\\] dom-bind not working with document.createElement [\\#1515](https://github.com/Polymer/polymer/issues/1515)\n\n- Please, more info about new releases [\\#1507](https://github.com/Polymer/polymer/issues/1507)\n\n- \\[0.9\\] Annotated computed properties don't work on autobinding template [\\#1500](https://github.com/Polymer/polymer/issues/1500)\n\n- Upgrade from polymer 0.5 to 0.8 [\\#1492](https://github.com/Polymer/polymer/issues/1492)\n\n- \\[0.8\\] Binding a property with value 'undefined' to an input value on IE11 shows the raw binding [\\#1491](https://github.com/Polymer/polymer/issues/1491)\n\n- \\[0.8\\] SVG elements fail on IE11 due to missing classList [\\#1490](https://github.com/Polymer/polymer/issues/1490)\n\n- Cross domain HTML import [\\#1489](https://github.com/Polymer/polymer/issues/1489)\n\n- Using Polymer with NW.js [\\#1481](https://github.com/Polymer/polymer/issues/1481)\n\n- 0.9: String literals as parameters of computed properties [\\#1475](https://github.com/Polymer/polymer/issues/1475)\n\n- Inheritance of CSS Variables [\\#1470](https://github.com/Polymer/polymer/issues/1470)\n\n- support data binding with ES6 module? [\\#1465](https://github.com/Polymer/polymer/issues/1465)\n\n- \\[0.8\\] IE9 styles broken [\\#1464](https://github.com/Polymer/polymer/issues/1464)\n\n- how to get polymer and requirejs working together? [\\#1463](https://github.com/Polymer/polymer/issues/1463)\n\n- .8 domReady never being called [\\#1460](https://github.com/Polymer/polymer/issues/1460)\n\n- TODO in polymer.js references fixed bug [\\#1457](https://github.com/Polymer/polymer/issues/1457)\n\n- \\[0.8\\] Self-closing p tag breaks template [\\#1455](https://github.com/Polymer/polymer/issues/1455)\n\n- \\[0.8\\] x-repeat failing to stamp instances on safari [\\#1443](https://github.com/Polymer/polymer/issues/1443)\n\n- \\[0.8\\] `\\<content select=\".class\"\\>` and `hostAttributes` don't work together [\\#1431](https://github.com/Polymer/polymer/issues/1431)\n\n- \\[0.8\\] Binding to \"id\" is not working [\\#1426](https://github.com/Polymer/polymer/issues/1426)\n\n- Event handlers within x-repeat always target the first instance of an element [\\#1425](https://github.com/Polymer/polymer/issues/1425)\n\n- \\[0.8\\] host, port, etc are reserved for anchor elements; let's avoid them [\\#1417](https://github.com/Polymer/polymer/issues/1417)\n\n- \\[0.8\\] IE11 displays and then hides Custom Elements [\\#1412](https://github.com/Polymer/polymer/issues/1412)\n\n- \\[0.8\\] x-repeat objectizes arrays of strings [\\#1411](https://github.com/Polymer/polymer/issues/1411)\n\n- \\[0.8\\] style scope missing  [\\#1410](https://github.com/Polymer/polymer/issues/1410)\n\n- Polymer 0.8 cant bind to array item. [\\#1409](https://github.com/Polymer/polymer/issues/1409)\n\n- \\[0.8\\]\\[styling\\] Want to define custom variables in the same scope as their references  [\\#1406](https://github.com/Polymer/polymer/issues/1406)\n\n- \\[0.8\\]\\[styling\\] Should be able to mixin sibling properties [\\#1399](https://github.com/Polymer/polymer/issues/1399)\n\n- \\[0.8\\] Properties deserialized from native inputs lose their type [\\#1396](https://github.com/Polymer/polymer/issues/1396)\n\n- Shady DOM doesn't correctly parse custom property rules. [\\#1389](https://github.com/Polymer/polymer/issues/1389)\n\n- Shady DOM custom properties don't inherit. [\\#1388](https://github.com/Polymer/polymer/issues/1388)\n\n- \\[0.8\\] dom-module nice but not perfect [\\#1380](https://github.com/Polymer/polymer/issues/1380)\n\n- \\[0.8\\] notify: true Bad idea unless it has a huge performance gain [\\#1379](https://github.com/Polymer/polymer/issues/1379)\n\n- Style mixin syntax is incompatible with Sass [\\#1373](https://github.com/Polymer/polymer/issues/1373)\n\n- \\[x-repeat\\] can't bind to childNodes under Shadow DOM [\\#1367](https://github.com/Polymer/polymer/issues/1367)\n\n- \\[0.8\\] - default property values are not set by the time observers are called [\\#1364](https://github.com/Polymer/polymer/issues/1364)\n\n- \\[0.8\\]: observer callbacks changed parameter ordering [\\#1363](https://github.com/Polymer/polymer/issues/1363)\n\n- \\[0.8\\] HTMLAnchor has a `host` property, breaks the intended behavior of `Polymer.Base.\\_queryHost` [\\#1359](https://github.com/Polymer/polymer/issues/1359)\n\n- \\[0.8\\] Style scoped immediate descendant selector no longer matches projected content [\\#1312](https://github.com/Polymer/polymer/issues/1312)\n\n- Spaces in binding causes SyntaxError: Unexpected identifier. [\\#1311](https://github.com/Polymer/polymer/issues/1311)\n\n- Tracking issue: Supporting CSP in 0.8+ [\\#1306](https://github.com/Polymer/polymer/issues/1306)\n\n- \\[0.8\\] `readOnly` property without `notify` will not be `readOnly` [\\#1294](https://github.com/Polymer/polymer/issues/1294)\n\n- Shady styling increases selector specificity [\\#1279](https://github.com/Polymer/polymer/issues/1279)\n\n- \\[0.8\\] body unresolved broken [\\#1271](https://github.com/Polymer/polymer/issues/1271)\n\n- \\[0.8\\] accidental shared state in configure value? [\\#1269](https://github.com/Polymer/polymer/issues/1269)\n\n- \\[0.8\\] Properties observers registered too early [\\#1258](https://github.com/Polymer/polymer/issues/1258)\n\n- \\[0.8\\] Polymer.import missing [\\#1248](https://github.com/Polymer/polymer/issues/1248)\n\n- \\[0.8\\] Consider always assigning to native properties [\\#1226](https://github.com/Polymer/polymer/issues/1226)\n\n**Merged pull requests:**\n\n- Notify array.length changes.  Fixes \\#1573. [\\#1600](https://github.com/Polymer/polymer/pull/1600) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n- Make `dom-bind` not scope element classes. Fixes \\#1542 [\\#1599](https://github.com/Polymer/polymer/pull/1599) ([sorvell](https://github.com/sorvell))\n\n- 1565,1582,1584 fix [\\#1597](https://github.com/Polymer/polymer/pull/1597) ([sorvell](https://github.com/sorvell))\n\n- Wait until imports resolve to stamp. Fixes \\#1500 [\\#1594](https://github.com/Polymer/polymer/pull/1594) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n- Perform dom-bind work in attached/detached. Add tests. [\\#1591](https://github.com/Polymer/polymer/pull/1591) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n- Clear input.value attribute before removing for IE. Fixes \\#1491. Fixe… [\\#1589](https://github.com/Polymer/polymer/pull/1589) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n- iterate behavior mixins in reverse order as the `hasOwnProperty` chec… [\\#1588](https://github.com/Polymer/polymer/pull/1588) ([sjmiles](https://github.com/sjmiles))\n\n- serializeValueToAttribute always provokes distribute if necessary [\\#1580](https://github.com/Polymer/polymer/pull/1580) ([sorvell](https://github.com/sorvell))\n\n- Use more resilient shadowroot checking [\\#1579](https://github.com/Polymer/polymer/pull/1579) ([azakus](https://github.com/azakus))\n\n- Literal args comma fix [\\#1577](https://github.com/Polymer/polymer/pull/1577) ([sjmiles](https://github.com/sjmiles))\n\n- allow behavior arrays to contain nested behavior arrays [\\#1576](https://github.com/Polymer/polymer/pull/1576) ([sjmiles](https://github.com/sjmiles))\n\n- X style fixes [\\#1570](https://github.com/Polymer/polymer/pull/1570) ([sorvell](https://github.com/sorvell))\n\n- Fix typo in PRIMER.md [\\#1569](https://github.com/Polymer/polymer/pull/1569) ([ragingwind](https://github.com/ragingwind))\n\n- Remove unused keyCodes enum [\\#1564](https://github.com/Polymer/polymer/pull/1564) ([jklein24](https://github.com/jklein24))\n\n- Xstyle [\\#1556](https://github.com/Polymer/polymer/pull/1556) ([sorvell](https://github.com/sorvell))\n\n## [v0.9.0](https://github.com/Polymer/polymer/tree/v0.9.0) (2015-05-14)\n\n**Implemented enhancements:**\n\n- Expose dom-repeat.\\_instanceForElement [\\#1501](https://github.com/Polymer/polymer/issues/1501)\n\n**Closed issues:**\n\n- Change color of main panel [\\#1536](https://github.com/Polymer/polymer/issues/1536)\n\n- \\[0.8.0-rc.5\\] observers as an array [\\#1527](https://github.com/Polymer/polymer/issues/1527)\n\n- \\[0.9\\] Touch scroll gesture, setScrollDirection doesn't work any longer [\\#1520](https://github.com/Polymer/polymer/issues/1520)\n\n- \\[0.9\\] Data binding? [\\#1517](https://github.com/Polymer/polymer/issues/1517)\n\n- `this.$.\\*` isn't set if an element \\* is inside a `dom-if` block and the condition evaluates to true [\\#1513](https://github.com/Polymer/polymer/issues/1513)\n\n- Paper-action-dialog with backdrop disables window [\\#1509](https://github.com/Polymer/polymer/issues/1509)\n\n- How to pass data from polymer element [\\#1503](https://github.com/Polymer/polymer/issues/1503)\n\n- \\[0.9\\] auto-binding, x-repeat template not working [\\#1502](https://github.com/Polymer/polymer/issues/1502)\n\n- \\[0.9\\] if=\"{{ 1 \\< 2 }}\" not supported?! [\\#1499](https://github.com/Polymer/polymer/issues/1499)\n\n- \\[0.9\\] touch track fails on iPhone, .touchIdentifier vs .identifier [\\#1496](https://github.com/Polymer/polymer/issues/1496)\n\n- Internet Explorer 11 \"Failed to open data:text/javascript;charset=utf-8,\" [\\#1485](https://github.com/Polymer/polymer/issues/1485)\n\n- \\[0.5.5\\] Function calling is not working in custom element [\\#1484](https://github.com/Polymer/polymer/issues/1484)\n\n- \\[0.8\\] Nested insertion points lose elements after distributeContent [\\#1480](https://github.com/Polymer/polymer/issues/1480)\n\n- \\[0.8\\] Binding the value of an input box with {{value::input}} loses caret index [\\#1471](https://github.com/Polymer/polymer/issues/1471)\n\n- \\[0.8\\] Nested property binding not working on Firefox/IE [\\#1391](https://github.com/Polymer/polymer/issues/1391)\n\n- Memory Leak when using Data Bindings [\\#1116](https://github.com/Polymer/polymer/issues/1116)\n\n**Merged pull requests:**\n\n- Update to wcjs 0.7.0. [\\#1532](https://github.com/Polymer/polymer/pull/1532) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n- 0.8 negate annotated computation [\\#1528](https://github.com/Polymer/polymer/pull/1528) ([sjmiles](https://github.com/sjmiles))\n\n- Add commands to test build [\\#1522](https://github.com/Polymer/polymer/pull/1522) ([azakus](https://github.com/azakus))\n\n- Implement a minimum track distance [\\#1518](https://github.com/Polymer/polymer/pull/1518) ([azakus](https://github.com/azakus))\n\n- Process nested templates in base, parse method args for parentProps. [\\#1514](https://github.com/Polymer/polymer/pull/1514) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n- trasnacted -\\> transacted in PRIMER.md [\\#1512](https://github.com/Polymer/polymer/pull/1512) ([Shrugs](https://github.com/Shrugs))\n\n- Add missing comma in code example [\\#1510](https://github.com/Polymer/polymer/pull/1510) ([fredj](https://github.com/fredj))\n\n- 0.8 shady api [\\#1508](https://github.com/Polymer/polymer/pull/1508) ([sorvell](https://github.com/sorvell))\n\n- Fix dom-module closing tag [\\#1497](https://github.com/Polymer/polymer/pull/1497) ([fredj](https://github.com/fredj))\n\n- Add more docs for Gestures [\\#1495](https://github.com/Polymer/polymer/pull/1495) ([azakus](https://github.com/azakus))\n\n- Fix nits from \\#1486 [\\#1494](https://github.com/Polymer/polymer/pull/1494) ([azakus](https://github.com/azakus))\n\n- Change x-style to custom-style in comments [\\#1493](https://github.com/Polymer/polymer/pull/1493) ([chuckh](https://github.com/chuckh))\n\n## [v0.9.0-rc.1](https://github.com/Polymer/polymer/tree/v0.9.0-rc.1) (2015-05-06)\n\n**Merged pull requests:**\n\n- Rename x-\\* elements. [\\#1488](https://github.com/Polymer/polymer/pull/1488) ([sorvell](https://github.com/sorvell))\n\n- 0.8 lexical template scope [\\#1487](https://github.com/Polymer/polymer/pull/1487) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n- 0.8 gestures in core [\\#1486](https://github.com/Polymer/polymer/pull/1486) ([sjmiles](https://github.com/sjmiles))\n\n## [0.5.6](https://github.com/Polymer/polymer/tree/0.5.6) (2015-05-05)\n\n**Implemented enhancements:**\n\n- \\[0.8\\] `hostAttributes` should respect user-provided defaults [\\#1458](https://github.com/Polymer/polymer/issues/1458)\n\n**Closed issues:**\n\n- Unable to connect to github.com... [\\#1468](https://github.com/Polymer/polymer/issues/1468)\n\n- error using mixins as computed property or in template methods in 0.8.0-rc.7 [\\#1456](https://github.com/Polymer/polymer/issues/1456)\n\n- \\[0.8\\] observers as an object. [\\#1452](https://github.com/Polymer/polymer/issues/1452)\n\n- \\[0.8\\] getDistributedNodes\\(\\) does not update when distributed content changes [\\#1449](https://github.com/Polymer/polymer/issues/1449)\n\n- \\[0.8\\] behaviors override properties on elements [\\#1444](https://github.com/Polymer/polymer/issues/1444)\n\n- \\[0.8\\] bower.json license does not follow specification [\\#1435](https://github.com/Polymer/polymer/issues/1435)\n\n- Error in 0.8 RC6 - not present in RC4 [\\#1428](https://github.com/Polymer/polymer/issues/1428)\n\n- \\[0.8\\] Support :root in x-style [\\#1415](https://github.com/Polymer/polymer/issues/1415)\n\n- \\[0.8\\] 'style-scope undefined' when combined with hostAttributes and x-if template [\\#1400](https://github.com/Polymer/polymer/issues/1400)\n\n- \\[0.8\\] `\\<link rel=\"import\" type=\"css\"\\>` styles are shimmed out of order [\\#1349](https://github.com/Polymer/polymer/issues/1349)\n\n- Polymer 0.5.2 release have version 0.5.1 [\\#1033](https://github.com/Polymer/polymer/issues/1033)\n\n**Merged pull requests:**\n\n- 0.8 x style [\\#1482](https://github.com/Polymer/polymer/pull/1482) ([sorvell](https://github.com/sorvell))\n\n- Fix translate3d call after transform refactor [\\#1478](https://github.com/Polymer/polymer/pull/1478) ([azakus](https://github.com/azakus))\n\n- 0.8 array notification [\\#1477](https://github.com/Polymer/polymer/pull/1477) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n- don't trap `id` for marshalling if it's a binding directive + test [\\#1474](https://github.com/Polymer/polymer/pull/1474) ([sjmiles](https://github.com/sjmiles))\n\n- use `hasOwnProperty` to avoid overwriting prototype methods when mixing in behaviors \\(+test\\) [\\#1473](https://github.com/Polymer/polymer/pull/1473) ([sjmiles](https://github.com/sjmiles))\n\n- 0.8 fix xif polyfill [\\#1469](https://github.com/Polymer/polymer/pull/1469) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n- 0.8 patching [\\#1462](https://github.com/Polymer/polymer/pull/1462) ([sorvell](https://github.com/sorvell))\n\n- 0.8 api scrub [\\#1440](https://github.com/Polymer/polymer/pull/1440) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n- typo in PRIMER.md [\\#1430](https://github.com/Polymer/polymer/pull/1430) ([batista](https://github.com/batista))\n\n- Build polymer 0.8. [\\#1402](https://github.com/Polymer/polymer/pull/1402) ([garlicnation](https://github.com/garlicnation))\n\n## [v0.8.0-rc.7](https://github.com/Polymer/polymer/tree/v0.8.0-rc.7) (2015-04-22)\n\n**Closed issues:**\n\n- \\[0.8\\] `readOnly` properties do not receive the initial value specified by `value` [\\#1393](https://github.com/Polymer/polymer/issues/1393)\n\n**Merged pull requests:**\n\n- Fixes style scoping when elements are stamped inside repeats. [\\#1439](https://github.com/Polymer/polymer/pull/1439) ([sorvell](https://github.com/sorvell))\n\n- 0.8 repeat fixes [\\#1438](https://github.com/Polymer/polymer/pull/1438) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n- Change user `constructor` to `factoryImpl` as an aid to compilation tool... [\\#1437](https://github.com/Polymer/polymer/pull/1437) ([sorvell](https://github.com/sorvell))\n\n- No more circular dependencies, because bower. [\\#1436](https://github.com/Polymer/polymer/pull/1436) ([nevir](https://github.com/nevir))\n\n- 0.8 behaviors [\\#1433](https://github.com/Polymer/polymer/pull/1433) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n- defeated -\\> disabled [\\#1423](https://github.com/Polymer/polymer/pull/1423) ([MetaMemoryT](https://github.com/MetaMemoryT))\n\n## [v0.8.0-rc.6](https://github.com/Polymer/polymer/tree/v0.8.0-rc.6) (2015-04-20)\n\n## [v0.8.0-rc.5](https://github.com/Polymer/polymer/tree/v0.8.0-rc.5) (2015-04-20)\n\n**Closed issues:**\n\n- \\[0.8\\] Global settings overwritten by webcomponents [\\#1404](https://github.com/Polymer/polymer/issues/1404)\n\n- \\[0.8\\] distributeContent loses light children [\\#1394](https://github.com/Polymer/polymer/issues/1394)\n\n- \\[ShadyDOM\\] Exception when removing non-distributed nodes [\\#1366](https://github.com/Polymer/polymer/issues/1366)\n\n**Merged pull requests:**\n\n- 0.8 path effects [\\#1422](https://github.com/Polymer/polymer/pull/1422) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n- 0.8 nested template [\\#1398](https://github.com/Polymer/polymer/pull/1398) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n- 0.8 shim class [\\#1397](https://github.com/Polymer/polymer/pull/1397) ([sorvell](https://github.com/sorvell))\n\n- \\<iron-doc-viewer\\> based index for local dev [\\#1395](https://github.com/Polymer/polymer/pull/1395) ([nevir](https://github.com/nevir))\n\n- Add license to css-parse.html [\\#1378](https://github.com/Polymer/polymer/pull/1378) ([garlicnation](https://github.com/garlicnation))\n\n## [v0.8.0-rc.4](https://github.com/Polymer/polymer/tree/v0.8.0-rc.4) (2015-04-10)\n\n## [v0.8.0-rc.3](https://github.com/Polymer/polymer/tree/v0.8.0-rc.3) (2015-04-09)\n\n**Closed issues:**\n\n- Polymer-micro.html broken? [\\#1390](https://github.com/Polymer/polymer/issues/1390)\n\n- listener for DOMContentLoaded and window resize [\\#1384](https://github.com/Polymer/polymer/issues/1384)\n\n- \\[0.8\\] Opting into native Shadow DOM isn't documented [\\#1382](https://github.com/Polymer/polymer/issues/1382)\n\n- Polymer in 10 Minutes - 3. Create an app [\\#1371](https://github.com/Polymer/polymer/issues/1371)\n\n- Polymer in 10 Minutes - Reusing other elements [\\#1370](https://github.com/Polymer/polymer/issues/1370)\n\n- \\[0.5.5\\] Event fire error on safari [\\#1362](https://github.com/Polymer/polymer/issues/1362)\n\n- \\[0.8\\] importHref fails in IE/FF [\\#1343](https://github.com/Polymer/polymer/issues/1343)\n\n- Attribute Value of \"selected\" in the tutorial [\\#1228](https://github.com/Polymer/polymer/issues/1228)\n\n**Merged pull requests:**\n\n- 0.8 machined [\\#1386](https://github.com/Polymer/polymer/pull/1386) ([sorvell](https://github.com/sorvell))\n\n- Clarify concept of host to mean dom host. Related: [\\#1372](https://github.com/Polymer/polymer/pull/1372) ([sorvell](https://github.com/sorvell))\n\n## [v0.8.0-rc.2](https://github.com/Polymer/polymer/tree/v0.8.0-rc.2) (2015-04-02)\n\n**Closed issues:**\n\n- \\[0.8\\] Using one-way binding to propagate upward [\\#1360](https://github.com/Polymer/polymer/issues/1360)\n\n## [v0.8.0](https://github.com/Polymer/polymer/tree/v0.8.0) (2015-04-02)\n\n**Implemented enhancements:**\n\n- \\[Shadow DOM\\] Make Shadow DOM optional  [\\#1042](https://github.com/Polymer/polymer/issues/1042)\n\n**Closed issues:**\n\n- \\[0.8\\] extended my-input element isn't shown [\\#1350](https://github.com/Polymer/polymer/issues/1350)\n\n- Polymer function not accessible in firefox/safari [\\#1316](https://github.com/Polymer/polymer/issues/1316)\n\n**Merged pull requests:**\n\n- Fix undeclared variable exception in \\_distributeInsertionPoint. [\\#1351](https://github.com/Polymer/polymer/pull/1351) ([icetraxx](https://github.com/icetraxx))\n\n- 0.8 custom notify event [\\#1335](https://github.com/Polymer/polymer/pull/1335) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n## [v0.8.0-rc.1](https://github.com/Polymer/polymer/tree/v0.8.0-rc.1) (2015-03-26)\n\n**Fixed bugs:**\n\n- \\[0.8-preview\\] Throws exception if left-hand-side of a property binding contains a dash  [\\#1161](https://github.com/Polymer/polymer/issues/1161)\n\n- Bindings in \\<style\\> no longer work under polyfill [\\#270](https://github.com/Polymer/polymer/issues/270)\n\n**Closed issues:**\n\n- core-list needs your attention [\\#1333](https://github.com/Polymer/polymer/issues/1333)\n\n- Icons oversized on Firefox on polymer-project.org [\\#1328](https://github.com/Polymer/polymer/issues/1328)\n\n- \\[0.8\\] Unable to observe property 'hidden' [\\#1322](https://github.com/Polymer/polymer/issues/1322)\n\n- \\[0.8\\] Unexpected token \\] [\\#1298](https://github.com/Polymer/polymer/issues/1298)\n\n- \\[0.8\\] Text bindings break if parenthesis are used [\\#1297](https://github.com/Polymer/polymer/issues/1297)\n\n- \\[0.8\\] Shady style processor doesn't drop operator for ::content [\\#1293](https://github.com/Polymer/polymer/issues/1293)\n\n- Polymer layout collision with another frameworks like Angular Material [\\#1289](https://github.com/Polymer/polymer/issues/1289)\n\n- Polymer Project Site - Broken Link [\\#1288](https://github.com/Polymer/polymer/issues/1288)\n\n- core-ajax [\\#1287](https://github.com/Polymer/polymer/issues/1287)\n\n- demo portions of documentation are missing/404 [\\#1286](https://github.com/Polymer/polymer/issues/1286)\n\n- \\[0.8\\] `attached` is called at different points in lifecycle for ShadeyDOM vs ShadowDOM [\\#1285](https://github.com/Polymer/polymer/issues/1285)\n\n- \\[0.8\\] Listening to events on an element produces different results under ShadowDOM v. ShadyDOM [\\#1284](https://github.com/Polymer/polymer/issues/1284)\n\n- Attribute selectors incorrectly scoped [\\#1282](https://github.com/Polymer/polymer/issues/1282)\n\n- \\[0.8-preview\\] Shadey styles have incorrect order of precedence [\\#1277](https://github.com/Polymer/polymer/issues/1277)\n\n- \\[0.8\\] Styling scoping not working with type extension elements [\\#1275](https://github.com/Polymer/polymer/issues/1275)\n\n- Typo on website [\\#1273](https://github.com/Polymer/polymer/issues/1273)\n\n- \\[0.8-preview\\] All properties are available for data binding [\\#1262](https://github.com/Polymer/polymer/issues/1262)\n\n- \\[0.8\\] camel-case attributes do not deserialize to properties correctly. [\\#1257](https://github.com/Polymer/polymer/issues/1257)\n\n- paper-autogrow-textarea bug [\\#1255](https://github.com/Polymer/polymer/issues/1255)\n\n- \\<paper-input-decorator label=“birthday”\\> [\\#1251](https://github.com/Polymer/polymer/issues/1251)\n\n- How addEventListener in nested template? [\\#1250](https://github.com/Polymer/polymer/issues/1250)\n\n- \\<paper-input-decorator label=\"test\" autoValidate?=\"{{autoValidate}}\"\\> [\\#1249](https://github.com/Polymer/polymer/issues/1249)\n\n- Installing with Bower not working [\\#1246](https://github.com/Polymer/polymer/issues/1246)\n\n- Bower package not found [\\#1245](https://github.com/Polymer/polymer/issues/1245)\n\n- \\[0.8\\] template x-repeat throws error under native ShadowDOM [\\#1244](https://github.com/Polymer/polymer/issues/1244)\n\n- \\[0.8\\] Multiple computed properties call same method [\\#1242](https://github.com/Polymer/polymer/issues/1242)\n\n- \\[0.8\\] value binding not working in samples.html [\\#1241](https://github.com/Polymer/polymer/issues/1241)\n\n- \\[0.8\\] encapsulate and class binding not working well together [\\#1240](https://github.com/Polymer/polymer/issues/1240)\n\n- Links in SPA tutorial are broken [\\#1239](https://github.com/Polymer/polymer/issues/1239)\n\n- What is the complete Polymer Public API? [\\#1233](https://github.com/Polymer/polymer/issues/1233)\n\n- content does not get wrapped on mobile devices [\\#1221](https://github.com/Polymer/polymer/issues/1221)\n\n- BUG: web-component-tester, sauce-connect-launcher dependency [\\#1214](https://github.com/Polymer/polymer/issues/1214)\n\n- Why calling polymer.js instead of polymer.min.js? [\\#1213](https://github.com/Polymer/polymer/issues/1213)\n\n- Imperatively declared element's custom fired event does not bubble up. [\\#1212](https://github.com/Polymer/polymer/issues/1212)\n\n- \\[0.8\\] Attribute deserialization possibly busted? [\\#1208](https://github.com/Polymer/polymer/issues/1208)\n\n- \\[0.8\\] Undefined method in constructor [\\#1207](https://github.com/Polymer/polymer/issues/1207)\n\n- Typo [\\#1205](https://github.com/Polymer/polymer/issues/1205)\n\n- \\[0.8\\] x-template should provide bound values to elements' configure [\\#1200](https://github.com/Polymer/polymer/issues/1200)\n\n- Dynamically publishing attributes [\\#1198](https://github.com/Polymer/polymer/issues/1198)\n\n- Template's script doesn't execute when imported from another document \\(polyfill\\) [\\#1197](https://github.com/Polymer/polymer/issues/1197)\n\n- \\[0.8-preview\\] x-repeat standalone issue [\\#1192](https://github.com/Polymer/polymer/issues/1192)\n\n- Polymer.Import - handle 404's [\\#1184](https://github.com/Polymer/polymer/issues/1184)\n\n- Get Started Tutorial [\\#1181](https://github.com/Polymer/polymer/issues/1181)\n\n- Initialization might fail when surrounded by p-element [\\#1180](https://github.com/Polymer/polymer/issues/1180)\n\n- Why no paper-label? [\\#1174](https://github.com/Polymer/polymer/issues/1174)\n\n- Polymer \\(inline styling\\) inconsistent between Chrome and Firefox [\\#1172](https://github.com/Polymer/polymer/issues/1172)\n\n- \\[0.8-preview\\] Bespoke element constructors [\\#1151](https://github.com/Polymer/polymer/issues/1151)\n\n- \\[0.8-preview\\] detached not getting called when the element being removed is in the localDom of another element. [\\#1145](https://github.com/Polymer/polymer/issues/1145)\n\n- \\[0.8-preview\\] Boolean attribute change handlers are called before `localDom` or `lightDom` are available. [\\#1131](https://github.com/Polymer/polymer/issues/1131)\n\n- Reference to `HTMLLinkElement` in `Polymer.import` callback [\\#1127](https://github.com/Polymer/polymer/issues/1127)\n\n- 0.8-preview: multiple arguments to computed method [\\#1092](https://github.com/Polymer/polymer/issues/1092)\n\n- 0.8-preview: handle case-sensitivity problems around attributes [\\#1080](https://github.com/Polymer/polymer/issues/1080)\n\n- 0.8-preview: \"ready\" fires before \"created\"? [\\#1079](https://github.com/Polymer/polymer/issues/1079)\n\n- Wrong Bindings types documentation [\\#980](https://github.com/Polymer/polymer/issues/980)\n\n**Merged pull requests:**\n\n- update webcomponents dependency [\\#1339](https://github.com/Polymer/polymer/pull/1339) ([garlicnation](https://github.com/garlicnation))\n\n- Update bower.json to point to wcjs at 0.6.0 instead of master. [\\#1338](https://github.com/Polymer/polymer/pull/1338) ([garlicnation](https://github.com/garlicnation))\n\n- Fix typo an -\\> and [\\#1330](https://github.com/Polymer/polymer/pull/1330) ([ragingwind](https://github.com/ragingwind))\n\n- Update PRIMER.md [\\#1327](https://github.com/Polymer/polymer/pull/1327) ([mohanaravind](https://github.com/mohanaravind))\n\n- Move notify event target check to \\_notifyListener. [\\#1323](https://github.com/Polymer/polymer/pull/1323) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n- Shady DOM optimizations: \\(1\\) fast path distribution when no insertion po... [\\#1320](https://github.com/Polymer/polymer/pull/1320) ([sorvell](https://github.com/sorvell))\n\n- \\[0.8\\] Minor doc typo [\\#1313](https://github.com/Polymer/polymer/pull/1313) ([fredj](https://github.com/fredj))\n\n- \\[0.8\\] Bye bye bowerrc [\\#1310](https://github.com/Polymer/polymer/pull/1310) ([nevir](https://github.com/nevir))\n\n- 0.8 gestures [\\#1309](https://github.com/Polymer/polymer/pull/1309) ([frankiefu](https://github.com/frankiefu))\n\n- Make webcomponentsjs a bower dependency [\\#1307](https://github.com/Polymer/polymer/pull/1307) ([robdodson](https://github.com/robdodson))\n\n- Walk attributes backward to avoid IE veto on removeAttribute. [\\#1302](https://github.com/Polymer/polymer/pull/1302) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n- Update PRIMER.md [\\#1301](https://github.com/Polymer/polymer/pull/1301) ([mohanaravind](https://github.com/mohanaravind))\n\n- Separate attributes function from annotations [\\#1300](https://github.com/Polymer/polymer/pull/1300) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n- Bugfix: ReferenceError: c is not defined [\\#1295](https://github.com/Polymer/polymer/pull/1295) ([atotic](https://github.com/atotic))\n\n- Minor text edits on DOM API description [\\#1281](https://github.com/Polymer/polymer/pull/1281) ([arthurevans](https://github.com/arthurevans))\n\n- Fixes typo and broken link in PRIMER. [\\#1274](https://github.com/Polymer/polymer/pull/1274) ([batista](https://github.com/batista))\n\n- 0.8 demodulate [\\#1264](https://github.com/Polymer/polymer/pull/1264) ([sjmiles](https://github.com/sjmiles))\n\n- 0.8 property config [\\#1256](https://github.com/Polymer/polymer/pull/1256) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n- Fixed insertion of numbers and booleans in the weakmap in 0.8-preview [\\#1253](https://github.com/Polymer/polymer/pull/1253) ([cedric-marcone](https://github.com/cedric-marcone))\n\n- Unique comp props [\\#1243](https://github.com/Polymer/polymer/pull/1243) ([ssorallen](https://github.com/ssorallen))\n\n- Standardize indentation across examples in Primer [\\#1235](https://github.com/Polymer/polymer/pull/1235) ([ssorallen](https://github.com/ssorallen))\n\n- Use correct `Dom` capitalization in Primer doc [\\#1222](https://github.com/Polymer/polymer/pull/1222) ([ssorallen](https://github.com/ssorallen))\n\n- Collection repeat [\\#1215](https://github.com/Polymer/polymer/pull/1215) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n- Fix typo in PRIMER.md [\\#1204](https://github.com/Polymer/polymer/pull/1204) ([fredj](https://github.com/fredj))\n\n## [0.5.5](https://github.com/Polymer/polymer/tree/0.5.5) (2015-02-18)\n\n**Closed issues:**\n\n- Need a Polymer Core \\(team member\\) representative asap? [\\#1194](https://github.com/Polymer/polymer/issues/1194)\n\n**Merged pull requests:**\n\n- possible fix for \\[0.8-preview\\] \\#1192 [\\#1202](https://github.com/Polymer/polymer/pull/1202) ([sjmiles](https://github.com/sjmiles))\n\n- Basic test for x-template stamping [\\#1199](https://github.com/Polymer/polymer/pull/1199) ([nevir](https://github.com/nevir))\n\n## [0.5.5-rc1](https://github.com/Polymer/polymer/tree/0.5.5-rc1) (2015-02-13)\n\n**Closed issues:**\n\n- How Polymer handle elements' model communication? [\\#1187](https://github.com/Polymer/polymer/issues/1187)\n\n- Polymer is failing silently without any console error [\\#1171](https://github.com/Polymer/polymer/issues/1171)\n\n- Elements created at runtime, can't know when ready [\\#1158](https://github.com/Polymer/polymer/issues/1158)\n\n- core-dropdown-menu is ugly magugly [\\#1146](https://github.com/Polymer/polymer/issues/1146)\n\n- polymer element not compatible with IE [\\#1143](https://github.com/Polymer/polymer/issues/1143)\n\n- polymer element not compatible with IE [\\#1142](https://github.com/Polymer/polymer/issues/1142)\n\n- Please improve home site's colors [\\#1141](https://github.com/Polymer/polymer/issues/1141)\n\n- polymer element not compatible with IE [\\#1140](https://github.com/Polymer/polymer/issues/1140)\n\n- polymer element not compatible with IE [\\#1139](https://github.com/Polymer/polymer/issues/1139)\n\n- polymer element not compatible with IE [\\#1138](https://github.com/Polymer/polymer/issues/1138)\n\n- Element with id=\"exports\" results in uncaught \"Observer is not defined\" exception [\\#1134](https://github.com/Polymer/polymer/issues/1134)\n\n- Data-binding in \\<template\\> on objects attributes have strange behaviour \\[bug?\\] [\\#1129](https://github.com/Polymer/polymer/issues/1129)\n\n- tipAttribute is not working properly [\\#1126](https://github.com/Polymer/polymer/issues/1126)\n\n- IE 10+11 + data binding in inline style not working in Polymer v0.5.4 [\\#1124](https://github.com/Polymer/polymer/issues/1124)\n\n- webcomponents.min.js:11 Uncaught TypeError: undefined is not a function [\\#1122](https://github.com/Polymer/polymer/issues/1122)\n\n- TypeError: Attempting to configurable attribute of unconfigurable property. [\\#1119](https://github.com/Polymer/polymer/issues/1119)\n\n- Template with svg style url\\(\\#id\\) is shimmed with file name [\\#751](https://github.com/Polymer/polymer/issues/751)\n\n**Merged pull requests:**\n\n- 0.8 dash case [\\#1191](https://github.com/Polymer/polymer/pull/1191) ([sjmiles](https://github.com/sjmiles))\n\n- Add externs. [\\#1165](https://github.com/Polymer/polymer/pull/1165) ([garlicnation](https://github.com/garlicnation))\n\n- primer: fix module syntax [\\#1162](https://github.com/Polymer/polymer/pull/1162) ([morethanreal](https://github.com/morethanreal))\n\n- nit: fix typo in PRIMER.md [\\#1147](https://github.com/Polymer/polymer/pull/1147) ([rictic](https://github.com/rictic))\n\n- Add build script for autoclave [\\#1132](https://github.com/Polymer/polymer/pull/1132) ([azakus](https://github.com/azakus))\n\n## [0.5.4](https://github.com/Polymer/polymer/tree/0.5.4) (2015-01-24)\n\n**Closed issues:**\n\n- Dropdown Menu [\\#1118](https://github.com/Polymer/polymer/issues/1118)\n\n- Extracting an unknown archive [\\#1103](https://github.com/Polymer/polymer/issues/1103)\n\n## [0.5.3](https://github.com/Polymer/polymer/tree/0.5.3) (2015-01-21)\n\n## [0.5.3-rc2](https://github.com/Polymer/polymer/tree/0.5.3-rc2) (2015-01-21)\n\n**Closed issues:**\n\n- problems trying 0.5.3-rc [\\#1117](https://github.com/Polymer/polymer/issues/1117)\n\n- Missing e in function - Tutorial [\\#1110](https://github.com/Polymer/polymer/issues/1110)\n\n- Cannot find function or filter [\\#1102](https://github.com/Polymer/polymer/issues/1102)\n\n- core-icons:work bug [\\#1100](https://github.com/Polymer/polymer/issues/1100)\n\n- https://www.polymer-project.org/components/all-of-them/all-of-them.html [\\#1096](https://github.com/Polymer/polymer/issues/1096)\n\n- Safari is not opening the demo page of polymer [\\#1088](https://github.com/Polymer/polymer/issues/1088)\n\n- 0.8-preview: newline confuses findAnnotatedNode [\\#1078](https://github.com/Polymer/polymer/issues/1078)\n\n**Merged pull requests:**\n\n- \\[0.8\\] name -\\> is [\\#1112](https://github.com/Polymer/polymer/pull/1112) ([nevir](https://github.com/nevir))\n\n- \\[0.8\\] Fix small typos in PRIMER.md [\\#1098](https://github.com/Polymer/polymer/pull/1098) ([peterwmwong](https://github.com/peterwmwong))\n\n## [0.5.3-rc](https://github.com/Polymer/polymer/tree/0.5.3-rc) (2015-01-15)\n\n**Fixed bugs:**\n\n- Need consistent path behavior [\\#651](https://github.com/Polymer/polymer/issues/651)\n\n**Closed issues:**\n\n- Missing scrollbars, and mouse wheel not working [\\#1089](https://github.com/Polymer/polymer/issues/1089)\n\n- Very noticeable sluggishness when scrolling [\\#1084](https://github.com/Polymer/polymer/issues/1084)\n\n- Can't build 0.8-preview and there is no build information at all [\\#1075](https://github.com/Polymer/polymer/issues/1075)\n\n- paper-toggle-button and paper-checkbox events incorrectly documented [\\#1074](https://github.com/Polymer/polymer/issues/1074)\n\n- Failed to assign list scroller to scroller of headerPanel [\\#1072](https://github.com/Polymer/polymer/issues/1072)\n\n- this.$ gets polluted with shadow dom of other components [\\#1069](https://github.com/Polymer/polymer/issues/1069)\n\n- Documentation Wrong and no worked Data binding on IE11 [\\#1067](https://github.com/Polymer/polymer/issues/1067)\n\n- How to replace tag name depend on attribute? [\\#1064](https://github.com/Polymer/polymer/issues/1064)\n\n- DataBinding not full work in IE \\(polymer-0.5.2\\) [\\#1063](https://github.com/Polymer/polymer/issues/1063)\n\n- Template references in SVG not working [\\#1061](https://github.com/Polymer/polymer/issues/1061)\n\n- Docs examples missing custom element name [\\#1058](https://github.com/Polymer/polymer/issues/1058)\n\n- :host styles not rendering [\\#1057](https://github.com/Polymer/polymer/issues/1057)\n\n- Redraw menu list [\\#1054](https://github.com/Polymer/polymer/issues/1054)\n\n- fire message to other element [\\#1045](https://github.com/Polymer/polymer/issues/1045)\n\n- img width 100% event [\\#1044](https://github.com/Polymer/polymer/issues/1044)\n\n- Typo [\\#1041](https://github.com/Polymer/polymer/issues/1041)\n\n- Please hire a competent technical writer [\\#1036](https://github.com/Polymer/polymer/issues/1036)\n\n- Chrome: Faulty responsiveness if window size is instantly changed [\\#1034](https://github.com/Polymer/polymer/issues/1034)\n\n- Polymer in 10 minutes - horizontal scroll bar doesn't work in chrome [\\#1030](https://github.com/Polymer/polymer/issues/1030)\n\n- Arguments in the function expressions are not watched - binding fails [\\#1021](https://github.com/Polymer/polymer/issues/1021)\n\n- core-selector doesn't work on FF/linux for core\\_elements \\>= 5.0 [\\#1015](https://github.com/Polymer/polymer/issues/1015)\n\n- Missing web-animations-next-lite.min.js [\\#1014](https://github.com/Polymer/polymer/issues/1014)\n\n- webcomponents.js doesn't work [\\#1013](https://github.com/Polymer/polymer/issues/1013)\n\n- The main page and demos doesn't work on Firefox!!!! [\\#1007](https://github.com/Polymer/polymer/issues/1007)\n\n- Remember scroll position of selected page and prevent auto scrolling when selecting a other page. [\\#1000](https://github.com/Polymer/polymer/issues/1000)\n\n- No field view on iOS 8 [\\#986](https://github.com/Polymer/polymer/issues/986)\n\n- \\<meta name=\"layout\" content=\"polymer or some other layout2\"\\> [\\#959](https://github.com/Polymer/polymer/issues/959)\n\n- Stoped to render on firefox after .35 update \\(trying to fix jquery conflict\\) [\\#697](https://github.com/Polymer/polymer/issues/697)\n\n- on-click doesn't work with bootstrap and jQuery [\\#625](https://github.com/Polymer/polymer/issues/625)\n\n**Merged pull requests:**\n\n- Adjust to the new unit test layout [\\#1093](https://github.com/Polymer/polymer/pull/1093) ([nevir](https://github.com/nevir))\n\n- Make `ready` independent of attached state and make distribution go top-down logically and composition unwind bottom-up [\\#1039](https://github.com/Polymer/polymer/pull/1039) ([sorvell](https://github.com/sorvell))\n\n- 0.8 simplex [\\#1028](https://github.com/Polymer/polymer/pull/1028) ([sorvell](https://github.com/sorvell))\n\n- Expands the `\\<content\\>` element to remember logical DOM [\\#1017](https://github.com/Polymer/polymer/pull/1017) ([jmesserly](https://github.com/jmesserly))\n\n## [0.5.2](https://github.com/Polymer/polymer/tree/0.5.2) (2014-12-11)\n\n**Closed issues:**\n\n- Best\\(?\\) practice for loading & saving relational data [\\#1008](https://github.com/Polymer/polymer/issues/1008)\n\n- the demos don't work in  Chrome and Opera [\\#1006](https://github.com/Polymer/polymer/issues/1006)\n\n- one click triggers two  popup of paper-dropdown-menu [\\#1004](https://github.com/Polymer/polymer/issues/1004)\n\n- polymer-project.org bad link [\\#1003](https://github.com/Polymer/polymer/issues/1003)\n\n- \\[Firefox\\] \\[Regression 0.4.2 -\\> 0.5.0\\] `on-tap` event not catched [\\#997](https://github.com/Polymer/polymer/issues/997)\n\n- In Q&A, answer about hosting for tests is misleading [\\#994](https://github.com/Polymer/polymer/issues/994)\n\n- core-overlay not working on firefox 34 [\\#993](https://github.com/Polymer/polymer/issues/993)\n\n- Circular dependency between core-iconset and core-icon bower modules [\\#992](https://github.com/Polymer/polymer/issues/992)\n\n- www.polymer-project.org unusable in firefox [\\#991](https://github.com/Polymer/polymer/issues/991)\n\n- \\<core-tooltip\\> and paper-fab don't like each other. [\\#988](https://github.com/Polymer/polymer/issues/988)\n\n- Weird bug in Firefox and Safari [\\#984](https://github.com/Polymer/polymer/issues/984)\n\n- Polymer 0.5.0 for iOS 8 Console reports ReferenceError: Can't find variable: logFlags [\\#981](https://github.com/Polymer/polymer/issues/981)\n\n- 404 Documentation Link [\\#977](https://github.com/Polymer/polymer/issues/977)\n\n- scrolling over a paper-input-decorator using a touch device selects that input making it nearly impossible to scroll over paper-input fields on a mobile device [\\#973](https://github.com/Polymer/polymer/issues/973)\n\n- core-item ignores clicks on polymer-project.org in Firefox [\\#968](https://github.com/Polymer/polymer/issues/968)\n\n- https://www.polymer-project.org/platform/custom-elements.html has a 404 for the \"Shadow dom\" button [\\#967](https://github.com/Polymer/polymer/issues/967)\n\n- ZIP download missing minified webcomponents.js [\\#965](https://github.com/Polymer/polymer/issues/965)\n\n- Unable to get on-core-select to fire in paper-dropdown-menu [\\#957](https://github.com/Polymer/polymer/issues/957)\n\n- 0.5.1 Element Name could not be inferred | Safari && Mobile Safari [\\#956](https://github.com/Polymer/polymer/issues/956)\n\n- url relative path ../  not works for cross domain  link import [\\#955](https://github.com/Polymer/polymer/issues/955)\n\n- url relative path ../  not works for cross domain  link import [\\#954](https://github.com/Polymer/polymer/issues/954)\n\n- Can't get a \\<core-menu-button\\> component in \\<core-toolbar\\> to show child nodes [\\#951](https://github.com/Polymer/polymer/issues/951)\n\n- paper-autogrow text not in bower update [\\#949](https://github.com/Polymer/polymer/issues/949)\n\n- Need info how to test polymer elements using Selenium. [\\#948](https://github.com/Polymer/polymer/issues/948)\n\n- \"horizontal layout wrap\" broken in fireFox [\\#945](https://github.com/Polymer/polymer/issues/945)\n\n- Zip file is empty upon download [\\#943](https://github.com/Polymer/polymer/issues/943)\n\n- on-tap not working on Firefox [\\#941](https://github.com/Polymer/polymer/issues/941)\n\n- \\[Question\\] Using Polymer for progressive enhancement [\\#940](https://github.com/Polymer/polymer/issues/940)\n\n- Buttons not working after vulcanize [\\#935](https://github.com/Polymer/polymer/issues/935)\n\n- Dropdown Resizing [\\#930](https://github.com/Polymer/polymer/issues/930)\n\n- demo content [\\#929](https://github.com/Polymer/polymer/issues/929)\n\n- https://www.polymer-project.org/components/web-component-tester/browser.js not found [\\#928](https://github.com/Polymer/polymer/issues/928)\n\n- web-animations.html missing from web-animations-next - \\(Polymer 0.5.1\\) [\\#923](https://github.com/Polymer/polymer/issues/923)\n\n- Paper Menu button page on Polymer website shows example for paper dropdown menu not paper menu button [\\#922](https://github.com/Polymer/polymer/issues/922)\n\n- Click handlers don't work anymore on iOS with 0.5.0 [\\#918](https://github.com/Polymer/polymer/issues/918)\n\n- paper-dropdown-menu not working correctly or documentation needs update.  [\\#911](https://github.com/Polymer/polymer/issues/911)\n\n- Add API for communicating hide/show/resize from parents to interested children [\\#849](https://github.com/Polymer/polymer/issues/849)\n\n- bower install on yosemite [\\#808](https://github.com/Polymer/polymer/issues/808)\n\n- Two finger touch events - not working [\\#802](https://github.com/Polymer/polymer/issues/802)\n\n- Create a core-label, associate a label with a child focusable control [\\#793](https://github.com/Polymer/polymer/issues/793)\n\n- Not possible to stay on older version \\(0.3.5\\) [\\#758](https://github.com/Polymer/polymer/issues/758)\n\n**Merged pull requests:**\n\n- 0.8 miceplay [\\#1012](https://github.com/Polymer/polymer/pull/1012) ([kevinpschaaf](https://github.com/kevinpschaaf))\n\n- Spelling correction. [\\#996](https://github.com/Polymer/polymer/pull/996) ([germ13](https://github.com/germ13))\n\n- Use possessive \"its\" [\\#970](https://github.com/Polymer/polymer/pull/970) ([BrianGeppert](https://github.com/BrianGeppert))\n\n- README update [\\#927](https://github.com/Polymer/polymer/pull/927) ([rottina](https://github.com/rottina))\n\n## [0.5.1](https://github.com/Polymer/polymer/tree/0.5.1) (2014-11-12)\n\n**Closed issues:**\n\n- Bug on site [\\#920](https://github.com/Polymer/polymer/issues/920)\n\n- href in my element not working on iOS [\\#919](https://github.com/Polymer/polymer/issues/919)\n\n- \\[Polymer\\#0.5.0\\]\\[Safari\\] TypeError: undefined is not an object \\(evaluating 'HTMLImports.path.resolveUrlsInStyle'\\) \\(url.js line 199\\) [\\#915](https://github.com/Polymer/polymer/issues/915)\n\n- \\[Polymer\\#0.5.0\\]\\[Firefox\\] TypeError: HTMLImports.path is undefined \\(platform.js line 14\\)  [\\#914](https://github.com/Polymer/polymer/issues/914)\n\n- \\[Polymer\\#0.5.0\\]\\[Chrome\\] Uncaught TypeError: Cannot read property 'parse' of undefined \\(boot.js line 14\\) [\\#913](https://github.com/Polymer/polymer/issues/913)\n\n- web-animations-next/web-animations.html file missing [\\#909](https://github.com/Polymer/polymer/issues/909)\n\n- No release notes for 0.5.0 [\\#908](https://github.com/Polymer/polymer/issues/908)\n\n- Back button navigation sometimes broken on polymer-project website [\\#907](https://github.com/Polymer/polymer/issues/907)\n\n- Designer Tool page appears blank [\\#906](https://github.com/Polymer/polymer/issues/906)\n\n- Polymer is undefined in IE11 [\\#905](https://github.com/Polymer/polymer/issues/905)\n\n- Using polymer with Jinja2 server side templating [\\#904](https://github.com/Polymer/polymer/issues/904)\n\n- ERR\\_CONNECTION\\_CLOSED trying to visit blog.polymer-project.org [\\#894](https://github.com/Polymer/polymer/issues/894)\n\n- Consider not dirty check polling when the tab is not visible [\\#892](https://github.com/Polymer/polymer/issues/892)\n\n## [0.5.0](https://github.com/Polymer/polymer/tree/0.5.0) (2014-11-10)\n\n**Fixed bugs:**\n\n- Links to \"\\#\" get rewritten to just \"\" which causes a refresh if clicked [\\#672](https://github.com/Polymer/polymer/issues/672)\n\n**Closed issues:**\n\n- Incorrect behaviour for disabled fields with Polymer paper-input-decorator [\\#901](https://github.com/Polymer/polymer/issues/901)\n\n- Ajax responseChanged return logged twice [\\#900](https://github.com/Polymer/polymer/issues/900)\n\n- behavior difference between \\<my-component/\\> and \\<my-component\\>\\</my-component\\> [\\#899](https://github.com/Polymer/polymer/issues/899)\n\n- on-tap does not cause paper-input value to be committed [\\#890](https://github.com/Polymer/polymer/issues/890)\n\n- \\<paper-item\\> has 'iconSrc' attribute, should be 'src' like \\<paper-fab\\>, \\<paper-icon-button\\> and \\<paper-menu-button\\> [\\#889](https://github.com/Polymer/polymer/issues/889)\n\n- paper-input documentation lacks details on field validation [\\#888](https://github.com/Polymer/polymer/issues/888)\n\n- paper-input documentation inconsistently suggests theming via JS properties [\\#887](https://github.com/Polymer/polymer/issues/887)\n\n- paper-input documentation suggests html /deep/ selectors, inconsistent with other elements [\\#886](https://github.com/Polymer/polymer/issues/886)\n\n- paper-input cursor doesn't seem to support theming [\\#885](https://github.com/Polymer/polymer/issues/885)\n\n- paper-input styling instructions lack the ::shadow pseudo-element [\\#884](https://github.com/Polymer/polymer/issues/884)\n\n- paper-dropdown-menu: selectedProperty doesn't seem to work [\\#881](https://github.com/Polymer/polymer/issues/881)\n\n- Add support for native ES6 class Symbol [\\#880](https://github.com/Polymer/polymer/issues/880)\n\n- demo page fails https://www.polymer-project.org/components/core-ajax/demo.html [\\#838](https://github.com/Polymer/polymer/issues/838)\n\n- core-icon-button does but paper-icon-button does not load core-iconset-svg [\\#834](https://github.com/Polymer/polymer/issues/834)\n\n- paper-fab button href bad [\\#830](https://github.com/Polymer/polymer/issues/830)\n\n- Documentation error on core-animation [\\#828](https://github.com/Polymer/polymer/issues/828)\n\n- Data-binding within component inside template style [\\#827](https://github.com/Polymer/polymer/issues/827)\n\n- Can't scroll using mouse or keyboard [\\#817](https://github.com/Polymer/polymer/issues/817)\n\n- On-tap sends event twice on touch device [\\#814](https://github.com/Polymer/polymer/issues/814)\n\n- paper-button  raised attribute does not work properly when set programmatically [\\#812](https://github.com/Polymer/polymer/issues/812)\n\n- Trying to import core-ajax I get an appendChild on \\#document error [\\#810](https://github.com/Polymer/polymer/issues/810)\n\n- core-ajax demo not working [\\#807](https://github.com/Polymer/polymer/issues/807)\n\n- Disabled on Switch is not working [\\#806](https://github.com/Polymer/polymer/issues/806)\n\n- core-dropdown 0.4.2 not working [\\#804](https://github.com/Polymer/polymer/issues/804)\n\n- paper-button has wrong documentation [\\#801](https://github.com/Polymer/polymer/issues/801)\n\n- Importing Polymer fails, cannot find WebComponents [\\#797](https://github.com/Polymer/polymer/issues/797)\n\n- Link Tooling information  is down [\\#792](https://github.com/Polymer/polymer/issues/792)\n\n- Can't set the background color of paper-progress from javascript [\\#787](https://github.com/Polymer/polymer/issues/787)\n\n- Element stops working if taken off the DOM and put back in [\\#782](https://github.com/Polymer/polymer/issues/782)\n\n- paper drop down list showing in middle of screen first time. [\\#776](https://github.com/Polymer/polymer/issues/776)\n\n- Template repeat index value is evaluated only after loop end [\\#774](https://github.com/Polymer/polymer/issues/774)\n\n- Polymer + Cordova + PhoneGap + iOS = Very Laggy / Slow? [\\#773](https://github.com/Polymer/polymer/issues/773)\n\n- Repository error [\\#767](https://github.com/Polymer/polymer/issues/767)\n\n- problem accessing polymer properties from content script [\\#753](https://github.com/Polymer/polymer/issues/753)\n\n- Polymer as UI only [\\#752](https://github.com/Polymer/polymer/issues/752)\n\n**Merged pull requests:**\n\n- add space between \"go\" and \"to\" [\\#778](https://github.com/Polymer/polymer/pull/778) ([jodytate](https://github.com/jodytate))\n\n- Create a basic jsdoc externs file for Polymer [\\#769](https://github.com/Polymer/polymer/pull/769) ([rictic](https://github.com/rictic))\n\n## [0.4.2](https://github.com/Polymer/polymer/tree/0.4.2) (2014-10-02)\n\n**Closed issues:**\n\n- 'Flexible children' example doesn't work. [\\#772](https://github.com/Polymer/polymer/issues/772)\n\n- Google Drive Element Error in IE [\\#771](https://github.com/Polymer/polymer/issues/771)\n\n- doesn't work in a zip file [\\#766](https://github.com/Polymer/polymer/issues/766)\n\n- Paper-Dialog on page load doesnt work in firefox. [\\#761](https://github.com/Polymer/polymer/issues/761)\n\n- Extending input not working in Chromium 37.0.2062.94 Ubuntu 14.10 \\(290621\\) \\(64-bit\\) [\\#754](https://github.com/Polymer/polymer/issues/754)\n\n- core-list scroll [\\#748](https://github.com/Polymer/polymer/issues/748)\n\n- Topeka responsiveness  [\\#708](https://github.com/Polymer/polymer/issues/708)\n\n- Chrome - animation glitch [\\#593](https://github.com/Polymer/polymer/issues/593)\n\n## [0.3.6](https://github.com/Polymer/polymer/tree/0.3.6) (2014-09-18)\n\n## [0.4.1](https://github.com/Polymer/polymer/tree/0.4.1) (2014-09-18)\n\n**Implemented enhancements:**\n\n- Feature request: testing whether a custom element extends a certain type [\\#380](https://github.com/Polymer/polymer/issues/380)\n\n**Fixed bugs:**\n\n- Elements failing `instanceof` after WebComponentsReady [\\#402](https://github.com/Polymer/polymer/issues/402)\n\n**Closed issues:**\n\n- OSX Yosemite [\\#750](https://github.com/Polymer/polymer/issues/750)\n\n- File structure not the same, when using bower [\\#747](https://github.com/Polymer/polymer/issues/747)\n\n- Closing the overlay resets the position to center of window [\\#746](https://github.com/Polymer/polymer/issues/746)\n\n- noscript breaks inheritance [\\#740](https://github.com/Polymer/polymer/issues/740)\n\n- In age-slider example, using space in name results in truncated name [\\#739](https://github.com/Polymer/polymer/issues/739)\n\n- Improve documentation for core-icon when using custom icon sets [\\#738](https://github.com/Polymer/polymer/issues/738)\n\n- Broken Link in Docs/CreatingElements/AddPropertiesAndMethods [\\#737](https://github.com/Polymer/polymer/issues/737)\n\n- Miss placing script element inside a polymer element lead to miss leading error message [\\#736](https://github.com/Polymer/polymer/issues/736)\n\n- Not a BUG - FYI: Update tutorial - core-icon-button [\\#730](https://github.com/Polymer/polymer/issues/730)\n\n- FormData wrapper breaks XMLHttpRequest\\#send\\(FormData\\) in Firefox [\\#725](https://github.com/Polymer/polymer/issues/725)\n\n- Tap event does not fire for SVG elements anymore [\\#722](https://github.com/Polymer/polymer/issues/722)\n\n- Computed property can't be data-bound from outside [\\#638](https://github.com/Polymer/polymer/issues/638)\n\n- IE issues [\\#592](https://github.com/Polymer/polymer/issues/592)\n\n- ShadowDOM renderer invalidated after insertion-point distribution [\\#512](https://github.com/Polymer/polymer/issues/512)\n\n- Content inside `\\<template\\>` breaks extending `\\<body\\>` element. [\\#421](https://github.com/Polymer/polymer/issues/421)\n\n## [0.4.0](https://github.com/Polymer/polymer/tree/0.4.0) (2014-08-28)\n\n**Implemented enhancements:**\n\n- Use the John Resig inheritance to define the component prototype [\\#647](https://github.com/Polymer/polymer/issues/647)\n\n- on-\\* expression support [\\#446](https://github.com/Polymer/polymer/issues/446)\n\n- add component-laid-out lifecycle callback [\\#434](https://github.com/Polymer/polymer/issues/434)\n\n- Allow creating \\<polymer-element\\>s without Shadow DOM [\\#222](https://github.com/Polymer/polymer/issues/222)\n\n- Consider adding support for loading user selectable css resources per element [\\#219](https://github.com/Polymer/polymer/issues/219)\n\n- Provide a provide a way to instantiate the template directly into the element [\\#157](https://github.com/Polymer/polymer/issues/157)\n\n- Consider deserializing to Date from attributes, if property is Date-valued [\\#119](https://github.com/Polymer/polymer/issues/119)\n\n**Fixed bugs:**\n\n- polymer-body double fire `ready`/`created`/`attached` [\\#447](https://github.com/Polymer/polymer/issues/447)\n\n- Polymer's controller-styles system doesn't work well with ShadowDOMPolyfill [\\#224](https://github.com/Polymer/polymer/issues/224)\n\n- Globals clobbering other globals [\\#185](https://github.com/Polymer/polymer/issues/185)\n\n- `bind` boilerplate base is inflexible [\\#179](https://github.com/Polymer/polymer/issues/179)\n\n**Closed issues:**\n\n- Possible shared state on core elements. [\\#731](https://github.com/Polymer/polymer/issues/731)\n\n- paper-input element doesn't show keyboard on Firefox OS 2.0 [\\#727](https://github.com/Polymer/polymer/issues/727)\n\n- designerr on polymer page lacks demo'd functioniality from youtube quickstart. [\\#726](https://github.com/Polymer/polymer/issues/726)\n\n- PhantomJS Support [\\#724](https://github.com/Polymer/polymer/issues/724)\n\n- http://www.polymer-project.org/platform/web-animations.html [\\#721](https://github.com/Polymer/polymer/issues/721)\n\n- Polymer site appears broken on Safari 8 [\\#719](https://github.com/Polymer/polymer/issues/719)\n\n- Non ASCII strings set in JavaScript show up as ? in Firefox [\\#717](https://github.com/Polymer/polymer/issues/717)\n\n- Materials page in Polymer is not rendering correctly [\\#716](https://github.com/Polymer/polymer/issues/716)\n\n- Polymer elements not rendering in Android 4.1.2 and 4.2.1. Works on 4.4.2 [\\#714](https://github.com/Polymer/polymer/issues/714)\n\n- Bower private packages & stats [\\#711](https://github.com/Polymer/polymer/issues/711)\n\n- Step-4 of tutorial code for post-card Polymer prototype does not use element name [\\#710](https://github.com/Polymer/polymer/issues/710)\n\n- Polymer does absolutely nothing if you have an \"undeclared\" element [\\#709](https://github.com/Polymer/polymer/issues/709)\n\n- Syntax error in example bower.json [\\#707](https://github.com/Polymer/polymer/issues/707)\n\n- Semver not being followed correctly [\\#704](https://github.com/Polymer/polymer/issues/704)\n\n- Safari bug when rendering a table using nested loops [\\#700](https://github.com/Polymer/polymer/issues/700)\n\n- Clicking on Paper Tab execute twice [\\#696](https://github.com/Polymer/polymer/issues/696)\n\n- div with tool attribute does not allow flex for div within  [\\#695](https://github.com/Polymer/polymer/issues/695)\n\n- it keeps resetting [\\#694](https://github.com/Polymer/polymer/issues/694)\n\n- Handlers disappearing when you hide the template [\\#690](https://github.com/Polymer/polymer/issues/690)\n\n- on-change event triggered twice [\\#687](https://github.com/Polymer/polymer/issues/687)\n\n- Consider making core-component-page a devDependency [\\#683](https://github.com/Polymer/polymer/issues/683)\n\n- custom nodes within svg aren't created [\\#681](https://github.com/Polymer/polymer/issues/681)\n\n- App not rendering on IE and Firefox [\\#668](https://github.com/Polymer/polymer/issues/668)\n\n- Clarification on the modularity of Polymer within external web component scripts: Is Polymer designed in a way to export it as a \\(commonjs\\) module? [\\#666](https://github.com/Polymer/polymer/issues/666)\n\n- Future Support for Installing Polymer through Chocolatey package manager [\\#657](https://github.com/Polymer/polymer/issues/657)\n\n- RangeError: Maximum call stack size exceeded. On Safari 7.0.5 [\\#656](https://github.com/Polymer/polymer/issues/656)\n\n- transform-style: preserve-3d causing odd stutter on hover of custom element [\\#652](https://github.com/Polymer/polymer/issues/652)\n\n- fire should only check for null and undefined. [\\#646](https://github.com/Polymer/polymer/issues/646)\n\n- 'target' field in 'event' argument passed into callback function for click/pointer events refers to first element instantiated [\\#641](https://github.com/Polymer/polymer/issues/641)\n\n- document.querySelectorAll sluggish on Firefox \\(v30\\) for large DOM [\\#629](https://github.com/Polymer/polymer/issues/629)\n\n- TemplateBinding should warn/console log about using bind with references. [\\#615](https://github.com/Polymer/polymer/issues/615)\n\n- platform fails to load [\\#606](https://github.com/Polymer/polymer/issues/606)\n\n- Can't keyboard nav around a custom element in a div that has contenteditable=\"true\" [\\#601](https://github.com/Polymer/polymer/issues/601)\n\n- Polymer doesn't appear to work at all under iOS 8 beta 2 [\\#591](https://github.com/Polymer/polymer/issues/591)\n\n- Resources not loading in http://www.polymer-project.org/tools/designer/ [\\#585](https://github.com/Polymer/polymer/issues/585)\n\n- Unable to extend iframe [\\#580](https://github.com/Polymer/polymer/issues/580)\n\n- Custom element that performs dynamic HTML Import gets corrupted offsetWidth when used inside \\<template\\> [\\#554](https://github.com/Polymer/polymer/issues/554)\n\n- Wrap as UMD - Do not force window global [\\#534](https://github.com/Polymer/polymer/issues/534)\n\n- Difference in inherited styles between Chrome & other browsers [\\#531](https://github.com/Polymer/polymer/issues/531)\n\n- Problem during bower install [\\#529](https://github.com/Polymer/polymer/issues/529)\n\n- Adding method `childrenChanged` crashes Firefox/Safari [\\#528](https://github.com/Polymer/polymer/issues/528)\n\n- fire and asyncFire need return values [\\#527](https://github.com/Polymer/polymer/issues/527)\n\n- Errors in Safari 7 with Polymer 0.3.1 [\\#523](https://github.com/Polymer/polymer/issues/523)\n\n- Polymer not working in elementary OS [\\#520](https://github.com/Polymer/polymer/issues/520)\n\n- Two way binding with Html attribute [\\#519](https://github.com/Polymer/polymer/issues/519)\n\n- Polyfills crashing jsbin [\\#517](https://github.com/Polymer/polymer/issues/517)\n\n- Polymer breaks dependency resolution with query strings [\\#513](https://github.com/Polymer/polymer/issues/513)\n\n- binding to a builtin name fails cryptically [\\#510](https://github.com/Polymer/polymer/issues/510)\n\n- Content of nested template is empty [\\#500](https://github.com/Polymer/polymer/issues/500)\n\n- Extending Vanilla JS Custom Element with polymer-element [\\#496](https://github.com/Polymer/polymer/issues/496)\n\n- Trouble in latest Canary reading styles in attached handler of imported element [\\#493](https://github.com/Polymer/polymer/issues/493)\n\n- Keyboard Support [\\#473](https://github.com/Polymer/polymer/issues/473)\n\n- HTML Imports polyfill is missing the .import property [\\#471](https://github.com/Polymer/polymer/issues/471)\n\n- Pseudo-classes in \\<content\\> select attribute [\\#470](https://github.com/Polymer/polymer/issues/470)\n\n- Using a keyword in attribute name causes error in IE11 [\\#466](https://github.com/Polymer/polymer/issues/466)\n\n- Error - Uncaught Possible attempt to load Polymer twice  [\\#464](https://github.com/Polymer/polymer/issues/464)\n\n- Get full list of polymer-elements. [\\#460](https://github.com/Polymer/polymer/issues/460)\n\n- document.registerElement raises error \"Options missing required prototype property\" [\\#455](https://github.com/Polymer/polymer/issues/455)\n\n- Exception when updating inner child element attributes from an object property in a repeat [\\#454](https://github.com/Polymer/polymer/issues/454)\n\n- Double quotes don't work in polyfill-next-selector content [\\#453](https://github.com/Polymer/polymer/issues/453)\n\n- title attribute cause issue in firefox [\\#451](https://github.com/Polymer/polymer/issues/451)\n\n- template bind=\"x as y\" doesn't work on safari [\\#450](https://github.com/Polymer/polymer/issues/450)\n\n- Generating an observe block in created or ready doesn't bind [\\#448](https://github.com/Polymer/polymer/issues/448)\n\n- \\<polymer-ui-accordion\\> doesn't always work with Shadow DOM polyfill [\\#444](https://github.com/Polymer/polymer/issues/444)\n\n- Polymer breaks `instanceof` for native elements. [\\#424](https://github.com/Polymer/polymer/issues/424)\n\n- Add @license tag [\\#413](https://github.com/Polymer/polymer/issues/413)\n\n- Can't turn body into custom element via is=\"...\" [\\#409](https://github.com/Polymer/polymer/issues/409)\n\n- bindProperties logger call refers to nonexistent variables [\\#406](https://github.com/Polymer/polymer/issues/406)\n\n- Polymer fails to render elements when query string contains a slash [\\#401](https://github.com/Polymer/polymer/issues/401)\n\n- Using native CustomElements and ShadowDOM polyfill together may cause unwanted attached/detached callbacks being called [\\#399](https://github.com/Polymer/polymer/issues/399)\n\n- Variable picked by `constructor` attribute is set after upgrade events. [\\#398](https://github.com/Polymer/polymer/issues/398)\n\n- Exception when invoking super from ready when the node is created by \\<template repeat\\> [\\#397](https://github.com/Polymer/polymer/issues/397)\n\n- automatic node finding within a template-if [\\#387](https://github.com/Polymer/polymer/issues/387)\n\n- Challenges of building a menu system in Polymer [\\#382](https://github.com/Polymer/polymer/issues/382)\n\n- XSS Vulnerability [\\#375](https://github.com/Polymer/polymer/issues/375)\n\n- Publishing an attribute named 'disabled' generates exception in IE10 [\\#372](https://github.com/Polymer/polymer/issues/372)\n\n- template if expression, trailing blanks should be ignored [\\#370](https://github.com/Polymer/polymer/issues/370)\n\n- processing bindings in a specific order [\\#368](https://github.com/Polymer/polymer/issues/368)\n\n- AngularJS incompatibility: need to unwrap elements when jqLite.data\\(\\) is used [\\#363](https://github.com/Polymer/polymer/issues/363)\n\n- Polymer makes getScreenCTM\\(\\) crash [\\#351](https://github.com/Polymer/polymer/issues/351)\n\n- Sorting an array can result in an \\*Changed method firing [\\#350](https://github.com/Polymer/polymer/issues/350)\n\n- Reentrancy question: reflectPropertyToAttribute can trigger unwanted attributedChanged effects [\\#349](https://github.com/Polymer/polymer/issues/349)\n\n- ShadowDOMPolyfill is way, way too intrusive!  [\\#346](https://github.com/Polymer/polymer/issues/346)\n\n- Separate out platform.js from polymer core [\\#344](https://github.com/Polymer/polymer/issues/344)\n\n- Attribute values should be copied to property values before `created` [\\#342](https://github.com/Polymer/polymer/issues/342)\n\n- custom event handler matching is case sensitive [\\#340](https://github.com/Polymer/polymer/issues/340)\n\n- Fragments in links get rewritten to point to directory of import [\\#339](https://github.com/Polymer/polymer/issues/339)\n\n- Address polymer-elements that take child elements [\\#337](https://github.com/Polymer/polymer/issues/337)\n\n- Declarative event discovery on custom elements [\\#336](https://github.com/Polymer/polymer/issues/336)\n\n- test-button element class with extends=\"button\" can't be instantiated with \\<test-button\\> syntax [\\#334](https://github.com/Polymer/polymer/issues/334)\n\n- Page rendering issue - navigation [\\#333](https://github.com/Polymer/polymer/issues/333)\n\n- Cannot modify a template's contents while it is stamping [\\#330](https://github.com/Polymer/polymer/issues/330)\n\n- Publish sub-projects on npm, add them to package.json. [\\#326](https://github.com/Polymer/polymer/issues/326)\n\n- stack: \"TypeError: Object \\#\\<Object\\> has no method 'getAttr [\\#325](https://github.com/Polymer/polymer/issues/325)\n\n- Support angular/django style filters [\\#323](https://github.com/Polymer/polymer/issues/323)\n\n- createElement-wrapped \\<img\\> throws TypeError on \\<canvas\\> drawImage [\\#316](https://github.com/Polymer/polymer/issues/316)\n\n- Databinding breaks after removing and reattaching an element to the DOM [\\#311](https://github.com/Polymer/polymer/issues/311)\n\n- Ensure {{}} are removed after binding [\\#304](https://github.com/Polymer/polymer/issues/304)\n\n- Getting started instructions incomplete: no polymer.min.js  [\\#300](https://github.com/Polymer/polymer/issues/300)\n\n- Site is not showing properly in IE11 [\\#299](https://github.com/Polymer/polymer/issues/299)\n\n- Prevent event bubbling in polyfill [\\#296](https://github.com/Polymer/polymer/issues/296)\n\n- Prevent duplicate ID's in polyfill [\\#295](https://github.com/Polymer/polymer/issues/295)\n\n- remove use of deprecated cancelBubble? [\\#292](https://github.com/Polymer/polymer/issues/292)\n\n- Polymer throws error in Canary when registering an element via import [\\#290](https://github.com/Polymer/polymer/issues/290)\n\n- Type Convert Error when work with canvas [\\#288](https://github.com/Polymer/polymer/issues/288)\n\n- DOM Spec Input - Virtual MutationRecords [\\#281](https://github.com/Polymer/polymer/issues/281)\n\n- polymer animation not support ios [\\#279](https://github.com/Polymer/polymer/issues/279)\n\n- Event.cancelBubble cannot be used for stopping event propagation in Polymer [\\#275](https://github.com/Polymer/polymer/issues/275)\n\n- Consider removing controllerStyles and requiring explicitly adding stylesheets [\\#272](https://github.com/Polymer/polymer/issues/272)\n\n- Write up suggestions on dealing with performance [\\#269](https://github.com/Polymer/polymer/issues/269)\n\n- improve on-\\* delegation by introducing control for Polymer-bubbling \\(as distinct from DOM bubbling\\) [\\#259](https://github.com/Polymer/polymer/issues/259)\n\n- Consider issuing a warning when a polymer-element's shadowRoot contains un-upgraded custom elements [\\#258](https://github.com/Polymer/polymer/issues/258)\n\n- on-tap doesn't fire all the time that on-click does [\\#255](https://github.com/Polymer/polymer/issues/255)\n\n- Chrome Packaged App: including the UI elements is not convenient [\\#248](https://github.com/Polymer/polymer/issues/248)\n\n- Polymer doesn't work on Iceweasel web browser [\\#247](https://github.com/Polymer/polymer/issues/247)\n\n- It's confusing that you need to nest a \\<template repeat\\> inside an outermost \\<template\\>. [\\#245](https://github.com/Polymer/polymer/issues/245)\n\n- http://www.polymer-project.org/tooling-strategy.html is a bit spare [\\#244](https://github.com/Polymer/polymer/issues/244)\n\n- documentation for attributeChanged is wrong [\\#242](https://github.com/Polymer/polymer/issues/242)\n\n- Using scoped models impacts 2-way property binding [\\#220](https://github.com/Polymer/polymer/issues/220)\n\n- loader seems to fail at random, but frequently when serving from localhost [\\#218](https://github.com/Polymer/polymer/issues/218)\n\n- Cloned attributes should not override user attributes in markup [\\#190](https://github.com/Polymer/polymer/issues/190)\n\n- Sugaring dynamics in ShadowDOM [\\#176](https://github.com/Polymer/polymer/issues/176)\n\n- Asynchronous attribute declaration [\\#160](https://github.com/Polymer/polymer/issues/160)\n\n- Consider adding broadcast [\\#145](https://github.com/Polymer/polymer/issues/145)\n\n- explore performance impact of import-order of components [\\#108](https://github.com/Polymer/polymer/issues/108)\n\n- title attribute [\\#97](https://github.com/Polymer/polymer/issues/97)\n\n- Write doc about attributes and type inference when applying to properties [\\#93](https://github.com/Polymer/polymer/issues/93)\n\n- Confusing cancelBubble  [\\#74](https://github.com/Polymer/polymer/issues/74)\n\n## [0.3.5](https://github.com/Polymer/polymer/tree/0.3.5) (2014-08-08)\n\n**Closed issues:**\n\n- Internet explorer is not binding inside \\<select\\> tag [\\#692](https://github.com/Polymer/polymer/issues/692)\n\n- \\<core-collapse\\> syntax issue. [\\#689](https://github.com/Polymer/polymer/issues/689)\n\n- TemplateBinding.js Uncaught HierarchyRequestError [\\#688](https://github.com/Polymer/polymer/issues/688)\n\n- TypeError: Argument 1 of Window.getDefaultComputedStyle does not implement interface Element [\\#686](https://github.com/Polymer/polymer/issues/686)\n\n- Not working in Safari - Window [\\#682](https://github.com/Polymer/polymer/issues/682)\n\n- Polymer should respect XHTML syntax [\\#680](https://github.com/Polymer/polymer/issues/680)\n\n- polymer design tool issue [\\#679](https://github.com/Polymer/polymer/issues/679)\n\n- Incomplete zip files. [\\#676](https://github.com/Polymer/polymer/issues/676)\n\n- Polymer Designer always deletes everything [\\#674](https://github.com/Polymer/polymer/issues/674)\n\n- Wrong import path on Designer Preview when importing polymer.html [\\#670](https://github.com/Polymer/polymer/issues/670)\n\n- error 404 on core-transition demo page  [\\#669](https://github.com/Polymer/polymer/issues/669)\n\n- Polymer site is not reachable. [\\#667](https://github.com/Polymer/polymer/issues/667)\n\n- TypeError and NetworkError when starting the designer tool from the url [\\#665](https://github.com/Polymer/polymer/issues/665)\n\n- Scroll disappearing on Polymer Website [\\#661](https://github.com/Polymer/polymer/issues/661)\n\n- paper-menu-button is not responsive [\\#660](https://github.com/Polymer/polymer/issues/660)\n\n- Core-drawer-panel hardcoded drawer width [\\#659](https://github.com/Polymer/polymer/issues/659)\n\n- the BSD license link at the bottom of http://www.polymer-project.org/ is a 404 [\\#655](https://github.com/Polymer/polymer/issues/655)\n\n- Polymer breaks URL [\\#653](https://github.com/Polymer/polymer/issues/653)\n\n- Cannot install polymer 0.3.4 [\\#643](https://github.com/Polymer/polymer/issues/643)\n\n- Polymer breaks KnockoutJS outside of Chrome [\\#640](https://github.com/Polymer/polymer/issues/640)\n\n- Paper button keeps flashing [\\#639](https://github.com/Polymer/polymer/issues/639)\n\n- \\<core-style\\> should use an element that parses in plain text mode [\\#637](https://github.com/Polymer/polymer/issues/637)\n\n- \"Assertion Failed\" unwrapping event [\\#636](https://github.com/Polymer/polymer/issues/636)\n\n- Rating Slider Knob goes outside boundaries [\\#635](https://github.com/Polymer/polymer/issues/635)\n\n- typo on http://www.polymer-project.org/docs/elements/paper-elements.html\\#paper-menu-button [\\#632](https://github.com/Polymer/polymer/issues/632)\n\n- core-list is inefficient in data initialization [\\#631](https://github.com/Polymer/polymer/issues/631)\n\n- Closing tags with /\\> leads to ignored shadow DOM content [\\#628](https://github.com/Polymer/polymer/issues/628)\n\n- Paper Elements use inline scripts =\\> violate Chrome packaged app CSP rules [\\#613](https://github.com/Polymer/polymer/issues/613)\n\n- paper-tab::shadow \\#ink glitches when click is held [\\#611](https://github.com/Polymer/polymer/issues/611)\n\n- Core-toolbar breaking material design speck [\\#605](https://github.com/Polymer/polymer/issues/605)\n\n- \\<input list=\"x\"\\>\\<datalist id=\"x\"\\> as a component used within another component [\\#600](https://github.com/Polymer/polymer/issues/600)\n\n- core-scroll-header-panel won't hide navigation bar on Android \\(stable and beta\\) [\\#569](https://github.com/Polymer/polymer/issues/569)\n\n- Scroll Header Panel flowing over panel scroll bar [\\#555](https://github.com/Polymer/polymer/issues/555)\n\n- Drawer Panel is not working. [\\#550](https://github.com/Polymer/polymer/issues/550)\n\n- Polymer 0.2.2 polymer-animation-group.js logs error to console [\\#463](https://github.com/Polymer/polymer/issues/463)\n\n- polymer-ui-scaffold and polymer-ui-nav-arrow [\\#343](https://github.com/Polymer/polymer/issues/343)\n\n- Better error when creating an element without a hyphenated name [\\#303](https://github.com/Polymer/polymer/issues/303)\n\n- polymer-ajax fails silently when json is not valid json [\\#257](https://github.com/Polymer/polymer/issues/257)\n\n## [0.3.4](https://github.com/Polymer/polymer/tree/0.3.4) (2014-07-11)\n\n**Fixed bugs:**\n\n- FormData.constructor fails when passed HTMLFormElement in Firefox [\\#587](https://github.com/Polymer/polymer/issues/587)\n\n**Closed issues:**\n\n- Paper component focusable demo missing [\\#624](https://github.com/Polymer/polymer/issues/624)\n\n- Step 1 of Tutorial incomplete [\\#623](https://github.com/Polymer/polymer/issues/623)\n\n- Step-1 of tutorial instructions are missing vital CSS [\\#622](https://github.com/Polymer/polymer/issues/622)\n\n- Link on paper-tabs for paper-tab is broken [\\#621](https://github.com/Polymer/polymer/issues/621)\n\n- Wrong example in polymer tutorial [\\#618](https://github.com/Polymer/polymer/issues/618)\n\n- Please improve the Core Elements / Scaffold example [\\#617](https://github.com/Polymer/polymer/issues/617)\n\n- Polymer demos are not working in android stock browser and polymer is not working in cordova apps in JellyBean and prior versions. It is throwing \"Window is not defined error in platform.js file at line number 15\". [\\#616](https://github.com/Polymer/polymer/issues/616)\n\n- Chrome Packaged App: Refused to evaluate a string as JavaScript because 'unsafe-eval' [\\#612](https://github.com/Polymer/polymer/issues/612)\n\n- Broken doc in 'using core icons [\\#610](https://github.com/Polymer/polymer/issues/610)\n\n- Navigation menu error [\\#609](https://github.com/Polymer/polymer/issues/609)\n\n- IE 11 issues [\\#608](https://github.com/Polymer/polymer/issues/608)\n\n- deadlink in polymer site [\\#604](https://github.com/Polymer/polymer/issues/604)\n\n- extjs and polymerjs [\\#603](https://github.com/Polymer/polymer/issues/603)\n\n- Mistake on proto-element.html [\\#602](https://github.com/Polymer/polymer/issues/602)\n\n- paper-slider does not work properly in Safari and FireFox [\\#599](https://github.com/Polymer/polymer/issues/599)\n\n- Polymer designer color-picker has no specific color palette [\\#598](https://github.com/Polymer/polymer/issues/598)\n\n- Paper Elements Input does not work on iOS [\\#596](https://github.com/Polymer/polymer/issues/596)\n\n- Core-Transition Demo  [\\#594](https://github.com/Polymer/polymer/issues/594)\n\n- Starting a webserver in Python [\\#590](https://github.com/Polymer/polymer/issues/590)\n\n- simple style attribute bindings and styleObject filter not working in IE11 \\(maybe other versions as well\\) [\\#589](https://github.com/Polymer/polymer/issues/589)\n\n- Images not rendering in the demp app tutorial [\\#588](https://github.com/Polymer/polymer/issues/588)\n\n- Core-transition demo link returns 404 [\\#586](https://github.com/Polymer/polymer/issues/586)\n\n- Paper-Checkbox Animation Fix [\\#584](https://github.com/Polymer/polymer/issues/584)\n\n- Designer will not save [\\#583](https://github.com/Polymer/polymer/issues/583)\n\n- ::content polyfill for VanillaJS Templates and Custom Elements [\\#582](https://github.com/Polymer/polymer/issues/582)\n\n- core-transition-css Error: Not Found [\\#581](https://github.com/Polymer/polymer/issues/581)\n\n- Polymer Tutorial step 1 multiple core-select events [\\#578](https://github.com/Polymer/polymer/issues/578)\n\n- Material design link is broken [\\#577](https://github.com/Polymer/polymer/issues/577)\n\n- core-scroll-header-panel background missing? [\\#576](https://github.com/Polymer/polymer/issues/576)\n\n- Can't get any of the demos work?? [\\#575](https://github.com/Polymer/polymer/issues/575)\n\n- paper-elements.html not found [\\#574](https://github.com/Polymer/polymer/issues/574)\n\n- Tutorial Typo [\\#572](https://github.com/Polymer/polymer/issues/572)\n\n- tutorial step-2: missing slash on closing div tag [\\#571](https://github.com/Polymer/polymer/issues/571)\n\n- Minor Duplication: unnecessary core-icon-button declaration block to style the fill color of the favorite icon  [\\#570](https://github.com/Polymer/polymer/issues/570)\n\n- Layout Messed  [\\#568](https://github.com/Polymer/polymer/issues/568)\n\n- Chromebook [\\#565](https://github.com/Polymer/polymer/issues/565)\n\n- \\[Docs\\]  The \"Learn\" page on polymer-project.org crashes Safari Mobile [\\#563](https://github.com/Polymer/polymer/issues/563)\n\n- core-scroll-header-panel won't hide nav bar on Chrome for Android [\\#562](https://github.com/Polymer/polymer/issues/562)\n\n- Polymer flat design phonegap [\\#560](https://github.com/Polymer/polymer/issues/560)\n\n- Input examples do not work in iPad iOS 7.1.1 [\\#558](https://github.com/Polymer/polymer/issues/558)\n\n- Demo & Edit on GitHub links not working on component page [\\#557](https://github.com/Polymer/polymer/issues/557)\n\n- Download link for checkboxes is broken [\\#556](https://github.com/Polymer/polymer/issues/556)\n\n- core-slide demo not found [\\#553](https://github.com/Polymer/polymer/issues/553)\n\n- Polymer website side panel menus overlaps url: http://www.polymer-project.org/docs/start/tutorial/intro.html [\\#552](https://github.com/Polymer/polymer/issues/552)\n\n- document.querySelector containing ::shadow fails in Firefox 30 [\\#551](https://github.com/Polymer/polymer/issues/551)\n\n- docs-menu polymer-ui-menu { position: fixed; } - Mozilla Firefox 30.0 [\\#549](https://github.com/Polymer/polymer/issues/549)\n\n- Invalid Zip File [\\#547](https://github.com/Polymer/polymer/issues/547)\n\n- http://www.polymer-project.org/docs/elements/core-elements.html\\#core-overlay-layer links to 404 page not found [\\#546](https://github.com/Polymer/polymer/issues/546)\n\n- Polymer docs gives wrong information [\\#545](https://github.com/Polymer/polymer/issues/545)\n\n- Can't open .zip files.. [\\#544](https://github.com/Polymer/polymer/issues/544)\n\n- \\[docs tutorial\\] step 3 code sample post-service closing tag [\\#543](https://github.com/Polymer/polymer/issues/543)\n\n- All of the top menu functionalities are not working [\\#542](https://github.com/Polymer/polymer/issues/542)\n\n- Sidebar menu elements are overlaid [\\#541](https://github.com/Polymer/polymer/issues/541)\n\n- Edit on GitHub Link returning 404 error [\\#540](https://github.com/Polymer/polymer/issues/540)\n\n- rendering problems with new website in FF on osx [\\#539](https://github.com/Polymer/polymer/issues/539)\n\n- \\[Docs\\] polymer-ui-menu on docs page doesn't seem to be displaying correctly, Chromium and Firefox [\\#538](https://github.com/Polymer/polymer/issues/538)\n\n- I think I found a mistake in the tutorial, not sure where to put it... [\\#536](https://github.com/Polymer/polymer/issues/536)\n\n- \\[In Docs\\] Wrong link in \"Demo\" button [\\#535](https://github.com/Polymer/polymer/issues/535)\n\n- I think seed-element shouldn't advise ignoring .bowerrc [\\#533](https://github.com/Polymer/polymer/issues/533)\n\n- The trouble with the now-deprecated applyAuthorStyles in Polymer Elements [\\#532](https://github.com/Polymer/polymer/issues/532)\n\n- Polymer does not display cyrillic characters correctly [\\#498](https://github.com/Polymer/polymer/issues/498)\n\n## [0.3.3](https://github.com/Polymer/polymer/tree/0.3.3) (2014-06-20)\n\n**Closed issues:**\n\n-  `stopPropagation\\(\\)` does not work for polymer events [\\#530](https://github.com/Polymer/polymer/issues/530)\n\n- bower.json missing \"main\" and \"moduleType\" [\\#525](https://github.com/Polymer/polymer/issues/525)\n\n- Published property with default value not reflected [\\#509](https://github.com/Polymer/polymer/issues/509)\n\n## [0.3.2](https://github.com/Polymer/polymer/tree/0.3.2) (2014-06-09)\n\n**Closed issues:**\n\n- Since 0.3.0 binding array elements doesn't work [\\#526](https://github.com/Polymer/polymer/issues/526)\n\n- minor documentation content issue [\\#522](https://github.com/Polymer/polymer/issues/522)\n\n- `\\<content select=\".test\"\\>` is not observing condition updates of child elements? [\\#505](https://github.com/Polymer/polymer/issues/505)\n\n## [0.3.1](https://github.com/Polymer/polymer/tree/0.3.1) (2014-05-30)\n\n**Closed issues:**\n\n- Bind to `value` on `\\<input type=\"color\"\\>` [\\#521](https://github.com/Polymer/polymer/issues/521)\n\n- classList not working anymore [\\#518](https://github.com/Polymer/polymer/issues/518)\n\n## [0.3.0](https://github.com/Polymer/polymer/tree/0.3.0) (2014-05-27)\n\n**Implemented enhancements:**\n\n- Add Polymer.version [\\#227](https://github.com/Polymer/polymer/issues/227)\n\n**Closed issues:**\n\n- Source Code Sandbox  - Web Components en action - Google I / O 2013 [\\#516](https://github.com/Polymer/polymer/issues/516)\n\n- Adding an event handler in an event handler can lead to infinite looping [\\#511](https://github.com/Polymer/polymer/issues/511)\n\n- Polymer alters the results of scoped queries in querySelectorAll [\\#508](https://github.com/Polymer/polymer/issues/508)\n\n- A non-body element marked \"unresolved\" still gets shown during boot [\\#507](https://github.com/Polymer/polymer/issues/507)\n\n- When running Parse.FacebookUtils.init Polymer raises InvalidCharacterError exception. [\\#506](https://github.com/Polymer/polymer/issues/506)\n\n- Content incorrectly rendered inside table. [\\#503](https://github.com/Polymer/polymer/issues/503)\n\n- 404 on polymer-project.org/docs/start/customelements\\#elementtypes  [\\#499](https://github.com/Polymer/polymer/issues/499)\n\n- Chrome Packaged App: Refused to evaluate a string as JavaScript because 'unsafe-eval' .... [\\#252](https://github.com/Polymer/polymer/issues/252)\n\n- on-\\* event delegation \\(other than on host node\\) does not work with non-bubbling events [\\#208](https://github.com/Polymer/polymer/issues/208)\n\n## [0.2.4](https://github.com/Polymer/polymer/tree/0.2.4) (2014-05-12)\n\n**Closed issues:**\n\n- Mongolian vowel separator causing exceptions. [\\#495](https://github.com/Polymer/polymer/issues/495)\n\n- Problem with root-relative URLs and the History API [\\#494](https://github.com/Polymer/polymer/issues/494)\n\n- Standalone template binding docs missing? [\\#491](https://github.com/Polymer/polymer/issues/491)\n\n- unable to use Polymer's dom mutation observer polyfill with mutation summary library [\\#490](https://github.com/Polymer/polymer/issues/490)\n\n- I guess there is a mistake in polymer documentation [\\#489](https://github.com/Polymer/polymer/issues/489)\n\n- Unclear how to bind complex data objects  to new instances of polymer-element as a passed-in attribute [\\#488](https://github.com/Polymer/polymer/issues/488)\n\n- Update expressions doc to clarify what's observed [\\#486](https://github.com/Polymer/polymer/issues/486)\n\n- on-change doesn't get triggered when change happens programmatically [\\#484](https://github.com/Polymer/polymer/issues/484)\n\n- style=\"color:{{person.nameColor}}\" does not work in IE11 [\\#483](https://github.com/Polymer/polymer/issues/483)\n\n- Publish a property by listing it in the `attributes` fails [\\#482](https://github.com/Polymer/polymer/issues/482)\n\n- Can't get polymer 0.2.3 via bower \\(now\\) [\\#481](https://github.com/Polymer/polymer/issues/481)\n\n- bower out of date? [\\#480](https://github.com/Polymer/polymer/issues/480)\n\n- Crash when Polymer/Platform loaded twice [\\#478](https://github.com/Polymer/polymer/issues/478)\n\n- Can't dynamically import an element definition in Canary [\\#477](https://github.com/Polymer/polymer/issues/477)\n\n- Middle clicking results in navigation not new tab [\\#472](https://github.com/Polymer/polymer/issues/472)\n\n## [0.2.3](https://github.com/Polymer/polymer/tree/0.2.3) (2014-04-18)\n\n**Fixed bugs:**\n\n- Including platform.js breaks YouTube's iframe API [\\#468](https://github.com/Polymer/polymer/issues/468)\n\n**Closed issues:**\n\n- Custom pseudo-elements cannot be targeted outside shadow dom [\\#475](https://github.com/Polymer/polymer/issues/475)\n\n- document.registerElement\\('foo', {extends: undefined}\\) fails [\\#462](https://github.com/Polymer/polymer/issues/462)\n\n- onBeforeUnload Event broken [\\#461](https://github.com/Polymer/polymer/issues/461)\n\n## [0.2.2](https://github.com/Polymer/polymer/tree/0.2.2) (2014-03-31)\n\n**Implemented enhancements:**\n\n- Consider inferring polymer-element tag name for registration [\\#195](https://github.com/Polymer/polymer/issues/195)\n\n**Closed issues:**\n\n- Reusing css libraries through out Polymer elements [\\#459](https://github.com/Polymer/polymer/issues/459)\n\n- Meta: Shadow DOM styling renames [\\#458](https://github.com/Polymer/polymer/issues/458)\n\n- Compatibility with Angular JS - manual bootstrap fails on document.body and document.documentElement when using Platform.js  [\\#457](https://github.com/Polymer/polymer/issues/457)\n\n- Problem with data binding and custom attributes in Firefox 27, 29. [\\#456](https://github.com/Polymer/polymer/issues/456)\n\n-  addEventListener beforeunload not working [\\#445](https://github.com/Polymer/polymer/issues/445)\n\n- Having any \\<link rel=\"stylesheet\"\\> makes entire app fail to initialize [\\#441](https://github.com/Polymer/polymer/issues/441)\n\n- Issues with platform version resolution with Bower and 0.2.1 [\\#440](https://github.com/Polymer/polymer/issues/440)\n\n- Polymer event bindings don't pass Firefox Marketplace CSP checks [\\#439](https://github.com/Polymer/polymer/issues/439)\n\n- Iterating over a member object [\\#436](https://github.com/Polymer/polymer/issues/436)\n\n- \\<template if\\> evaluating all expressions twice [\\#433](https://github.com/Polymer/polymer/issues/433)\n\n- Remove support for applyAuthorStyles/resetStyleInheritance [\\#425](https://github.com/Polymer/polymer/issues/425)\n\n- Conflicts with Revealjs style sheets [\\#410](https://github.com/Polymer/polymer/issues/410)\n\n- Bower install broken for latest and \\#0.1.3 [\\#407](https://github.com/Polymer/polymer/issues/407)\n\n- Add organization logo [\\#361](https://github.com/Polymer/polymer/issues/361)\n\n- Add a declarative way to set applyAuthorStyles on a element's shadowRoot [\\#106](https://github.com/Polymer/polymer/issues/106)\n\n## [0.2.1](https://github.com/Polymer/polymer/tree/0.2.1) (2014-03-07)\n\n**Closed issues:**\n\n- attributeChanged is not called under some circumstances [\\#438](https://github.com/Polymer/polymer/issues/438)\n\n- Add polyfill support for new Shadow DOM CSS cominbators [\\#435](https://github.com/Polymer/polymer/issues/435)\n\n- Problem with special characters and HTML entities [\\#432](https://github.com/Polymer/polymer/issues/432)\n\n- FOUC body\\[unresolved\\] should be \\[unresolved\\] [\\#431](https://github.com/Polymer/polymer/issues/431)\n\n-  polymer-project.org menu scroll behaviour is distracting [\\#430](https://github.com/Polymer/polymer/issues/430)\n\n- polymer-list is broken in \\#0.2.0 [\\#427](https://github.com/Polymer/polymer/issues/427)\n\n- polymer-project.org is slow [\\#426](https://github.com/Polymer/polymer/issues/426)\n\n- Polymer setup Instructions resulted in blank screen [\\#423](https://github.com/Polymer/polymer/issues/423)\n\n- Custom Elements and canvas/ctx functionality on iOS [\\#422](https://github.com/Polymer/polymer/issues/422)\n\n- External styles fails to load [\\#420](https://github.com/Polymer/polymer/issues/420)\n\n- Cannot access content \\(childNodes\\) in nested Polymer Element [\\#414](https://github.com/Polymer/polymer/issues/414)\n\n**Merged pull requests:**\n\n- Update README.md [\\#428](https://github.com/Polymer/polymer/pull/428) ([kentaromiura](https://github.com/kentaromiura))\n\n## [0.2.0](https://github.com/Polymer/polymer/tree/0.2.0) (2014-02-15)\n\n**Closed issues:**\n\n- HTMLImports.Loader maybe callback twice [\\#418](https://github.com/Polymer/polymer/issues/418)\n\n- Binding to input type=range does not work in IE 11 [\\#416](https://github.com/Polymer/polymer/issues/416)\n\n- Serveral issues on Opera browser [\\#411](https://github.com/Polymer/polymer/issues/411)\n\n- Adding Polymer to a page causes Typekit fonts to break [\\#408](https://github.com/Polymer/polymer/issues/408)\n\n- Polymer bind method -- should take oneTime flag? [\\#405](https://github.com/Polymer/polymer/issues/405)\n\n- how to use part style in polymer? [\\#376](https://github.com/Polymer/polymer/issues/376)\n\n- polymer declarative event doesn't work in lightdom mode [\\#331](https://github.com/Polymer/polymer/issues/331)\n\n- Expose a way to get shadowRoots by name of creating declaration, e.g. getShadowRoot\\('x-foo'\\) [\\#310](https://github.com/Polymer/polymer/issues/310)\n\n**Merged pull requests:**\n\n- update copyright year [\\#412](https://github.com/Polymer/polymer/pull/412) ([gdi2290](https://github.com/gdi2290))\n\n## [0.1.4](https://github.com/Polymer/polymer/tree/0.1.4) (2014-01-27)\n\n**Closed issues:**\n\n- polymer-localstorage-load only fires if the value has previously been set [\\#404](https://github.com/Polymer/polymer/issues/404)\n\n- CSS generated content without space goes missing \\(Safari\\) [\\#403](https://github.com/Polymer/polymer/issues/403)\n\n- \\(docs\\): Core API reference page doesn't load [\\#400](https://github.com/Polymer/polymer/issues/400)\n\n- Repeating a template from \"content\" does not work with repeat=\"d in data\" [\\#396](https://github.com/Polymer/polymer/issues/396)\n\n## [0.1.3](https://github.com/Polymer/polymer/tree/0.1.3) (2014-01-17)\n\n**Closed issues:**\n\n- polymer-ajax is missing the \"body\" attribute in the \\<polymer-element\\> declaration [\\#395](https://github.com/Polymer/polymer/issues/395)\n\n- this year is 2014 [\\#394](https://github.com/Polymer/polymer/issues/394)\n\n- Can't separate attributes in element's definition with vertical whitespace [\\#393](https://github.com/Polymer/polymer/issues/393)\n\n- \"deliverDeclarations Platform is not a function\" error loading polymer.js [\\#391](https://github.com/Polymer/polymer/issues/391)\n\n- Assertion Error thrown [\\#388](https://github.com/Polymer/polymer/issues/388)\n\n## [0.1.2](https://github.com/Polymer/polymer/tree/0.1.2) (2014-01-10)\n\n**Closed issues:**\n\n- Polymer UI Sidebar Menu doesn't work in JSBin [\\#389](https://github.com/Polymer/polymer/issues/389)\n\n- Pointer Event Example links currently 404 Not Found [\\#385](https://github.com/Polymer/polymer/issues/385)\n\n- Getting started examples are all broken for tk-\\* [\\#383](https://github.com/Polymer/polymer/issues/383)\n\n- function strings for declarative event handlers appear in the markup [\\#378](https://github.com/Polymer/polymer/issues/378)\n\n- binding to multiple mustaches \\(e.g. foo=\"{{bar}} {{zot}}\"\\) causes exception [\\#377](https://github.com/Polymer/polymer/issues/377)\n\n- Attribute value not correctly propagated to elements [\\#374](https://github.com/Polymer/polymer/issues/374)\n\n- Calling this.super can refer to the wrong method [\\#373](https://github.com/Polymer/polymer/issues/373)\n\n- \"Getting the code\" instructions are out of date/broken [\\#369](https://github.com/Polymer/polymer/issues/369)\n\n- polymer-ui-menu-item does not show the icon [\\#365](https://github.com/Polymer/polymer/issues/365)\n\n- polymer-selected class is not applied to Polymer UI elements [\\#364](https://github.com/Polymer/polymer/issues/364)\n\n- InvalidCharacterError on document.register if $ exists in constructor function name [\\#362](https://github.com/Polymer/polymer/issues/362)\n\n- Exception when running on Canary without Experimental Web Platform Features [\\#360](https://github.com/Polymer/polymer/issues/360)\n\n- Page navigation issue [\\#353](https://github.com/Polymer/polymer/issues/353)\n\n- in polymer 0.0.20131025  element id attribute not allowed [\\#332](https://github.com/Polymer/polymer/issues/332)\n\n- FAQ entry on scoped animations is not accurate [\\#141](https://github.com/Polymer/polymer/issues/141)\n\n## [0.1.1](https://github.com/Polymer/polymer/tree/0.1.1) (2013-12-12)\n\n**Closed issues:**\n\n- Polyfill support for reprojecting content in shadow nodes [\\#367](https://github.com/Polymer/polymer/issues/367)\n\n- bower instructions don't work [\\#366](https://github.com/Polymer/polymer/issues/366)\n\n- Broken Links [\\#359](https://github.com/Polymer/polymer/issues/359)\n\n- Failing to import polymer.html can cause an infinite loop [\\#356](https://github.com/Polymer/polymer/issues/356)\n\n- The bower pkg looks broken [\\#355](https://github.com/Polymer/polymer/issues/355)\n\n- Documentation display issue [\\#352](https://github.com/Polymer/polymer/issues/352)\n\n## [0.1.0](https://github.com/Polymer/polymer/tree/0.1.0) (2013-11-27)\n\n**Closed issues:**\n\n- shim styling: need to support ^ and ^^ when they are defined outside of \\<polymer-element\\> [\\#354](https://github.com/Polymer/polymer/issues/354)\n\n- Extensions to type extension custom elements must specify an extends property when registering [\\#347](https://github.com/Polymer/polymer/issues/347)\n\n- ShadowDOM polyfill breaks CSS `content: attr\\(foo\\)` [\\#345](https://github.com/Polymer/polymer/issues/345)\n\n## [v0.0.20131107](https://github.com/Polymer/polymer/tree/v0.0.20131107) (2013-11-07)\n\n**Closed issues:**\n\n- `ready` and `created` are listed in the wrong order [\\#338](https://github.com/Polymer/polymer/issues/338)\n\n- CSS: pseudo-classes don't work with :host under the polyfill [\\#335](https://github.com/Polymer/polymer/issues/335)\n\n- Allow bindings to wire events to functions [\\#324](https://github.com/Polymer/polymer/issues/324)\n\n## [v0.0.20131025](https://github.com/Polymer/polymer/tree/v0.0.20131025) (2013-10-25)\n\n**Implemented enhancements:**\n\n- Consider providing a mechanism to easily observe a set of property paths [\\#194](https://github.com/Polymer/polymer/issues/194)\n\n**Closed issues:**\n\n- binding style attribute in IE doesn't work [\\#327](https://github.com/Polymer/polymer/issues/327)\n\n- CSS: only add \\[is=..\\] selector if element is type-extension [\\#320](https://github.com/Polymer/polymer/issues/320)\n\n- Clarification on use of template repeat for \\<tr\\> & \\<select\\> [\\#318](https://github.com/Polymer/polymer/issues/318)\n\n- Autofocus doesn't work with polymer-veiling. [\\#317](https://github.com/Polymer/polymer/issues/317)\n\n- Polyfill: @polyfill @host rules are broken in an extended element [\\#315](https://github.com/Polymer/polymer/issues/315)\n\n- Polyfill: Parent styles are not inherited if there's no \\<template\\> in an extended class [\\#314](https://github.com/Polymer/polymer/issues/314)\n\n**Merged pull requests:**\n\n- Event bindings [\\#328](https://github.com/Polymer/polymer/pull/328) ([azakus](https://github.com/azakus))\n\n- Remove SideTable dependency [\\#322](https://github.com/Polymer/polymer/pull/322) ([azakus](https://github.com/azakus))\n\n- fix Node.bind to pass the property name to reflectPropertyToAttribute [\\#319](https://github.com/Polymer/polymer/pull/319) ([jmesserly](https://github.com/jmesserly))\n\n## [v0.0.20131010](https://github.com/Polymer/polymer/tree/v0.0.20131010) (2013-10-10)\n\n**Closed issues:**\n\n- trailing space in polymer attributes causes exception in IE10 [\\#313](https://github.com/Polymer/polymer/issues/313)\n\n- Calling cancelUnbindAll is cumbersome under the CustomElements polyfill [\\#312](https://github.com/Polymer/polymer/issues/312)\n\n- Calling methods on proxies returned when querying nodes can yield different results than calling directly on impl even without shadow dom use [\\#309](https://github.com/Polymer/polymer/issues/309)\n\n- Using this.$.\\[id\\] syntax yields different results in Canary than when using Polyfill [\\#308](https://github.com/Polymer/polymer/issues/308)\n\n- Debugging polymer apps: stack trace is wacko [\\#307](https://github.com/Polymer/polymer/issues/307)\n\n- Need Object.observe-enabled builders in waterfall [\\#306](https://github.com/Polymer/polymer/issues/306)\n\n- FR: Error on failed import [\\#189](https://github.com/Polymer/polymer/issues/189)\n\n## [v0.0.20131003](https://github.com/Polymer/polymer/tree/v0.0.20131003) (2013-10-03)\n\n**Implemented enhancements:**\n\n- Allow hooking into the template instantiation process [\\#156](https://github.com/Polymer/polymer/issues/156)\n\n- Support stylesheets in element templates [\\#146](https://github.com/Polymer/polymer/issues/146)\n\n- System for automatic setting of component instance attributes [\\#92](https://github.com/Polymer/polymer/issues/92)\n\n**Closed issues:**\n\n- Polymer tests failing with Object.observe enabled [\\#302](https://github.com/Polymer/polymer/issues/302)\n\n- FAQ bug: polymer fails CSP because of inline script tags not XHR. [\\#301](https://github.com/Polymer/polymer/issues/301)\n\n- \\<propertyName\\>Changed may get called twice for a single property value change [\\#298](https://github.com/Polymer/polymer/issues/298)\n\n- Two-way Binding doesn't work in canary [\\#297](https://github.com/Polymer/polymer/issues/297)\n\n- please create gh-pages [\\#294](https://github.com/Polymer/polymer/issues/294)\n\n- Conditional attributes are not properly bound [\\#293](https://github.com/Polymer/polymer/issues/293)\n\n- Bound boolean isn't set from true to false when radio button is unchecked [\\#291](https://github.com/Polymer/polymer/issues/291)\n\n- Bindings in nested templates with named scopes fail to update correctly after initial population [\\#285](https://github.com/Polymer/polymer/issues/285)\n\n- \\<content\\> not being displayed if too deep. [\\#283](https://github.com/Polymer/polymer/issues/283)\n\n- polymer-element who to fire properties change？ [\\#282](https://github.com/Polymer/polymer/issues/282)\n\n- how to get inner element [\\#280](https://github.com/Polymer/polymer/issues/280)\n\n- how to bind tap event on children node [\\#278](https://github.com/Polymer/polymer/issues/278)\n\n- Provide finer control over unresolved element styling [\\#276](https://github.com/Polymer/polymer/issues/276)\n\n- Question regarding your usage of a getter [\\#274](https://github.com/Polymer/polymer/issues/274)\n\n- Consider removing \"tools\" submodule [\\#271](https://github.com/Polymer/polymer/issues/271)\n\n- Community registry in the wild [\\#268](https://github.com/Polymer/polymer/issues/268)\n\n- HTMLImports fails on IE9 [\\#229](https://github.com/Polymer/polymer/issues/229)\n\n- External element scripts not loading [\\#216](https://github.com/Polymer/polymer/issues/216)\n\n- polymer-element script tag are ignored when using innerHTML to inject polymer-element\\(s\\) into the page [\\#205](https://github.com/Polymer/polymer/issues/205)\n\n- Galaxy Nexus Stock-Browser [\\#202](https://github.com/Polymer/polymer/issues/202)\n\n- Allow body FOUC prevention to be optional [\\#197](https://github.com/Polymer/polymer/issues/197)\n\n- Consider converting attributes with dashes into to camelCased properties [\\#193](https://github.com/Polymer/polymer/issues/193)\n\n- \\(IE only\\) Last element created by \\<template repeat\\> is unbound [\\#187](https://github.com/Polymer/polymer/issues/187)\n\n- Can't bind to the value of a custom element that extends \\<input\\> [\\#186](https://github.com/Polymer/polymer/issues/186)\n\n- Calling offsetWidth in a style-modifying forEach is slow [\\#180](https://github.com/Polymer/polymer/issues/180)\n\n- Explicitly fire ready\\(\\) [\\#178](https://github.com/Polymer/polymer/issues/178)\n\n- Consider deserializing to Number only if property is already Number-valued [\\#120](https://github.com/Polymer/polymer/issues/120)\n\n- Cannot load Google's jsapi inside of a component [\\#115](https://github.com/Polymer/polymer/issues/115)\n\n- Document toolkit styling helpers [\\#101](https://github.com/Polymer/polymer/issues/101)\n\n- Make sure properties are not doc'd as attributes [\\#96](https://github.com/Polymer/polymer/issues/96)\n\n- Document that attributes and properties are not dynamically converted [\\#94](https://github.com/Polymer/polymer/issues/94)\n\n**Merged pull requests:**\n\n- Removes unnecessary px declarations in coordinate attributes. [\\#289](https://github.com/Polymer/polymer/pull/289) ([mrmrs](https://github.com/mrmrs))\n\n- remove extra argument to unbindProperty that was ignored [\\#286](https://github.com/Polymer/polymer/pull/286) ([jmesserly](https://github.com/jmesserly))\n\n- small fix to bubbles parameter of utils.fire [\\#284](https://github.com/Polymer/polymer/pull/284) ([jmesserly](https://github.com/jmesserly))\n\n## [v0.0.20130912](https://github.com/Polymer/polymer/tree/v0.0.20130912) (2013-09-12)\n\n**Fixed bugs:**\n\n- Updated use of PathObservers to match new API [\\#267](https://github.com/Polymer/polymer/issues/267)\n\n**Closed issues:**\n\n- Point each repo's CONTRIBUTING file to Polymer's [\\#273](https://github.com/Polymer/polymer/issues/273)\n\n- Nested templates throwing exceptions with reference to observe.js [\\#264](https://github.com/Polymer/polymer/issues/264)\n\n- Perf regression in polyfill - 20130808 release  [\\#236](https://github.com/Polymer/polymer/issues/236)\n\n- Auto-registration of polymer-elements broken? [\\#221](https://github.com/Polymer/polymer/issues/221)\n\n## [v0.0.20130905](https://github.com/Polymer/polymer/tree/v0.0.20130905) (2013-09-05)\n\n**Closed issues:**\n\n- SD polyfill in latest release breaks chromestatus.com [\\#263](https://github.com/Polymer/polymer/issues/263)\n\n- On latest Chrome Canary, using vulcanized version won't show the style of elements [\\#262](https://github.com/Polymer/polymer/issues/262)\n\n- grunt will fail using the latest commit of polymer-all [\\#261](https://github.com/Polymer/polymer/issues/261)\n\n- Need a way to get the activeElement inside a Polymer element [\\#253](https://github.com/Polymer/polymer/issues/253)\n\n- When using minified version on polymer, images of the button don't show in the ui-toolbar example [\\#251](https://github.com/Polymer/polymer/issues/251)\n\n- Make sure boolean properties are reflected as boolean attributes [\\#240](https://github.com/Polymer/polymer/issues/240)\n\n- Attributes are not reflected at bind time [\\#239](https://github.com/Polymer/polymer/issues/239)\n\n- HTML imports fail when url params contain '/' characters [\\#238](https://github.com/Polymer/polymer/issues/238)\n\n- Unable to use the Sandbox on Chrome \\<= 28 [\\#138](https://github.com/Polymer/polymer/issues/138)\n\n## [v0.0.20130829](https://github.com/Polymer/polymer/tree/v0.0.20130829) (2013-08-28)\n\n**Closed issues:**\n\n- loading a local file \\(file:///\\) using polymer will fail to load properly [\\#260](https://github.com/Polymer/polymer/issues/260)\n\n- uppercase signals do not work [\\#256](https://github.com/Polymer/polymer/issues/256)\n\n- Chrome Packaged App: including UI elements in an application will show some errors [\\#249](https://github.com/Polymer/polymer/issues/249)\n\n- Changing a DOM attribute doesn't change the model [\\#246](https://github.com/Polymer/polymer/issues/246)\n\n- Latest build broken w/ jQuery \\(chrome 28\\) [\\#243](https://github.com/Polymer/polymer/issues/243)\n\n- window.Loader name colliding with ES6 window.Loader \\(modules\\) [\\#237](https://github.com/Polymer/polymer/issues/237)\n\n**Merged pull requests:**\n\n- Recursive build for polymer [\\#250](https://github.com/Polymer/polymer/pull/250) ([azakus](https://github.com/azakus))\n\n## [v0.0.20130815](https://github.com/Polymer/polymer/tree/v0.0.20130815) (2013-08-15)\n\n## [v0.0.20130816](https://github.com/Polymer/polymer/tree/v0.0.20130816) (2013-08-15)\n\n**Fixed bugs:**\n\n- FF broken in latest release w/ dom.webcomponents.enabled: true [\\#235](https://github.com/Polymer/polymer/issues/235)\n\n**Closed issues:**\n\n- HTMLImports fails silently on Chrome 28.0.1500.95 \\(Debian , 64bit\\) [\\#234](https://github.com/Polymer/polymer/issues/234)\n\n- ss [\\#233](https://github.com/Polymer/polymer/issues/233)\n\n- Internet Explorer - not working at all [\\#217](https://github.com/Polymer/polymer/issues/217)\n\n**Merged pull requests:**\n\n- 8/15 master -\\> stable [\\#241](https://github.com/Polymer/polymer/pull/241) ([azakus](https://github.com/azakus))\n\n- Fixes for some of the workbench samples [\\#232](https://github.com/Polymer/polymer/pull/232) ([chrisbu](https://github.com/chrisbu))\n\n## [v0.0.20130808](https://github.com/Polymer/polymer/tree/v0.0.20130808) (2013-08-08)\n\n**Implemented enhancements:**\n\n- Add @version string to build files [\\#226](https://github.com/Polymer/polymer/issues/226)\n\n**Closed issues:**\n\n- Events on distributed nodes aren't bubbled to parent nodes in shadow DOM under polyfill [\\#230](https://github.com/Polymer/polymer/issues/230)\n\n- `ReferenceError: PathObserver is not defined` when loading in node-webkit [\\#228](https://github.com/Polymer/polymer/issues/228)\n\n**Merged pull requests:**\n\n- 8/8 master -\\> stable [\\#231](https://github.com/Polymer/polymer/pull/231) ([azakus](https://github.com/azakus))\n\n## [v0.0.20130801](https://github.com/Polymer/polymer/tree/v0.0.20130801) (2013-08-01)\n\n**Implemented enhancements:**\n\n- It's awkward to make a property with an object default value [\\#215](https://github.com/Polymer/polymer/issues/215)\n\n- Throw a more useful error if Polymer.register is used [\\#210](https://github.com/Polymer/polymer/issues/210)\n\n- Consider if/when/how to reflect bound property values to attributes [\\#188](https://github.com/Polymer/polymer/issues/188)\n\n- Make platform and toolkit builds available as simple downloads and/or from CDN [\\#87](https://github.com/Polymer/polymer/issues/87)\n\n**Closed issues:**\n\n- If `Polymer\\(\\)` is not called almost immediately, the element is not initialised. [\\#214](https://github.com/Polymer/polymer/issues/214)\n\n- Input value is not initialised. [\\#213](https://github.com/Polymer/polymer/issues/213)\n\n- Fail more gracefully on unsupported browsers [\\#207](https://github.com/Polymer/polymer/issues/207)\n\n- Binding and xxxChanged function break if element is moved to a different shadow [\\#203](https://github.com/Polymer/polymer/issues/203)\n\n- table element problems on firefox [\\#196](https://github.com/Polymer/polymer/issues/196)\n\n- Bindings on a range input not working well in google chrome [\\#182](https://github.com/Polymer/polymer/issues/182)\n\n- Add support for creating Polymer elements imperatively [\\#163](https://github.com/Polymer/polymer/issues/163)\n\n- Issue with scrolling using the flot library [\\#162](https://github.com/Polymer/polymer/issues/162)\n\n- \\[Feature Request\\] Using Bower instead of submodules [\\#147](https://github.com/Polymer/polymer/issues/147)\n\n- minor documentation typo [\\#139](https://github.com/Polymer/polymer/issues/139)\n\n**Merged pull requests:**\n\n- 8/1 master -\\> stable [\\#223](https://github.com/Polymer/polymer/pull/223) ([azakus](https://github.com/azakus))\n\n## [v0.0.20130711](https://github.com/Polymer/polymer/tree/v0.0.20130711) (2013-07-11)\n\n**Implemented enhancements:**\n\n- Support resetStyleInheritance on prototype [\\#199](https://github.com/Polymer/polymer/issues/199)\n\n- Add styling polyfill support for pseudos [\\#152](https://github.com/Polymer/polymer/issues/152)\n\n**Fixed bugs:**\n\n- template/element polyfill styling need !important [\\#191](https://github.com/Polymer/polymer/issues/191)\n\n- Type extension elements lose styling under polyfill [\\#171](https://github.com/Polymer/polymer/issues/171)\n\n- When polymer-scope=\"global\" is used to pull a stylesheet to the document, it appears multiple times [\\#155](https://github.com/Polymer/polymer/issues/155)\n\n- PathObservers in observeProperties.js must be created at insertedCallback and removed at removeCallback [\\#121](https://github.com/Polymer/polymer/issues/121)\n\n- shimStyling: styles defined within shadowDOM are not prefixed with the scope name in Firefox [\\#107](https://github.com/Polymer/polymer/issues/107)\n\n- Event target is incorrect after certain DOM changes in ShadowDOM Polyfill [\\#102](https://github.com/Polymer/polymer/issues/102)\n\n- Bindings in icon-button fail under ShadowDOMPolyfill [\\#83](https://github.com/Polymer/polymer/issues/83)\n\n- \\[dev\\] Uncaught ReferenceError: SideTable is not defined [\\#80](https://github.com/Polymer/polymer/issues/80)\n\n- \\[dev\\] template iterate doesn't work inside component [\\#79](https://github.com/Polymer/polymer/issues/79)\n\n- Toolkit Components fail if they have a property named \"node\" [\\#78](https://github.com/Polymer/polymer/issues/78)\n\n- Support component upgrade using \"is\" style declaration [\\#71](https://github.com/Polymer/polymer/issues/71)\n\n- Styles declared in a component's shadowRoot should not leak out of the component [\\#70](https://github.com/Polymer/polymer/issues/70)\n\n- this.node.webkitShadowRoot needs to return ShadowRoot [\\#68](https://github.com/Polymer/polymer/issues/68)\n\n- Commented @host rule style gets applied [\\#67](https://github.com/Polymer/polymer/issues/67)\n\n- data: URLs are being rewritten to relative URLs in \\<style\\> [\\#66](https://github.com/Polymer/polymer/issues/66)\n\n- Custom Element shim incorrectly handles @host rule [\\#65](https://github.com/Polymer/polymer/issues/65)\n\n- path.js needs to handle absolute url paths [\\#62](https://github.com/Polymer/polymer/issues/62)\n\n- imperative instantiation is broken [\\#56](https://github.com/Polymer/polymer/issues/56)\n\n- nodes inside a component's shadowDOM have incorrect model when using shadowDOM shim [\\#43](https://github.com/Polymer/polymer/issues/43)\n\n- g-component custom events can be handled in wrong scope [\\#30](https://github.com/Polymer/polymer/issues/30)\n\n**Closed issues:**\n\n- Consider optimizing propertyForAttribute [\\#181](https://github.com/Polymer/polymer/issues/181)\n\n- nameInThis\\(\\) in oop.js is slow [\\#177](https://github.com/Polymer/polymer/issues/177)\n\n- Internationalization of Web Components [\\#175](https://github.com/Polymer/polymer/issues/175)\n\n- polymer-scope=\"controller\" should not install the same stylesheet multiple times  [\\#173](https://github.com/Polymer/polymer/issues/173)\n\n- Add polyfill styling support for @host :scope [\\#170](https://github.com/Polymer/polymer/issues/170)\n\n- Error loading polymer if window.location.hash is not null [\\#167](https://github.com/Polymer/polymer/issues/167)\n\n- Unexpected result upgraded plain DOM to custom element instance [\\#166](https://github.com/Polymer/polymer/issues/166)\n\n- Alias this.webkitShadowRoot -\\> this.shadowRoot [\\#165](https://github.com/Polymer/polymer/issues/165)\n\n- Simplest way to \"Fire up a web server\" to run examples [\\#161](https://github.com/Polymer/polymer/issues/161)\n\n- Custom elements seem to cache data after being deleted and re-added [\\#159](https://github.com/Polymer/polymer/issues/159)\n\n- Prevent memory leaking under MDV polyfill [\\#154](https://github.com/Polymer/polymer/issues/154)\n\n- Element templates are stamped into shadowRoot with unbound values [\\#153](https://github.com/Polymer/polymer/issues/153)\n\n- Styles should not be shimmed asynchronously under ShadowDOMPolyfill [\\#151](https://github.com/Polymer/polymer/issues/151)\n\n- Polymer.js fails to load with \"ReferenceError: Can't find variable: Window\" on Windows 7 Safari browser and iPad 1 iOS 5.1.1 [\\#149](https://github.com/Polymer/polymer/issues/149)\n\n- Stylesheets in \\<element\\> elements are emitted in incorrect order [\\#148](https://github.com/Polymer/polymer/issues/148)\n\n- Web animations is not loaded by Polymer [\\#140](https://github.com/Polymer/polymer/issues/140)\n\n- Polymer components should be called monomers.   [\\#137](https://github.com/Polymer/polymer/issues/137)\n\n- Small error in \"Getting Started\" tutorial [\\#136](https://github.com/Polymer/polymer/issues/136)\n\n- add doc-comments to 'base.js' [\\#133](https://github.com/Polymer/polymer/issues/133)\n\n- Attribute-based styles not always updated [\\#132](https://github.com/Polymer/polymer/issues/132)\n\n- attributeChanged event on \"sub-component\" not fired in Canary but works in Chrome [\\#131](https://github.com/Polymer/polymer/issues/131)\n\n- Stylesheets throw exception if toolkit-scope is defined and the element definition is inline [\\#127](https://github.com/Polymer/polymer/issues/127)\n\n- Consider deserializing to Array from attributes, if property is Array-valued [\\#124](https://github.com/Polymer/polymer/issues/124)\n\n- Modify attrs.js to accept Date strings in custom element attribute values [\\#118](https://github.com/Polymer/polymer/issues/118)\n\n- Attribute value that's a comma delineated list of numbers is converted to a property incorrectly [\\#117](https://github.com/Polymer/polymer/issues/117)\n\n- Including toolkit.js on a page moves all \\<style\\>s to  the \\<head\\>. [\\#114](https://github.com/Polymer/polymer/issues/114)\n\n- PointerEvents registration fails in the presence of ShadowDOMPolyfill in some cases [\\#111](https://github.com/Polymer/polymer/issues/111)\n\n- Distributing template content to a shadowDOM can fail under shadowDOM polyfill [\\#110](https://github.com/Polymer/polymer/issues/110)\n\n- Cursor moves to end of input after typing [\\#109](https://github.com/Polymer/polymer/issues/109)\n\n- toolkitchen.github.io code samples not showing up in ff [\\#105](https://github.com/Polymer/polymer/issues/105)\n\n- Document Browser support and test coverage using Testing CI and Travis CI [\\#104](https://github.com/Polymer/polymer/issues/104)\n\n- clean up commented code in events.js [\\#100](https://github.com/Polymer/polymer/issues/100)\n\n- rename `base.send` to `base.fire` or `base.bubble` [\\#98](https://github.com/Polymer/polymer/issues/98)\n\n- toolkit.min.js missing method shimStyling [\\#91](https://github.com/Polymer/polymer/issues/91)\n\n- Git repo url incorrect [\\#89](https://github.com/Polymer/polymer/issues/89)\n\n- Menu-button workbench file hangs chrome under ShadowDOM Polyfill [\\#86](https://github.com/Polymer/polymer/issues/86)\n\n- can't make bindings to objects on elements instantiated by mdv [\\#81](https://github.com/Polymer/polymer/issues/81)\n\n- Don't name things \\_, \\_\\_ and $ [\\#73](https://github.com/Polymer/polymer/issues/73)\n\n- @host styles aren't processed for base elements [\\#72](https://github.com/Polymer/polymer/issues/72)\n\n- \"export\" flag attribute documented in platform.js is actually \"exportas\" [\\#64](https://github.com/Polymer/polymer/issues/64)\n\n- handlers=\"...\" declarative events listen on the host element and therefore see no event target info for events generated in  shadowDom [\\#41](https://github.com/Polymer/polymer/issues/41)\n\n- MutationObserver code for custom event \\(on-\\*\\) binding is inefficient [\\#24](https://github.com/Polymer/polymer/issues/24)\n\n- g-component published properties don't inherit [\\#18](https://github.com/Polymer/polymer/issues/18)\n\n- g-component property automation is inefficient [\\#15](https://github.com/Polymer/polymer/issues/15)\n\n- Add unit tests for g-overlay, g-selector, g-selection [\\#11](https://github.com/Polymer/polymer/issues/11)\n\n- Document public api [\\#10](https://github.com/Polymer/polymer/issues/10)\n\n- have some good defaults for g-overlay [\\#7](https://github.com/Polymer/polymer/issues/7)\n\n**Merged pull requests:**\n\n- 7/11 master -\\> stable [\\#204](https://github.com/Polymer/polymer/pull/204) ([azakus](https://github.com/azakus))\n\n- Correct test to check global div [\\#201](https://github.com/Polymer/polymer/pull/201) ([ebidel](https://github.com/ebidel))\n\n- Fixes issue \\#199 - adds support for resetStyleInheritance on prototype [\\#200](https://github.com/Polymer/polymer/pull/200) ([ebidel](https://github.com/ebidel))\n\n- Switch to \\<polymer-element\\> [\\#192](https://github.com/Polymer/polymer/pull/192) ([azakus](https://github.com/azakus))\n\n- 6/17 master -\\> stable [\\#184](https://github.com/Polymer/polymer/pull/184) ([azakus](https://github.com/azakus))\n\n- Fix a typo in contributing.md [\\#183](https://github.com/Polymer/polymer/pull/183) ([alexhancock](https://github.com/alexhancock))\n\n- Flatten repos [\\#174](https://github.com/Polymer/polymer/pull/174) ([azakus](https://github.com/azakus))\n\n- 6/5 master -\\> stable [\\#172](https://github.com/Polymer/polymer/pull/172) ([azakus](https://github.com/azakus))\n\n- Merge mdv-syntax branch [\\#168](https://github.com/Polymer/polymer/pull/168) ([sjmiles](https://github.com/sjmiles))\n\n- added array & obj support to attrs.js \\(plus refactor\\) [\\#158](https://github.com/Polymer/polymer/pull/158) ([bsatrom](https://github.com/bsatrom))\n\n- Fix link in CONTRIBUTING.md [\\#144](https://github.com/Polymer/polymer/pull/144) ([markhealey](https://github.com/markhealey))\n\n- 5/15 master -\\> stable [\\#135](https://github.com/Polymer/polymer/pull/135) ([azakus](https://github.com/azakus))\n\n- 5/14 master -\\> stable [\\#134](https://github.com/Polymer/polymer/pull/134) ([azakus](https://github.com/azakus))\n\n- Add custom date parsing module [\\#130](https://github.com/Polymer/polymer/pull/130) ([bsatrom](https://github.com/bsatrom))\n\n- 5/9 master -\\> stable [\\#125](https://github.com/Polymer/polymer/pull/125) ([azakus](https://github.com/azakus))\n\n- added deserialization of Date attributes for custom elements [\\#122](https://github.com/Polymer/polymer/pull/122) ([bsatrom](https://github.com/bsatrom))\n\n- merge Observer branch [\\#113](https://github.com/Polymer/polymer/pull/113) ([sjmiles](https://github.com/sjmiles))\n\n- 4/17 master -\\> stable [\\#99](https://github.com/Polymer/polymer/pull/99) ([azakus](https://github.com/azakus))\n\n- Bring experimental test harness in from alt-test branch [\\#85](https://github.com/Polymer/polymer/pull/85) ([sjmiles](https://github.com/sjmiles))\n\n- Wrap grunt test in xvfb for virtual display. [\\#84](https://github.com/Polymer/polymer/pull/84) ([agable-chromium](https://github.com/agable-chromium))\n\n- Add step-generator script to toolkit [\\#82](https://github.com/Polymer/polymer/pull/82) ([agable-chromium](https://github.com/agable-chromium))\n\n- Stop using \\_\\_{lookup,define}{G,S}etter\\_\\_ [\\#76](https://github.com/Polymer/polymer/pull/76) ([arv](https://github.com/arv))\n\n- Use XMLHttpRequest directly [\\#75](https://github.com/Polymer/polymer/pull/75) ([arv](https://github.com/arv))\n\n- Updating meta tag [\\#61](https://github.com/Polymer/polymer/pull/61) ([ebidel](https://github.com/ebidel))\n\n- Adding Contributors guide [\\#60](https://github.com/Polymer/polymer/pull/60) ([ebidel](https://github.com/ebidel))\n\n- Tweaks to README. [\\#58](https://github.com/Polymer/polymer/pull/58) ([ebidel](https://github.com/ebidel))\n\n- latest event handling scheme [\\#55](https://github.com/Polymer/polymer/pull/55) ([sjmiles](https://github.com/sjmiles))\n\n- g-panels updates [\\#54](https://github.com/Polymer/polymer/pull/54) ([sorvell](https://github.com/sorvell))\n\n- g-component tweaks to improve data-binding [\\#53](https://github.com/Polymer/polymer/pull/53) ([sjmiles](https://github.com/sjmiles))\n\n- updated components for the new changes in g-component [\\#52](https://github.com/Polymer/polymer/pull/52) ([frankiefu](https://github.com/frankiefu))\n\n- Merge polybinding branch into master [\\#51](https://github.com/Polymer/polymer/pull/51) ([sjmiles](https://github.com/sjmiles))\n\n- minor fixes to support app development [\\#49](https://github.com/Polymer/polymer/pull/49) ([sorvell](https://github.com/sorvell))\n\n- added g-menu-button and g-toolbar [\\#48](https://github.com/Polymer/polymer/pull/48) ([frankiefu](https://github.com/frankiefu))\n\n- g-overlay: simplify styling. [\\#47](https://github.com/Polymer/polymer/pull/47) ([sorvell](https://github.com/sorvell))\n\n- g-overlay update: simplify and add basic management for focus and z-index. [\\#46](https://github.com/Polymer/polymer/pull/46) ([sorvell](https://github.com/sorvell))\n\n- add unit tests to cover more components and the latest sugaring in g-components [\\#45](https://github.com/Polymer/polymer/pull/45) ([frankiefu](https://github.com/frankiefu))\n\n- fixes issue \\#30: allow findController to step out of lightDOM [\\#44](https://github.com/Polymer/polymer/pull/44) ([sjmiles](https://github.com/sjmiles))\n\n- update g-ajax and minor g-panels and g-page fixes [\\#42](https://github.com/Polymer/polymer/pull/42) ([sorvell](https://github.com/sorvell))\n\n- update to use the new g-component sugar [\\#40](https://github.com/Polymer/polymer/pull/40) ([frankiefu](https://github.com/frankiefu))\n\n- g-component minor fixup; updates for g-page and g-panels [\\#39](https://github.com/Polymer/polymer/pull/39) ([sorvell](https://github.com/sorvell))\n\n- implement new 'protected' syntax [\\#38](https://github.com/Polymer/polymer/pull/38) ([sjmiles](https://github.com/sjmiles))\n\n- g-component and g-panels minor changes [\\#37](https://github.com/Polymer/polymer/pull/37) ([sorvell](https://github.com/sorvell))\n\n- filter mustaches in takeAttributes, other minor tweaks [\\#36](https://github.com/Polymer/polymer/pull/36) ([sjmiles](https://github.com/sjmiles))\n\n- g-page: use external stylesheet [\\#35](https://github.com/Polymer/polymer/pull/35) ([sorvell](https://github.com/sorvell))\n\n- added g-page component [\\#34](https://github.com/Polymer/polymer/pull/34) ([sorvell](https://github.com/sorvell))\n\n- g-component attribute parsing fix; g-panels & g-overlay & g-ajax minor fixes [\\#33](https://github.com/Polymer/polymer/pull/33) ([sorvell](https://github.com/sorvell))\n\n- bug fixes, more indirection around 'conventions' [\\#32](https://github.com/Polymer/polymer/pull/32) ([sjmiles](https://github.com/sjmiles))\n\n- minor updates/fixes to g-component, selector and menu [\\#31](https://github.com/Polymer/polymer/pull/31) ([frankiefu](https://github.com/frankiefu))\n\n- g-panels minor bug fixes [\\#29](https://github.com/Polymer/polymer/pull/29) ([sorvell](https://github.com/sorvell))\n\n- add g-panels [\\#28](https://github.com/Polymer/polymer/pull/28) ([sorvell](https://github.com/sorvell))\n\n- g-overlay: refactor/simplify [\\#27](https://github.com/Polymer/polymer/pull/27) ([sorvell](https://github.com/sorvell))\n\n- g-component: fix typo [\\#26](https://github.com/Polymer/polymer/pull/26) ([sorvell](https://github.com/sorvell))\n\n- update components based on changes in g-component [\\#25](https://github.com/Polymer/polymer/pull/25) ([frankiefu](https://github.com/frankiefu))\n\n- MDV sugaring  [\\#23](https://github.com/Polymer/polymer/pull/23) ([sjmiles](https://github.com/sjmiles))\n\n- menu component and basic component unit tests [\\#22](https://github.com/Polymer/polymer/pull/22) ([frankiefu](https://github.com/frankiefu))\n\n- \"DOMTokenList.enable\" was renamed to \"toggle\" at platform, update polyfill [\\#21](https://github.com/Polymer/polymer/pull/21) ([sjmiles](https://github.com/sjmiles))\n\n- use MutationObserver to maintain custom event bindings, bug fixes [\\#20](https://github.com/Polymer/polymer/pull/20) ([sjmiles](https://github.com/sjmiles))\n\n- tabs component, simplify togglebutton and more unit tests [\\#19](https://github.com/Polymer/polymer/pull/19) ([frankiefu](https://github.com/frankiefu))\n\n- unit test harness [\\#17](https://github.com/Polymer/polymer/pull/17) ([frankiefu](https://github.com/frankiefu))\n\n- use shadow=\"shim\" instead of shimShadow for compatibility with URL override [\\#16](https://github.com/Polymer/polymer/pull/16) ([sjmiles](https://github.com/sjmiles))\n\n- change property automation to be property-first instead of attribute-first [\\#14](https://github.com/Polymer/polymer/pull/14) ([sjmiles](https://github.com/sjmiles))\n\n- call shadowRootCreated in the right scope and add g-ratings component [\\#13](https://github.com/Polymer/polymer/pull/13) ([frankiefu](https://github.com/frankiefu))\n\n- update for names changes in polyfill [\\#12](https://github.com/Polymer/polymer/pull/12) ([frankiefu](https://github.com/frankiefu))\n\n- add g-selection and g-selector components [\\#9](https://github.com/Polymer/polymer/pull/9) ([sjmiles](https://github.com/sjmiles))\n\n- add ajax and togglebutton components [\\#8](https://github.com/Polymer/polymer/pull/8) ([frankiefu](https://github.com/frankiefu))\n\n- various changes to enable g-overlay [\\#6](https://github.com/Polymer/polymer/pull/6) ([sjmiles](https://github.com/sjmiles))\n\n- add g-icon-button [\\#4](https://github.com/Polymer/polymer/pull/4) ([sjmiles](https://github.com/sjmiles))\n\n- fix path [\\#3](https://github.com/Polymer/polymer/pull/3) ([sjmiles](https://github.com/sjmiles))\n\n- make workBench live with toolkit [\\#2](https://github.com/Polymer/polymer/pull/2) ([sjmiles](https://github.com/sjmiles))\n\n- Initial Components [\\#1](https://github.com/Polymer/polymer/pull/1) ([sjmiles](https://github.com/sjmiles))\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to Polymer\n\nThere are many ways to contribute to the Polymer project! We welcome and truly appreciate contribution in all forms - issues and pull requests to the [main library](https://github.com/polymer/polymer), issues and pull requests to the [elements the Polymer team maintains](https://github.com/polymerelements), issues and pull requests to one of our many [Polymer-related tools](https://github.com/polymer), and of course we love to hear about any Polymer elements that you build to share with the community!\n\n## Logistics\n\n### Communicating with the Polymer team\n\nBeyond GitHub, we try to have a variety of different lines of communication open:\n\n* [Blog](https://blog.polymer-project.org/)\n* [Twitter](https://twitter.com/polymer)\n* [Mailing list](https://groups.google.com/forum/#!forum/polymer-dev)\n* [Slack channel](https://bit.ly/polymerslack)\n\n### The Polymer Repositories\n\nBecause of the component-based nature of the Polymer project, we tend to have lots of different repositories. Our main repository for the Polymer library itself is at [github.com/Polymer/polymer](https://github.com/polymer/polymer). File any issues or pull requests that have to do with the core library on that repository, and we'll take a look ASAP.\n\nWe keep all of the element \"product lines\" that the Polymer team maintains and distributes in the [PolymerElements](https://github.com/polymerelements) organization. For any element-specific issues or pull requests, file directly on the element's repository, such as the `paper-button` repository at [github.com/polymerelements/paper-button](https://github.com/polymerelements/paper-button). Of course, the elements built by the Polymer team are just a tiny fraction of all the Polymer-based elements out there - catalogs of other web components include [https://www.webcomponents.org/](https://github.com/webcomponents/webcomponents.org) and [component.kitchen](https://component.kitchen).\n\nThe GoogleWebComponents element product line is maintained by teams all across Google, and so is kept in a separate organization: the [GoogleWebComponents](https://github.com/googlewebcomponents) org. Feel free to file issues and PR's on those elements directly in that organization.\n\nWe also track each element product line overall in \"meta-repos\", named as `$PRODUCTLINE-elements`. These include [paper-elements](https://github.com/polymerelements/paper-elements), [iron-elements](https://github.com/polymerelements/iron-elements), [gold-elements](https://github.com/polymerelements/gold-elements), and more. Feel free to file issues for element requests on those meta-repos, and the README in each repo tracks a roadmap for the product line.\n\n### Contributor License Agreement\n\nYou might notice our friendly CLA-bot commenting on a pull request you open if you haven't yet signed our CLA. We use the same CLA for all open-source Google projects, so you only have to sign it once. Once you complete the CLA, all your pull-requests will automatically get the `cla: yes` tag.\n\nIf you've already signed a CLA but are still getting bothered by the awfully insistent CLA bot, it's possible we don't have your GitHub username or you're using a different email address. Check the [information on your CLA](https://cla.developers.google.com/clas) or see this help article on [setting the email on your git commits](https://help.github.com/articles/setting-your-email-in-git/).\n\n[Complete the CLA](https://cla.developers.google.com/clas)\n\n## Contributing\n\n### Filing bugs\n\nThe Polymer team heavily uses (and loves!) GitHub for all of our software management. We use GitHub issues to track all bugs and features.\n\nIf you find an issue, please do file it on the repository. The [Polymer/polymer issues](https://github.com/polymer/polymer/issues) should be used only for issues on the Polymer library itself - bugs somewhere in the core codebase.\n\nFor issues with elements the team maintains, please file directly on the element's repository. If you're not sure if a bug stems from the element or the library, err toward filing it on the element and we'll move the issue if necessary.\n\nPlease file issues using the issue template provided, filling out as many fields as possible. We love examples for addressing issues - issues with a jsBin, Plunkr, jsFiddle, or glitch.me repro will be much easier for us to work on quickly. You can start with [this jsbin](http://jsbin.com/luhaxab/edit) which sets up the basics to demonstrate a Polymer element.  If you need your repro to run in IE11, you can start from [this glitch](https://glitch.com/edit/#!/polymer-repro?path=my-element.html:2:0), which serves the source via polyserve for automatic transpilation, although you must sign up for a glitch.me account to ensure your code persists for more than 5 days (note the glitch.me _editing environment_ is not compatible with IE11, however the \"live\" view link of the running code should work).\n\nOccasionally we'll close issues if they appear stale or are too vague - please don't take this personally! Please feel free to re-open issues we've closed if there's something we've missed and they still need to be addressed.\n\n### Contributing Pull Requests\n\nPR's are even better than issues. We gladly accept community pull requests. In general across the core library and all of the elements, there are a few necessary steps before we can accept a pull request:\n\n- Open an issue describing the problem that you are looking to solve in your PR (if one is not already open), and your approach to solving it. This makes it easier to have a conversation around the best general approach for solving your problem, outside of the code itself.\n- Sign the [CLA](https://cla.developers.google.com/clas), as described above.\n- Fork the repo you're making the fix on to your own GitHub account.\n- Code!\n- Ideally, squash your commits into a single commit with a clear message of what the PR does. If it absolutely makes sense to keep multiple commits, that's OK - or perhaps consider making two separate PR's.\n- **Include tests that test the range of behavior that changes with your PR.** If you PR fixes a bug, make sure your tests capture that bug. If your PR adds new behavior, make sure that behavior is fully tested. Every PR *must* include associated tests. (See [Unit tests](#unit-tests) for more.)\n- Submit your PR, making sure it references the issue you created.\n- If your PR fixes a bug, make sure the issue includes clear steps to reproduce the bug so we can test your fix.\n\nIf you've completed all of these steps the core team will do its best to respond to the PR as soon as possible.\n\n#### Contributing Code to Elements\n\nThough the aim of the Polymer library is to allow lots of flexibility and not get in your way, we work to standardize our elements to make them as toolable and easy to maintain as possible.\n\nAll elements should follow the [Polymer element style guide](https://www.polymer-project.org/3.0/docs/tools/documentation), which defines how to specify properties, documentation, and more. It's a great guide to follow when building your own elements as well, for maximum standardization and toolability. For instance, structuring elements following the style guide will ensure that they work with the [`iron-component-page`](https://github.com/polymerelements/iron-component-page) element, an incredibly easy way to turn any raw element directly into a documentation page.\n\n#### Contributing Code to the Polymer library\n\nWe follow the most common JavaScript and HTML style guidelines for how we structure our code - in general, look at the code and you'll know how to contribute! If you'd like a bit more structure, the [Google JavaScript Styleguide](https://google.github.io/styleguide/javascriptguide.xml) is a good place to start.\n\nPolymer also participates in Google's [Patch Rewards Program](https://www.google.com/about/appsecurity/patch-rewards/), where you can earn cold, hard cash for qualifying security patches to the Polymer library. Visit the [patch rewards page](https://www.google.com/about/appsecurity/patch-rewards/) to find out more.\n\n## Unit tests\n\nAll Polymer projects use [`polymer-cli`](https://github.com/Polymer/tools/tree/master/packages/cli) for unit tests.\n\nFor maximum flexibility, install `polymer-cli` locally:\n\n    npm install -g polymer-cli\n\n### Running the Polymer library unit tests\n\nTo run the Polymer library unit tests:\n\n1.  Clone the [Polymer repo](https://github.com/polymer/polymer).\n\n2.  Install the dependencies:\n\n\t\tnpm install\n\n3.  Run the tests:\n\n\t\tnpm test\n\n    Or if you have `polymer-cli` installed locally:\n\n\t\tpolymer test --npm\n\nTo run individual test suites:\n\n<code>npm test <var>path/to/suite</var></code>\n\nOr:\n\n<code>polymer test --npm <var>path/to/suite</var></code>\n\nFor example:\n\n\tpolymer test --npm test/unit/polymer.element.html\n\nYou can also run tests in the browser:\n\n\tpolymer serve --npm\n\nNavigate to:\n\n[`http://localhost:8080/components/@polymer/polymer/test/runner.html`](http://localhost:8080/components/@polymer/polymer/test/runner.html)\n\n### Running Polymer element unit tests\n\nTo run the element unit tests, you need a global install of `polymer-cli` .\n\n1. Clone the element repo.\n\n1. Install the dependencies.\n\n       bower install\n\n1. Run the tests:\n\n       polymer test\n\n     Or run the tests in a browser:\n\n       polymer serve\n\n     Navigate to:\n\n     <code>http://localhost:8080/components/<var>element-name</var>/test/runner.html</code>\n\n### Configuring `web-component-tester`\n\nBy default, `polymer test` runs tests on all installed browsers. You can configure it\nto run tests on a subset of available browsers, or to run tests remotely using Sauce Labs.\n\nSee the [`web-component-tester` README](https://github.com/Polymer/tools/tree/master/packages/web-component-tester) for\ninformation on configuring the tool using by `polymer-cli` to run the tests.\n\n### Viewing the source documentation locally\n\nYou can view the updates you make to the source documentation locally with the following steps.\nMake sure to rerun step 1 after every change you make.\n\n1. Run `polymer analyze > analysis.json`\n\n1. Run `polymer serve`\n\n1. Open `http://127.0.0.1:PORT/components/polymer/` to view the documentation\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "// Copyright (c) 2017 The Polymer Authors. All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//    * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//    * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//    * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.md",
    "content": "# Polymer\n\n[![Build Status](https://travis-ci.org/Polymer/polymer.svg?branch=master)](https://travis-ci.org/Polymer/polymer)\n[![Published on npm](https://img.shields.io/npm/v/@polymer/polymer.svg)](https://www.npmjs.com/package/@polymer/polymer)\n[![Published on webcomponents.org](https://img.shields.io/badge/webcomponents.org-published-blue.svg)](https://www.webcomponents.org/element/@polymer/polymer)\n\n> ℹ️ Note: This is the current stable version of the Polymer library.  At Google I/O 2018 we announced a new Web Component base class, [`LitElement`](https://github.com/lit/lit), as a successor to the `PolymerElement` base class in this library.\n>\n> If you're starting a new project, we recommend that you consider using LitElement instead.\n>\n> If you have a project you've built with an earlier version of the Polymer library, we recommend that you [migrate](#about-polymer-30) to 3.0 for best compatibility with the JavaScript ecosystem. Thanks to the interoperability of Web Components, elements built with Polymer 3.0 and LitElement can be mixed and matched in the same app, so once you have updated your project to Polymer 3.0, you can migrate to LitElement incrementally, one element at a time.  See our blog post on the [Polymer Project roadmap](https://www.polymer-project.org/blog/2018-05-02-roadmap-update.html) for more information.\n\nPolymer lets you build encapsulated, reusable [Web Components](https://www.webcomponents.org/introduction) that work just like standard HTML elements, to use in building web applications.  Using a Web Component built with Polymer is as simple as importing its definition then using it like any other HTML element:\n\n```html\n<!-- Import a component -->\n<script src=\"https://unpkg.com/@polymer/paper-checkbox@next/paper-checkbox.js?module\" type=\"module\" ></script>\n\n<!-- Use it like any other HTML element -->\n<paper-checkbox>Web Components!</paper-checkbox>\n```\n\nWeb Components are now implemented natively on Safari and Chrome (~70% of installed browsers), and run well on Firefox, Edge, and IE11 using [polyfills](https://github.com/webcomponents/webcomponentsjs).  Read more [below](#overview).\n\n## Getting started\n\n * The easiest way to try out Polymer is to use one of these online tools:\n\n    * Runs in all [supported](#supported-browsers) browsers: [StackBlitz](https://stackblitz.com/edit/polymer-element-example?file=index.js), [Glitch](https://glitch.com/edit/#!/polymer-element-example?path=index.html)\n\n    * Runs in browsers with [JavaScript Modules](https://caniuse.com/#search=modules): [JSBin](https://jsbin.com/wuxejiz/edit?html,output),\n [CodePen](https://codepen.io/kevinpschaaf/pen/BxdErp?editors=1000).\n\n * You can also save [this HTML file](https://gist.githubusercontent.com/kevinpschaaf/8a5acbea7b25d2bb5e82eeea2b105669/raw/c3a86872f07603e2d0ddae736687e52a5c8c499f/index.html) to a local file and run it in any browser that supports [JavaScript Modules]((https://caniuse.com/#search=modules)).\n\n * When you're ready to use Polymer in a project, install it via [npm](https://www.npmjs.com/). To run the project in the browser,\n a module-compatible toolchain is required. We recommend installing the [Polymer CLI](https://github.com/Polymer/tools/tree/master/packages/cli) to and using its development server as follows.\n\n    1. Add Polymer to your project:\n\n        ```npm i @polymer/polymer```\n\n    1. Create an element by extending PolymerElement and calling `customElements.define` with your class (see the examples below).\n\n    1. Install the Polymer CLI:\n\n        ```npm i -g polymer-cli```\n\n    1. Run the development server and open a browser pointing to its URL:\n\n        ```polymer serve --npm```\n\n    > Polymer 3.0 is published on [npm](https://www.npmjs.com/package/@polymer/polymer) using JavaScript Modules.\n    This means it can take advantage of the standard native JavaScript module loader available in all current major browsers.\n    >\n    > However, since Polymer uses npm conventions to reference dependencies by name, a light transform to rewrite specifiers to URLs is required to run in the browser. The polymer-cli's development server `polymer serve`, as well as `polymer build` (for building an optimized app for deployment)  automatically handles this transform.\n\n    Tools like [webpack](https://webpack.js.org/) and [Rollup](https://rollupjs.org/) can also be used to serve and/or bundle Polymer elements.\n\n\n## Minimal Example\n\n  1. Create a class that extends `PolymerElement`.\n  1. Implement a static `properties` getter that describes the element's public property/attribute API\n  (these automatically become observed attributes).\n  1. Then implement a `template` getter that returns an `HTMLTemplateElement` describing the element's rendering, including encapsulated styling and any property bindings.\n\n```html\n  <script src=\"node_modules/@webcomponents/webcomponents-loader.js\"></script>\n  <script type=\"module\">\n    import {PolymerElement, html} from '@polymer/polymer';\n\n    class MyElement extends PolymerElement {\n      static get properties() { return { mood: String }}\n      static get template() {\n        return html`\n          <style> .mood { color: green; } </style>\n          Web Components are <span class=\"mood\">[[mood]]</span>!\n        `;\n      }\n    }\n\n    customElements.define('my-element', MyElement);\n  </script>\n\n  <my-element mood=\"happy\"></my-element>\n```\n\n## Overview\n\nWeb components are an incredibly powerful new set of primitives baked into the web platform, and open up a whole new world of possibility when it comes to componentizing front-end code and easily creating powerful, immersive, app-like experiences on the web.\n\nPolymer is a lightweight library built on top of the web standards-based [Web Components](http://webcomponents.org/introduction) APIs, and makes it easier to build your very own custom HTML elements. Creating reusable custom elements - and using elements built by others - can make building complex web applications easier and more efficient.\n\nBy being based on the Web Components APIs built in the browser (or [polyfilled](https://github.com/webcomponents/webcomponentsjs) where needed), elements built with Polymer are:\n\n* Built from the platform up\n* Self-contained\n* Re-usable\n* Interoperable across frameworks\n\nAmong many ways to leverage custom elements, they can be particularly useful for building reusable UI components. Instead of continually re-building a specific navigation bar or button in different frameworks and for different projects, you can define this element once using Polymer, and then reuse it throughout your project or in any future project.\n\nPolymer provides a declarative syntax to easily create your own custom elements, using all standard web technologies - define the structure of the element with HTML, style it with CSS, and add interactions to the element with JavaScript.\n\nPolymer also provides optional two-way data-binding, meaning:\n\n1. When properties in the model for an element get updated, the element can update itself in response.\n2. When the element is updated internally, the changes can be propagated back to the model.\n\nPolymer is designed to be flexible, lightweight, and close to the web platform - the library doesn't invent complex new abstractions and magic, but uses the best features of the web platform in straightforward ways to simply sugar the creation of custom elements.\n\n## About Polymer 3.0\n\nPolymer 3.0 is now released to stable, and introduces a major change to how Polymer is distributed: from HTML Imports on Bower, to JS modules on npm.  Otherwise, the API is almost entirely backward compatible with Polymer 2.0 (the only changes are removing APIs related to HTML Imports like `importHref`, and converting Polymer's API to be module-based rather than globals-based).\n\nMigrating to Polymer 3.0 by hand is mostly mechanical:\n* Components should be defined in JS modules instead of in HTML\n* Templates should be encoded in JS modules using a `static get template()` getter on PolymerElement subclasses using the `html` tagged template literal function (which parses `HTMLTemplateElement`s out of strings in JS) rather than using `<template>` elements in a `<dom-module>`\n* All dependencies should be imported JS module imports rather than HTML Imports.\n\nHowever, the [`polymer-modulizer`](https://github.com/Polymer/polymer-modulizer) tool automates the vast majority of this migration work.  Please see details on that repo for automated conversion of Polymer 2.0 apps and elements to Polymer 3.0.\n\n👀 **Looking for Polymer v2.x?** Please see [the v2 branch](https://github.com/Polymer/polymer/tree/2.x).\n\n👀 **Looking for Polymer v1.x?** Please see [the v1 branch](https://github.com/Polymer/polymer/tree/1.x).\n\n## Contributing\n\nThe Polymer team loves contributions from the community! Take a look at our [contributing guide](CONTRIBUTING.md) for more information on how to contribute.  Please file issues on the Polymer issue tracker following the issue template and contributing guide [issues](https://github.com/Polymer/polymer/issues/new).\n\n## Communicating with the Polymer team\n\nBeyond GitHub, we try to have a variety of different lines of communication available:\n\n* [Blog](https://blog.polymer-project.org/)\n* [Twitter](https://twitter.com/polymer)\n* [Mailing list](https://groups.google.com/forum/#!forum/polymer-dev)\n* [Slack channel](https://bit.ly/polymerslack)\n\n# License\n\nThe Polymer library uses a BSD-like license that is available [here](./LICENSE.txt)\n"
  },
  {
    "path": "RELEASING.md",
    "content": "## How to release a new version of Polymer\n\n- `npm ci`\n- `npm i -g np`\n- `npx gulp update-version`\n- Update CHANGELOG.md\n- Edit package.json back to the previous version so that `np` can be the one\n  to bump the version.\n- `np --yolo --preview`\n  - Ensures that you have permission, does a final check of all the steps.\n- `npm pack` and diff the tgz's contents against the previous version's.\n  We release a new version of Polymer rarely enough that it's worth it to be\n  careful.\n- `np --yolo`\n- After it completes successfully it will open the GitHub releases page for\n  your new version. Edit the changelist there to remove irrelevent entries and publish.\n"
  },
  {
    "path": "externs/.gitignore",
    "content": "# TODO(timvdlippe): Ignore all files here once we can generate them.\n# *\n!.gitignore\n!.npmignore\nclosure-types.js\n"
  },
  {
    "path": "externs/.npmignore",
    "content": ""
  },
  {
    "path": "externs/polymer-dom-api-externs.js",
    "content": "/**\n * @externs\n * @fileoverview Externs for PolymerDomApi for backwards compatibility with\n * the Polymer 1 externs.\n */\n\n/**\n * A Polymer DOM API for manipulating DOM such that local DOM and light DOM\n * trees are properly maintained.\n *\n * This type exists only to provide compatibility between compiled hybrid\n * Polymer V1 and V2 code. Polymer V2 only code should simply use the DomApi\n * class type.\n *\n * @interface\n */\nvar PolymerDomApi = function() {};\n\n/**\n * @param {?Node} node\n * @return {boolean}\n */\nPolymerDomApi.prototype.deepContains = function(node) {};\n\n/** @param {!Node} node */\nPolymerDomApi.prototype.appendChild = function(node) {};\n\n/**\n * @param {!Node} oldNode\n * @param {!Node} newNode\n */\nPolymerDomApi.prototype.replaceChild = function(oldNode, newNode) {};\n\n/**\n * @param {!Node} node\n * @param {?Node} beforeNode\n */\nPolymerDomApi.prototype.insertBefore = function(node, beforeNode) {};\n\n/** @param {!Node} node */\nPolymerDomApi.prototype.removeChild = function(node) {};\n\n/** @type {!Array<!HTMLElement>|!NodeList<!HTMLElement>} */\nPolymerDomApi.prototype.children;\n\n/** @type {!Array<!Node>|!NodeList<!Node>} */\nPolymerDomApi.prototype.childNodes;\n\n/** @type {?Node} */\nPolymerDomApi.prototype.parentNode;\n\n/** @type {?Node} */\nPolymerDomApi.prototype.firstChild;\n\n/** @type {?Node} */\nPolymerDomApi.prototype.lastChild;\n\n/** @type {?HTMLElement} */\nPolymerDomApi.prototype.firstElementChild;\n\n/** @type {?HTMLElement} */\nPolymerDomApi.prototype.lastElementChild;\n\n/** @type {?Node} */\nPolymerDomApi.prototype.previousSibling;\n\n/** @type {?Node} */\nPolymerDomApi.prototype.nextSibling;\n\n/** @type {?HTMLElement} */\nPolymerDomApi.prototype.previousElementSibling;\n\n/** @type {?HTMLElement} */\nPolymerDomApi.prototype.nextElementSibling;\n\n/** @type {string} */\nPolymerDomApi.prototype.textContent;\n\n/** @type {string} */\nPolymerDomApi.prototype.innerHTML;\n\n/** @type {?HTMLElement} */\nPolymerDomApi.prototype.activeElement;\n\n/**\n * @param {string} selector\n * @return {?Element}\n */\nPolymerDomApi.prototype.querySelector = function(selector) {};\n\n/**\n * @param {string} selector\n * @return {!Array<!Element>|!NodeList<!Element>}\n */\nPolymerDomApi.prototype.querySelectorAll = function(selector) {};\n\n/** @return {!Array<!Node>} */\nPolymerDomApi.prototype.getDistributedNodes = function() {};\n\n/** @return {!Array<!Node>} */\nPolymerDomApi.prototype.getDestinationInsertionPoints = function() {};\n\n/** @return {?Node} */\nPolymerDomApi.prototype.getOwnerRoot = function() {};\n\n/** @type {!Node} */\nPolymerDomApi.prototype.node;\n\n/**\n * @param {string} attribute\n * @param {string} value\n */\nPolymerDomApi.prototype.setAttribute = function(attribute, value) {};\n\n/** @param {string} attribute */\nPolymerDomApi.prototype.removeAttribute = function(attribute) {};\n\n/**\n * @typedef {function(!PolymerDomApi.ObserveInfo)}\n */\nPolymerDomApi.ObserveCallback;\n\n/**\n * @typedef {{\n *   target: !Node,\n *   addedNodes: !Array<!Node>,\n *   removedNodes: !Array<!Node>\n * }}\n */\nPolymerDomApi.ObserveInfo;\n\n/**\n * A virtual type for observer callback handles.\n *\n * @interface\n */\nPolymerDomApi.ObserveHandle = function() {};\n\n/**\n * @return {void}\n */\nPolymerDomApi.ObserveHandle.prototype.disconnect = function() {};\n\n/**\n * Notifies callers about changes to the element's effective child nodes,\n * the same list as returned by `getEffectiveChildNodes`.\n *\n * @param {!PolymerDomApi.ObserveCallback} callback The supplied callback\n * is called with an `info` argument which is an object that provides\n * the `target` on which the changes occurred, a list of any nodes\n * added in the `addedNodes` array, and nodes removed in the\n * `removedNodes` array.\n *\n * @return {!PolymerDomApi.ObserveHandle} Handle which is the argument to\n * `unobserveNodes`.\n */\nPolymerDomApi.prototype.observeNodes = function(callback) {};\n\n/**\n * Stops observing changes to the element's effective child nodes.\n *\n * @param {!PolymerDomApi.ObserveHandle} handle The handle for the\n * callback that should no longer receive notifications. This\n * handle is returned from `observeNodes`.\n */\nPolymerDomApi.prototype.unobserveNodes = function(handle) {};\n\n/** @type {?DOMTokenList} */\nPolymerDomApi.prototype.classList;\n\n/**\n * @param {string} selector\n * @return {!Array<!HTMLElement>}\n */\nPolymerDomApi.prototype.queryDistributedElements = function(selector) {};\n\n/**\n * Returns a list of effective child nodes for this element.\n *\n * @return {!Array<!HTMLElement>}\n */\nPolymerDomApi.prototype.getEffectiveChildNodes = function() {};\n"
  },
  {
    "path": "externs/polymer-externs.js",
    "content": "/**\n * @fileoverview Externs for Polymer Pass and external Polymer API\n * @externs\n *\n * @license\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\n * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\n * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\n * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\n * Code distributed by Google as part of the polymer project is also\n * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n */\n\n/* eslint-disable */\n\n/**\n * @typedef {{\n *   type: !Function,\n *   value: (* | undefined),\n *   readOnly: (boolean | undefined),\n *   computed: (string | undefined),\n *   reflectToAttribute: (boolean | undefined),\n *   notify: (boolean | undefined),\n *   observer: (string | function(this:?, ?, ?) | undefined)\n * }}\n */\nlet PolymerElementPropertiesMeta;\n\n/**\n * @typedef {Object<string, !Function|!PolymerElementPropertiesMeta>}\n */\nlet PolymerElementProperties;\n\n/** @record */\nlet PolymerInit = function() {};\n/** @type {string} */\nPolymerInit.prototype.is;\n/** @type {(string | undefined)} */\nPolymerInit.prototype.extends;\n/** @type {(!PolymerElementProperties | undefined)} */\nPolymerInit.prototype.properties;\n/** @type {(!Array<string> | undefined)} */\nPolymerInit.prototype.observers;\n/** @type {(!HTMLTemplateElement | string | undefined | null)} */\nPolymerInit.prototype.template;\n/** @type {(!Object<string, *> | undefined)} */\nPolymerInit.prototype.hostAttributes;\n/** @type {(!Object<string, string> | undefined)} */\nPolymerInit.prototype.listeners;\n/** @type {(!Object| !Array<!Object> | undefined)} */\nPolymerInit.prototype.behaviors;\n\n/** @record */\nlet PolymerElementConstructor = function () {};\n/** @type {(string | undefined)} */\nPolymerElementConstructor.is;\n/** @type {(string | undefined)} */\nPolymerElementConstructor.extends;\n/** @type {(!PolymerElementProperties | undefined)} */\nPolymerElementConstructor.properties;\n/** @type {(!Array<string> | undefined)} */\nPolymerElementConstructor.observers;\n/** @type {(!HTMLTemplateElement | string | undefined | null)} */\nPolymerElementConstructor.template;\n\n/** @interface */\nlet PropertiesMixinConstructor = function () {};\n/** @type {(!PolymerElementProperties | undefined)} */\nPropertiesMixinConstructor.prototype.properties;\n/** @return {void} */\nPropertiesMixinConstructor.prototype.finalize = function() {};\n\n/**\n * @param {!PolymerInit} init\n * @return {!function(new:HTMLElement)}\n */\nfunction Polymer(init){}\n\n/**\n * @type {(function(*,string,string,Node):*)|undefined}\n */\nPolymer.sanitizeDOMValue;\n\n/**\n * @type {boolean}\n */\nPolymer.passiveTouchGestures;\n\n/**\n * @type {boolean}\n */\nPolymer.strictTemplatePolicy;\n\n/**\n * @type {boolean}\n */\nPolymer.allowTemplateFromDomModule;\n\n/**\n * @type {string}\n */\nPolymer.rootPath;\n\n/**\n * @param {string} string\n * @param {Object} obj\n * @return {string}\n */\nfunction JSCompiler_renameProperty(string, obj) {}\n\n/** @record */\nfunction PolymerTelemetry() {}\n/** @type {number} */\nPolymerTelemetry.instanceCount;\n/** @type {function():void} */\nPolymerTelemetry.incrementInstanceCount;\n/** @type {Array<HTMLElement>} */\nPolymerTelemetry.registrations;\n/** @type {function(HTMLElement)} */\nPolymerTelemetry._regLog;\n/** @type {function(HTMLElement)} */\nPolymerTelemetry.register;\n/** @type {function(HTMLElement)} */\nPolymerTelemetry.dumpRegistrations;\n\n/** @type {PolymerTelemetry} */\nPolymer.telemetry;\n\n/** @type {string} */\nPolymer.version;\n\n/** @type {boolean} */\nPolymer.legacyOptimizations;\n\n/** @type {boolean} */\nPolymer.syncInitialRender;\n\n/** @type {boolean} */\nPolymer.legacyUndefined;\n\n/** @type {boolean} */\nPolymer.legacyWarnings;\n\n/** @type {boolean} */\nPolymer.orderedComputed;\n\n/** @type {boolean} */\nPolymer.fastDomIf;\n\n/** @type {boolean} */\nPolymer.removeNestedTemplates;\n\n/** @type {boolean} */\nPolymer.suppressTemplateNotifications;\n\n// nb. This is explicitly 'var', as Closure Compiler checks that this is the case.\n/**\n * @constructor\n * @extends {HTMLElement}\n * @implements {Polymer_LegacyElementMixin}\n */\nvar PolymerElement = function() {};\n\n/**\n * The tag name of the cutom element type.\n * @type {string|undefined}\n */\nPolymerElement.is;\n/**\n * The template to stamp when creating this element type.\n * @type {!HTMLTemplateElement|undefined|null}\n */\nPolymerElement.template;\n/**\n * The properties of the cutom element type.\n * @type {!PolymerElementProperties|undefined}\n */\nPolymerElement.properties;\n/**\n * The observers of this custom element type.\n * @type {!Array<string>|undefined}\n */\nPolymerElement.observers;\n/** @type {!PolymerInit|undefined} */\nPolymerElement.generatedFrom;\n\n/**\n * On create callback.\n * @override\n */\nPolymerElement.prototype.created = function() {};\n/**\n * On ready callback.\n * @override\n */\nPolymerElement.prototype.ready = function() {};\n/** On before register callback. */\nPolymerElement.prototype.beforeRegister = function() {};\n/** On registered callback. */\nPolymerElement.prototype.registered = function() {};\n/**\n * On attached to the DOM callback.\n * @override\n */\nPolymerElement.prototype.attached = function() {};\n/**\n * On detached from the DOM callback.\n * @override\n */\nPolymerElement.prototype.detached = function() {};\n\n/**\n * @typedef {{\n *   index: number,\n *   removed: !Array,\n *   addedCount: number,\n *   object: !Array,\n *   type: string,\n * }}\n */\nvar PolymerSplice;\n/**\n * @typedef {{\n *   indexSplices: ?Array<!PolymerSplice>,\n * }}\n */\nvar PolymerSpliceChange;\n\n/**\n * The type of the object received by an observer function when deep\n * sub-property observation is enabled. See:\n * https://www.polymer-project.org/2.0/docs/devguide/observers#deep-observation\n *\n * @typedef {{\n *   path: string,\n *   value: (?Object|undefined),\n *   base: (?Object|undefined)\n * }}\n */\nvar PolymerDeepPropertyChange;\n\n/**\n * Event object for events dispatched by children of a dom-repeat template.\n * @see https://www.polymer-project.org/2.0/docs/devguide/templates#handling-events\n * @extends {Event}\n * @constructor\n * @template T\n */\nvar DomRepeatEvent = function() {};\n\n/**\n * @type {{\n *   index: number,\n *   item: T\n * }}\n */\nDomRepeatEvent.prototype.model;\n"
  },
  {
    "path": "externs/polymer-iconset-externs.js",
    "content": "/**\n * @externs\n * @fileoverview Externs for Polymer.Iconset.\n */\n\n/**\n * The interface that iconsets should obey. Iconsets are registered by setting\n * their name in the IronMeta 'iconset' db, and a value of type Polymer.Iconset.\n *\n * Used by iron-icon but needs to live here since iron-icon, iron-iconset, etc don't\n * depend on each other at all and talk only through iron-meta.\n *\n * @interface\n */\nPolymer.Iconset = function() {};\n\n/**\n * Applies an icon to the given element as a css background image. This\n * method does not size the element, and it's usually necessary to set\n * the element's height and width so that the background image is visible.\n *\n * @param {Element} element The element to which the icon is applied.\n * @param {string} icon The name of the icon to apply.\n * @param {string=} theme (optional) The name or index of the icon to apply.\n * @param {number=} scale (optional, defaults to 1) Icon scaling factor.\n */\nPolymer.Iconset.prototype.applyIcon = function(\n      element, icon, theme, scale) {};\n\n/**\n * Remove an icon from the given element by undoing the changes effected\n * by `applyIcon`.\n *\n * @param {Element} element The element from which the icon is removed.\n */\nPolymer.Iconset.prototype.removeIcon = function(element) {};\n"
  },
  {
    "path": "externs/polymer-internal-shared-types.js",
    "content": "/**\n * @fileoverview Internal shared types for Polymer\n * @externs\n *\n * @license\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\n * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\n * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\n * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\n * Code distributed by Google as part of the polymer project is also\n * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n */\n\n/* eslint-disable no-unused-vars, strict, valid-jsdoc */\n\n/**\n * @constructor\n * @extends {DocumentFragment}\n */\nfunction StampedTemplate() { }\n/** @type {boolean} */\nStampedTemplate.prototype.__noInsertionPoint;\n/** @type {!Array<!Node>} */\nStampedTemplate.prototype.nodeList;\n/** @type {!Object<string, !Element>} */\nStampedTemplate.prototype.$;\n/** @type {!TemplateInfo | undefined} */\nStampedTemplate.prototype.templateInfo;\n\n/** @interface */\nfunction NodeInfo() { }\n/** @type {string} */\nNodeInfo.prototype.id;\n/** @type {!Array<{name: string, value: string}>}*/\nNodeInfo.prototype.events;\n/** @type {boolean} */\nNodeInfo.prototype.hasInsertionPoint;\n/** @type {!TemplateInfo} */\nNodeInfo.prototype.templateInfo;\n/** @type {!NodeInfo} */\nNodeInfo.prototype.parentInfo;\n/** @type {number} */\nNodeInfo.prototype.parentIndex;\n/** @type {number} */\nNodeInfo.prototype.infoIndex;\n/** @type {!Array<!Binding>} */\nNodeInfo.prototype.bindings;\n\n/** @interface */\nfunction TemplateInfo() { }\n/** @type {!Array<!NodeInfo>} */\nTemplateInfo.prototype.nodeInfoList;\n/** @type {!Array<!Node>} */\nTemplateInfo.prototype.nodeList;\n/** @type {boolean} */\nTemplateInfo.prototype.stripWhitespace;\n/** @type {boolean | undefined} */\nTemplateInfo.prototype.hasInsertionPoint;\n/** @type {!Object} */\nTemplateInfo.prototype.hostProps;\n/** @type {!Object} */\nTemplateInfo.prototype.propertyEffects;\n/** @type {TemplateInfo | undefined} */\nTemplateInfo.prototype.nextSibling;\n/** @type {TemplateInfo | undefined} */\nTemplateInfo.prototype.previousSibling;\n/** @type {TemplateInfo | undefined} */\nTemplateInfo.prototype.firstChild;\n/** @type {TemplateInfo | undefined} */\nTemplateInfo.prototype.parent;\n/** @type {!Array<!Node>} */\nTemplateInfo.prototype.childNodes;\n/** @type {boolean} */\nTemplateInfo.prototype.wasPreBound;\n\n/**\n * type for HTMLTemplateElement with `_templateInfo`\n *\n * @constructor\n * @extends {HTMLTemplateElement}\n */\nfunction HTMLTemplateElementWithInfo() { }\n/** @type {TemplateInfo} */\nHTMLTemplateElementWithInfo.prototype._templateInfo;\n\n/**\n * @typedef {{\n * literal: string,\n * compoundIndex: (number | undefined)\n * }}\n */\nlet LiteralBindingPart;\n\n/**\n * @typedef {{\n * literal: boolean,\n * name: string,\n * value: (string | number),\n * rootProperty: (string | undefined),\n * structured: (boolean | undefined),\n * wildcard: (boolean | undefined)\n * }}\n */\nlet MethodArg;\n\n/**\n * @typedef {{\n * methodName: string,\n * static: boolean,\n * args: !Array<!MethodArg>,\n * dynamicFn: (boolean | undefined),\n * }}\n */\nlet MethodSignature;\n\n/**\n * @typedef {{\n * mode: string,\n * negate: boolean,\n * source: string,\n * dependencies: !Array<(!MethodArg|string)>,\n * customEvent: boolean,\n * signature: Object,\n * event: string\n * }}\n */\nlet ExpressionBindingPart;\n\n/**\n * @typedef {LiteralBindingPart | ExpressionBindingPart}\n */\nlet BindingPart;\n\n/**\n * @typedef {{\n * kind: string,\n * target: string,\n * parts: Array<!BindingPart>,\n * literal: (string | undefined),\n * isCompound: boolean,\n * listenerEvent: (string | undefined),\n * listenerNegate: (boolean | undefined)\n * }}\n */\nlet Binding;\n\n/**\n * @typedef {{\n * path: string\n * }}\n */\nlet PathInfo;\n\n/**\n * @typedef {{\n * forwardHostProp: (function(string, *) | undefined),\n * instanceProps: (Object | undefined),\n * mutableData: (boolean | undefined),\n * notifyInstanceProp: (function(*, string, *) | undefined),\n * parentModel: (boolean | undefined)\n * }}\n */\nlet TemplatizeOptions;\n\n/** @record */\nfunction AsyncInterface(){}\n/** @type {function(!Function, number=): number} */\nAsyncInterface.prototype.run;\n/** @type {function(number): void} */\nAsyncInterface.prototype.cancel;\n\n/** @record */\nlet GestureInfo = function(){};\n/** @type {string|undefined} */\nGestureInfo.prototype.state;\n/** @type {boolean|undefined} */\nGestureInfo.prototype.started;\n/** @type {!Array<?>|undefined} */\nGestureInfo.prototype.moves;\n/** @type {number|undefined} */\nGestureInfo.prototype.x;\n/** @type {number|undefined} */\nGestureInfo.prototype.y;\n/** @type {boolean|undefined} */\nGestureInfo.prototype.prevent;\n/** @type {function(?): void|undefined} */\nGestureInfo.prototype.addMove;\n/** @type {null|undefined} */\nGestureInfo.prototype.movefn;\n/** @type {null|undefined} */\nGestureInfo.prototype.upFn;\n\n/** @record */\nlet GestureRecognizer = function(){};\n/** @type {string} */\nGestureRecognizer.prototype.name;\n/** @type {!Array<string>} */\nGestureRecognizer.prototype.deps;\n/** @type {function(): void} */\nGestureRecognizer.prototype.reset;\n/** @type {function(MouseEvent): void | undefined} */\nGestureRecognizer.prototype.mousedown;\n/** @type {(function(MouseEvent): void | undefined)} */\nGestureRecognizer.prototype.mousemove;\n/** @type {(function(MouseEvent): void | undefined)} */\nGestureRecognizer.prototype.mouseup;\n/** @type {(function(TouchEvent): void | undefined)} */\nGestureRecognizer.prototype.touchstart;\n/** @type {(function(TouchEvent): void | undefined)} */\nGestureRecognizer.prototype.touchmove;\n/** @type {(function(TouchEvent): void | undefined)} */\nGestureRecognizer.prototype.touchend;\n/** @type {(function(MouseEvent): void | undefined)} */\nGestureRecognizer.prototype.click;\n/** @type {!GestureInfo} */\nGestureRecognizer.prototype.info;\n/** @type {!Array<string>} */\nGestureRecognizer.prototype.emits;\n"
  },
  {
    "path": "externs/polymer-internal-types.html",
    "content": "<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<!-- internal shared types for closure pass -->\n<script src=\"polymer-internal-shared-types.js\"></script>"
  },
  {
    "path": "externs/webcomponents-externs.js",
    "content": "/**\n * @fileoverview Externs for webcomponents polyfills\n * @externs\n * @suppress {duplicate}\n *\n * @license\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\n * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\n * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\n * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\n * Code distributed by Google as part of the polymer project is also\n * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n */\n/* eslint-disable */\n\nvar HTMLImports = {};\n\n/**\n * @param {function()=} callback\n */\nHTMLImports.whenReady = function(callback) {};\n\n/**\n * Returns the import document containing the element.\n * @param {!Node} element\n * @return {?HTMLLinkElement|?Document|undefined}\n */\nHTMLImports.importForElement = function(element) {};\n\nwindow.HTMLImports = HTMLImports;\n\nvar ShadyDOM = {};\n\nShadyDOM.inUse;\nShadyDOM.composedPath;\n\nShadyDOM.flush = function() {};\n\n/**\n * @param {!Node} target\n * @param {function(Array<MutationRecord>, MutationObserver)} callback\n * @return {MutationObserver}\n */\nShadyDOM.observeChildren = function(target, callback) {};\n\n/**\n * @param {MutationObserver} observer\n */\nShadyDOM.unobserveChildren = function(observer) {};\n\n/**\n * @param {Node} node\n */\nShadyDOM.patch = function(node) {};\n\n/**\n * @param {!ShadowRoot} shadowroot\n */\nShadyDOM.flushInitial = function(shadowroot) {};\n\nwindow.ShadyDOM = ShadyDOM;\n\nvar WebComponents = {};\nwindow.WebComponents = WebComponents;\n\n/** @type {Element} */\nHTMLElement.prototype._activeElement;\n\n/**\n * @param {HTMLTemplateElement} template\n */\nHTMLTemplateElement.decorate = function(template){};\n\n/**\n * @param {function(function())} cb callback\n */\nCustomElementRegistry.prototype.polyfillWrapFlushCallback = function(cb){};\n\n/**\n * @param {string} cssText\n */\nCSSStyleSheet.prototype.replaceSync = function(cssText) {};\n"
  },
  {
    "path": "gulpfile.js",
    "content": "/**\n * @license\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\n * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\n * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\n * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\n * Code distributed by Google as part of the polymer project is also\n * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n */\n\n/* eslint-env node */\n'use strict';\n\nconst gulp = require('gulp');\nconst gulpif = require('gulp-if');\nconst del = require('del');\nconst eslint = require('gulp-eslint');\nconst fs = require('fs-extra');\nconst path = require('path');\nconst mergeStream = require('merge-stream');\nconst babel = require('gulp-babel');\nconst size = require('gulp-size');\nconst lazypipe = require('lazypipe');\nconst closure = require('google-closure-compiler').gulp();\nconst minimalDocument = require('./util/minimalDocument.js');\nconst dom5 = require('dom5/lib/index-next');\nconst parse5 = require('parse5');\nconst replace = require('gulp-replace');\n\nconst DIST_DIR = 'dist';\nconst BUNDLED_DIR = path.join(DIST_DIR, 'bundled');\nconst COMPILED_DIR = path.join(DIST_DIR, 'compiled');\nconst POLYMER_LEGACY = 'polymer-legacy.js';\n\nconst {PolymerProject, HtmlSplitter} = require('polymer-build');\n\nconst {Transform} = require('stream');\n\nclass BackfillStream extends Transform {\n  constructor(fileList) {\n    super({objectMode: true});\n    this.fileList = fileList;\n  }\n  _transform(file, enc, cb) {\n    if (this.fileList) {\n      const origFile = this.fileList.shift();\n      // console.log(`rename ${file.path} -> ${origFile.path}`)\n      file.path = origFile.path;\n    }\n    cb(null, file);\n  }\n  _flush(cb) {\n    if (this.fileList && this.fileList.length > 0) {\n      this.fileList.forEach((oldFile) => {\n        // console.log(`pumping fake file ${oldFile.path}`)\n        let newFile = oldFile.clone({deep: true, contents: false});\n        newFile.contents = new Buffer('');\n        this.push(newFile);\n      });\n    }\n    cb();\n  }\n}\n\nlet firstImportFinder = dom5.predicates.AND(\n  dom5.predicates.hasTagName('link'), dom5.predicates.hasAttrValue('rel', 'import')\n);\n\nconst header =\n`/**\n * @fileoverview Generated typings for Polymer mixins\n * @externs\n * @suppress {checkPrototypalTypes}\n *\n * @license\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\n * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\n * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\n * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\n * Code distributed by Google as part of the polymer project is also\n * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n */\n/* eslint-disable */\n`;\n\nclass AddClosureTypeImport extends Transform {\n  constructor(entryFileName, typeFileName) {\n    super({objectMode: true});\n    this.target = path.resolve(entryFileName);\n    this.importPath = path.resolve(typeFileName);\n  }\n  _transform(file, enc, cb) {\n    if (file.path === this.target) {\n      let contents = file.contents.toString();\n      let html = parse5.parse(contents, {locationInfo: true});\n      let firstImport = dom5.query(html, firstImportFinder);\n      if (firstImport) {\n        let importPath = path.relative(path.dirname(this.target), this.importPath);\n        let importLink = dom5.constructors.element('link');\n        dom5.setAttribute(importLink, 'rel', 'import');\n        dom5.setAttribute(importLink, 'href', importPath);\n        dom5.insertBefore(firstImport.parentNode, firstImport, importLink);\n        dom5.removeFakeRootElements(html);\n        file.contents = Buffer(parse5.serialize(html));\n      }\n    }\n    cb(null, file);\n  }\n}\n\ngulp.task('clean', () => del([DIST_DIR, 'closure.log']));\n\ngulp.task('generate-externs', gulp.series('clean', async () => {\n  let genClosure = require('@polymer/gen-closure-declarations').generateDeclarations;\n  const declarations = await genClosure();\n  await fs.writeFile('externs/closure-types.js', `${header}${declarations}`);\n}));\n\nconst runClosureOnly = ({lintOnly}) => () => {\n  let entry, splitRx, joinRx, addClosureTypes;\n\n  function config(path) {\n    entry = path;\n    joinRx = new RegExp(path.split('/').join('\\\\/'));\n    splitRx = new RegExp(joinRx.source + '_script_\\\\d+\\\\.js$');\n    addClosureTypes = new AddClosureTypeImport(entry, 'externs/polymer-internal-types.html');\n  }\n\n  config('polymer-legacy.js');\n\n  const project = new PolymerProject({\n    shell: `./${entry}`,\n    fragments: [\n      'node_modules/@webcomponents/shadycss/entrypoints/apply-shim.js',\n      'node_modules/@webcomponents/shadycss/entrypoints/custom-style-interface.js'\n    ],\n    extraDependencies: [\n      addClosureTypes.importPath,\n      'externs/polymer-internal-shared-types.js',\n    ]\n  });\n\n  function closureLintLogger(log) {\n    let chalk = require('chalk');\n    // write out log to use with diffing tools later\n    fs.writeFileSync('closure.log', chalk.stripColor(log));\n    console.error(log);\n    process.exit(-1);\n  }\n\n  let closurePluginOptions;\n\n  if (lintOnly) {\n    closurePluginOptions = {\n      logger: closureLintLogger\n    };\n  }\n\n  const closureStream = closure({\n    compilation_level: 'ADVANCED',\n    language_in: 'ES6_STRICT',\n    language_out: 'ES5_STRICT',\n    warning_level: 'VERBOSE',\n    isolation_mode: 'IIFE',\n    assume_function_wrapper: true,\n    rewrite_polyfills: false,\n    new_type_inf: true,\n    checks_only: lintOnly,\n    polymer_version: 2,\n    externs: [\n      'bower_components/shadycss/externs/shadycss-externs.js',\n      'externs/webcomponents-externs.js',\n      'externs/closure-types.js',\n      'externs/polymer-externs.js',\n      'externs/polymer-dom-api-externs.js',\n    ],\n    extra_annotation_name: [\n      'appliesMixin',\n      'mixinClass',\n      'mixinFunction',\n      'polymer',\n      'customElement'\n    ]\n  }, closurePluginOptions);\n\n  const closurePipeline = lazypipe()\n    .pipe(() => closureStream)\n    .pipe(() => new BackfillStream(closureStream.fileList_));\n\n  // process source files in the project\n  const sources = project.sources();\n\n  // process dependencies\n  const dependencies = project.dependencies();\n\n  // merge the source and dependencies streams to we can analyze the project\n  const mergedFiles = mergeStream(sources, dependencies);\n\n  const splitter = new HtmlSplitter();\n  return mergedFiles\n    .pipe(addClosureTypes)\n    .pipe(project.bundler())\n    .pipe(splitter.split())\n    .pipe(gulpif(splitRx, closurePipeline()))\n    .pipe(splitter.rejoin())\n    .pipe(gulpif(joinRx, minimalDocument()))\n    .pipe(gulpif(joinRx, size({title: 'closure size', gzip: true, showTotal: false, showFiles: true})))\n    .pipe(gulp.dest(COMPILED_DIR));\n};\n\ngulp.task('closure', gulp.series('generate-externs', runClosureOnly({\n  lintOnly: false\n})));\n\ngulp.task('lint-closure', runClosureOnly({\n  lintOnly: true\n}));\n\ngulp.task('estimate-size', gulp.series('clean', () => {\n\n  const babelPresets = {\n    presets: [['minify', {regexpConstructors: false, simplifyComparisons: false}]]\n  };\n\n  const project = new PolymerProject({\n    shell: POLYMER_LEGACY,\n    fragments: [\n      'node_modules/@webcomponents/shadycss/entrypoints/apply-shim.js',\n      'node_modules/@webcomponents/shadycss/entrypoints/custom-style-interface.js'\n    ]\n  });\n\n  // process source files in the project\n  const sources = project.sources();\n\n  // process dependencies\n  const dependencies = project.dependencies();\n\n  // merge the source and dependencies streams to we can analyze the project\n  const mergedFiles = mergeStream(sources, dependencies);\n\n  const bundledSplitter = new HtmlSplitter();\n\n  const bundlePipe = lazypipe()\n  .pipe(() => bundledSplitter.split())\n  .pipe(() => gulpif(/\\.js$/, babel(babelPresets)))\n  .pipe(() => bundledSplitter.rejoin())\n  .pipe(minimalDocument);\n\n  return mergedFiles\n    .pipe(project.bundler())\n    .pipe(gulpif(/polymer\\.html$/, bundlePipe()))\n    .pipe(gulpif(/polymer\\.html$/, size({ title: 'bundled size', gzip: true, showTotal: false, showFiles: true })))\n    // write to the bundled folder\n    .pipe(gulp.dest(BUNDLED_DIR));\n}));\n\ngulp.task('lint-eslint', function() {\n  return gulp.src(['lib/**/*.js', 'test/unit/*.{html,js}', 'util/*.js'])\n    .pipe(eslint())\n    .pipe(eslint.format())\n    .pipe(eslint.failAfterError());\n});\n\n// TODO(timvdlippe): Add back `, 'lint-closure'` once closure lint works again\ngulp.task('lint', gulp.series('lint-eslint'));\n\n// TODO(timvdlippe): Add back `'generate-externs',` once we can generate externs again\n\ngulp.task('update-version', () => {\n  return gulp.src('lib/mixins/element-mixin.js')\n  .pipe(replace(/(export const version = )'\\d+\\.\\d+\\.\\d+'/, `$1'${require('./package.json').version}'`))\n  .pipe(gulp.dest('lib/mixins'));\n});\n"
  },
  {
    "path": "index.html",
    "content": "<!doctype html>\n<!--\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n\n  <meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n\n  <script src=\"../../@webcomponents/webcomponentsjs/webcomponents-lite.js\"></script>\n  <script type=\"module\" src=\"../../@polymer/iron-component-page/iron-component-page.js\"></script>\n\n</head>\n<body>\n\n  <iron-component-page></iron-component-page>\n\n</body>\n</html>\n"
  },
  {
    "path": "interfaces.d.ts",
    "content": "/**\n * This file contains the types that are required for compilation of the\n * Polymer generated type declarations, but which could not themselves be\n * automatically generated.\n */\n\n// Types from \"externs/polymer-externs.js\"\n\nexport interface PolymerElementPropertiesMeta {\n  type?: Function;\n  value?: any;\n  readOnly?: boolean;\n  computed?: string;\n  reflectToAttribute?: boolean;\n  notify?: boolean;\n  observer?: string|((val: any, old: any) => void);\n}\n\nexport type PolymerElementProperties = {\n  [key: string]: PolymerElementPropertiesMeta|Function;\n};\n\n// TODO Document these properties.\nexport interface PolymerInit {\n  is: string;\n  extends?: string;\n  properties?: PolymerElementProperties;\n  observers?: string[];\n  _template?: HTMLTemplateElement|(() => HTMLTemplateElement);\n  hostAttributes?: {[key: string]: any};\n  listeners?: {[key: string]: string};\n  behaviors?: BehaviorInit | BehaviorInit[];\n\n  // Lifecycle methods\n  registered?(): void;\n  created?(): void;\n  attached?(): void;\n  detached?(): void;\n  ready?(): void;\n  attributeChanged?(name: string, old?: string, value?: string): void;\n\n  // Allow any other user-defined properties\n  [others: string]: any;\n}\n\nexport type BehaviorInit = Pick<\n  PolymerInit,\n  Exclude<keyof PolymerInit, \"is\" | \"extends\" | \"_template\">\n>;\n\n/**\n * The object passed to \".*\" wildcard obsevers. A record of a change made to an\n * object.\n * @template B The object matching the non-wildcard portion of the path.\n * @template V Additional types that could be set at the path.\n */\nexport interface PolymerDeepPropertyChange<B, V> {\n  /** Path to the property that changed. */\n  path: string;\n  /** The object matching the non-wildcard portion of the path. */\n  base: B;\n  /** New value of the path that changed. */\n  value: B|V;\n}\n\n/**\n * A record of changes made to an array.\n * @template T The type of the array being observed.\n */\nexport interface PolymerSplice<T extends Array<{}|null|undefined>> {\n  /** Position where the splice started. */\n  index: number;\n  /** Array of removed items. */\n  removed: T;\n  /** Number of new items inserted at index. */\n  addedCount: number;\n  /** A reference to the array in question. */\n  object: T;\n  /** The string literal 'splice'. */\n  type: 'splice';\n}\n\n/**\n * The object passed to \".splices\" observers. A set of mutations made to the\n * array.\n * @template T The type of the array being observed.\n */\nexport interface PolymerSpliceChange<T extends Array<{}|null|undefined>> {\n  indexSplices: Array<PolymerSplice<T>>;\n}\n\n// Types from \"externs/polymer-internal-shared-types.js\"\n\nexport interface StampedTemplate extends DocumentFragment {\n  __noInsertionPoint: boolean;\n  nodeList: Node[];\n  $: {[key: string]: Node};\n  templateInfo?: TemplateInfo;\n}\n\nexport interface NodeInfo {\n  id: string;\n  events: {name: string, value: string}[];\n  hasInsertionPoint: boolean;\n  templateInfo: TemplateInfo;\n  parentInfo: NodeInfo;\n  parentIndex: number;\n  infoIndex: number;\n  bindings: Binding[];\n}\n\nexport interface TemplateInfo {\n  nodeInfoList: NodeInfo[];\n  nodeList: Node[];\n  stripWhitespace: boolean;\n  hasInsertionPoint?: boolean;\n  hostProps: Object;\n  propertyEffects: Object;\n  childNodes: Node[];\n  wasPreBound: boolean;\n}\n\nexport interface LiteralBindingPart {\n  literal: string;\n  compoundIndex?: number;\n}\n\nexport interface MethodArg {\n  literal: boolean;\n  name: string;\n  value: string|number;\n  rootProperty?: string;\n  structured?: boolean;\n  wildcard?: boolean;\n}\n\nexport interface MethodSignature {\n  methodName: string;\n  static: boolean;\n  args: MethodArg[];\n  dynamicFn?: boolean;\n}\n\nexport interface ExpressionBindingPart {\n  mode: string;\n  negate: boolean;\n  source: string;\n  dependencies: Array<MethodArg|string>;\n  customEvent: boolean;\n  signature: Object|null;\n  event: string;\n}\n\nexport type BindingPart = LiteralBindingPart|ExpressionBindingPart;\n\nexport interface Binding {\n  kind: string;\n  target: string;\n  parts: BindingPart[];\n  literal?: string;\n  isCompound: boolean;\n  listenerEvent?: string;\n  listenerNegate?: boolean;\n}\n\nexport interface AsyncInterface {\n  run: (fn: Function, delay?: number) => number;\n  cancel: (handle: number) => void;\n}\n\n// Types from \"lib/utils/gestures.html\"\n\nexport interface GestureRecognizer {\n  reset: () => void;\n  mousedown?: (e: MouseEvent) => void;\n  mousemove?: (e: MouseEvent) => void;\n  mouseup?: (e: MouseEvent) => void;\n  touchstart?: (e: TouchEvent) => void;\n  touchmove?: (e: TouchEvent) => void;\n  touchend?: (e: TouchEvent) => void;\n  click?: (e: MouseEvent) => void;\n}\n\n/**\n * Not defined in the TypeScript DOM library.\n * See https://developer.mozilla.org/en-US/docs/Web/API/IdleDeadline\n */\nexport interface IdleDeadline {\n  didTimeout: boolean;\n  timeRemaining(): number;\n}\n\nexport interface PolymerElementConstructor {\n  new (): HTMLElement;\n  is?: string;\n  extends?: string;\n  properties?: PolymerElementProperties;\n  observers?: string[];\n  template?: string|HTMLTemplateElement|null;\n}\n"
  },
  {
    "path": "lib/elements/array-selector.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n// tslint:disable:no-any describes the API as best we are able today\n\nimport {PolymerElement} from '../../polymer-element.js';\n\nimport {dedupingMixin} from '../utils/mixin.js';\n\nimport {calculateSplices} from '../utils/array-splice.js';\n\nimport {ElementMixin} from '../mixins/element-mixin.js';\n\n\n/**\n * Element mixin for recording dynamic associations between item paths in a\n * master `items` array and a `selected` array such that path changes to the\n * master array (at the host) element or elsewhere via data-binding) are\n * correctly propagated to items in the selected array and vice-versa.\n *\n * The `items` property accepts an array of user data, and via the\n * `select(item)` and `deselect(item)` API, updates the `selected` property\n * which may be bound to other parts of the application, and any changes to\n * sub-fields of `selected` item(s) will be kept in sync with items in the\n * `items` array.  When `multi` is false, `selected` is a property\n * representing the last selected item.  When `multi` is true, `selected`\n * is an array of multiply selected items.\n */\ndeclare function ArraySelectorMixin<T extends new (...args: any[]) => {}>(base: T): T & ArraySelectorMixinConstructor & ElementMixinConstructor & PropertyEffectsConstructor & TemplateStampConstructor & PropertyAccessorsConstructor & PropertiesChangedConstructor & PropertiesMixinConstructor;\n\nimport {ElementMixinConstructor} from '../mixins/element-mixin.js';\n\nimport {PropertyEffectsConstructor, PropertyEffects} from '../mixins/property-effects.js';\n\nimport {TemplateStampConstructor, TemplateStamp} from '../mixins/template-stamp.js';\n\nimport {PropertyAccessorsConstructor, PropertyAccessors} from '../mixins/property-accessors.js';\n\nimport {PropertiesChangedConstructor, PropertiesChanged} from '../mixins/properties-changed.js';\n\nimport {PropertiesMixinConstructor, PropertiesMixin} from '../mixins/properties-mixin.js';\n\ninterface ArraySelectorMixinConstructor {\n  new(...args: any[]): ArraySelectorMixin;\n}\n\nexport {ArraySelectorMixinConstructor};\n\ninterface ArraySelectorMixin extends ElementMixin, PropertyEffects, TemplateStamp, PropertyAccessors, PropertiesChanged, PropertiesMixin {\n\n  /**\n   * An array containing items from which selection will be made.\n   */\n  items: any[]|null|undefined;\n\n  /**\n   * When `true`, multiple items may be selected at once (in this case,\n   * `selected` is an array of currently selected items).  When `false`,\n   * only one item may be selected at a time.\n   */\n  multi: boolean|null|undefined;\n\n  /**\n   * When `multi` is true, this is an array that contains any selected.\n   * When `multi` is false, this is the currently selected item, or `null`\n   * if no item is selected.\n   */\n  selected: object|object[]|null;\n\n  /**\n   * When `multi` is false, this is the currently selected item, or `null`\n   * if no item is selected.\n   */\n  selectedItem: object|null;\n\n  /**\n   * When `true`, calling `select` on an item that is already selected\n   * will deselect the item.\n   */\n  toggle: boolean|null|undefined;\n\n  /**\n   * Clears the selection state.\n   */\n  clearSelection(): void;\n\n  /**\n   * Returns whether the item is currently selected.\n   *\n   * @param item Item from `items` array to test\n   * @returns Whether the item is selected\n   */\n  isSelected(item: any): boolean;\n\n  /**\n   * Returns whether the item is currently selected.\n   *\n   * @param idx Index from `items` array to test\n   * @returns Whether the item is selected\n   */\n  isIndexSelected(idx: number): boolean;\n\n  /**\n   * Deselects the given item if it is already selected.\n   *\n   * @param item Item from `items` array to deselect\n   */\n  deselect(item: any): void;\n\n  /**\n   * Deselects the given index if it is already selected.\n   *\n   * @param idx Index from `items` array to deselect\n   */\n  deselectIndex(idx: number): void;\n\n  /**\n   * Selects the given item.  When `toggle` is true, this will automatically\n   * deselect the item if already selected.\n   *\n   * @param item Item from `items` array to select\n   */\n  select(item: any): void;\n\n  /**\n   * Selects the given index.  When `toggle` is true, this will automatically\n   * deselect the item if already selected.\n   *\n   * @param idx Index from `items` array to select\n   */\n  selectIndex(idx: number): void;\n}\n\nexport {ArraySelectorMixin};\n\n/**\n * Element implementing the `ArraySelector` mixin, which records\n * dynamic associations between item paths in a master `items` array and a\n * `selected` array such that path changes to the master array (at the host)\n * element or elsewhere via data-binding) are correctly propagated to items\n * in the selected array and vice-versa.\n *\n * The `items` property accepts an array of user data, and via the\n * `select(item)` and `deselect(item)` API, updates the `selected` property\n * which may be bound to other parts of the application, and any changes to\n * sub-fields of `selected` item(s) will be kept in sync with items in the\n * `items` array.  When `multi` is false, `selected` is a property\n * representing the last selected item.  When `multi` is true, `selected`\n * is an array of multiply selected items.\n *\n * Example:\n *\n * ```js\n * import {PolymerElement} from '@polymer/polymer';\n * import '@polymer/polymer/lib/elements/array-selector.js';\n *\n * class EmployeeList extends PolymerElement {\n *   static get _template() {\n *     return html`\n *         <div> Employee list: </div>\n *         <dom-repeat id=\"employeeList\" items=\"{{employees}}\">\n *           <template>\n *             <div>First name: <span>{{item.first}}</span></div>\n *               <div>Last name: <span>{{item.last}}</span></div>\n *               <button on-click=\"toggleSelection\">Select</button>\n *           </template>\n *         </dom-repeat>\n *\n *         <array-selector id=\"selector\"\n *                         items=\"{{employees}}\"\n *                         selected=\"{{selected}}\"\n *                         multi toggle></array-selector>\n *\n *         <div> Selected employees: </div>\n *         <dom-repeat items=\"{{selected}}\">\n *           <template>\n *             <div>First name: <span>{{item.first}}</span></div>\n *             <div>Last name: <span>{{item.last}}</span></div>\n *           </template>\n *         </dom-repeat>`;\n *   }\n *   static get is() { return 'employee-list'; }\n *   static get properties() {\n *     return {\n *       employees: {\n *         value() {\n *           return [\n *             {first: 'Bob', last: 'Smith'},\n *             {first: 'Sally', last: 'Johnson'},\n *             ...\n *           ];\n *         }\n *       }\n *     };\n *   }\n *   toggleSelection(e) {\n *     const item = this.$.employeeList.itemForElement(e.target);\n *     this.$.selector.select(item);\n *   }\n * }\n * ```\n */\ndeclare class ArraySelector extends\n  ArraySelectorMixin(\n  PolymerElement) {\n}\n\ndeclare global {\n\n  interface HTMLElementTagNameMap {\n    \"array-selector\": ArraySelector;\n  }\n}\n\nexport {ArraySelector};\n"
  },
  {
    "path": "lib/elements/array-selector.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport { PolymerElement } from '../../polymer-element.js';\n\nimport { dedupingMixin } from '../utils/mixin.js';\nimport { calculateSplices } from '../utils/array-splice.js';\nimport { ElementMixin } from '../mixins/element-mixin.js';\n\n/**\n * Element mixin for recording dynamic associations between item paths in a\n * master `items` array and a `selected` array such that path changes to the\n * master array (at the host) element or elsewhere via data-binding) are\n * correctly propagated to items in the selected array and vice-versa.\n *\n * The `items` property accepts an array of user data, and via the\n * `select(item)` and `deselect(item)` API, updates the `selected` property\n * which may be bound to other parts of the application, and any changes to\n * sub-fields of `selected` item(s) will be kept in sync with items in the\n * `items` array.  When `multi` is false, `selected` is a property\n * representing the last selected item.  When `multi` is true, `selected`\n * is an array of multiply selected items.\n *\n * @polymer\n * @mixinFunction\n * @appliesMixin ElementMixin\n * @summary Element mixin for recording dynamic associations between item paths in a\n * master `items` array and a `selected` array\n */\nlet ArraySelectorMixin = dedupingMixin(superClass => {\n\n  /**\n   * @constructor\n   * @implements {Polymer_ElementMixin}\n   * @private\n   */\n  let elementBase = ElementMixin(superClass);\n\n  /**\n   * @polymer\n   * @mixinClass\n   * @implements {Polymer_ArraySelectorMixin}\n   * @unrestricted\n   */\n  class ArraySelectorMixin extends elementBase {\n\n    static get properties() {\n      return {\n\n        /**\n         * An array containing items from which selection will be made.\n         */\n        items: {\n          type: Array,\n        },\n\n        /**\n         * When `true`, multiple items may be selected at once (in this case,\n         * `selected` is an array of currently selected items).  When `false`,\n         * only one item may be selected at a time.\n         */\n        multi: {\n          type: Boolean,\n          value: false,\n        },\n\n        /**\n         * When `multi` is true, this is an array that contains any selected.\n         * When `multi` is false, this is the currently selected item, or `null`\n         * if no item is selected.\n         * @type {?Object|?Array<!Object>}\n         */\n        selected: {type: Object, notify: true},\n\n        /**\n         * When `multi` is false, this is the currently selected item, or `null`\n         * if no item is selected.\n         * @type {?Object}\n         */\n        selectedItem: {type: Object, notify: true},\n\n        /**\n         * When `true`, calling `select` on an item that is already selected\n         * will deselect the item.\n         */\n        toggle: {type: Boolean, value: false}\n\n      };\n    }\n\n    static get observers() {\n      return ['__updateSelection(multi, items.*)'];\n    }\n\n    constructor() {\n      super();\n      this.__lastItems = null;\n      this.__lastMulti = null;\n      this.__selectedMap = null;\n    }\n\n    __updateSelection(multi, itemsInfo) {\n      let path = itemsInfo.path;\n      if (path == JSCompiler_renameProperty('items', this)) {\n        // Case 1 - items array changed, so diff against previous array and\n        // deselect any removed items and adjust selected indices\n        let newItems = itemsInfo.base || [];\n        let lastItems = this.__lastItems;\n        let lastMulti = this.__lastMulti;\n        if (multi !== lastMulti) {\n          this.clearSelection();\n        }\n        if (lastItems) {\n          let splices = calculateSplices(newItems, lastItems);\n          this.__applySplices(splices);\n        }\n        this.__lastItems = newItems;\n        this.__lastMulti = multi;\n      } else if (itemsInfo.path == `${JSCompiler_renameProperty('items', this)}.splices`) {\n        // Case 2 - got specific splice information describing the array mutation:\n        // deselect any removed items and adjust selected indices\n        this.__applySplices(itemsInfo.value.indexSplices);\n      } else {\n        // Case 3 - an array element was changed, so deselect the previous\n        // item for that index if it was previously selected\n        let part = path.slice(`${JSCompiler_renameProperty('items', this)}.`.length);\n        let idx = parseInt(part, 10);\n        if ((part.indexOf('.') < 0) && part == idx) {\n          this.__deselectChangedIdx(idx);\n        }\n      }\n    }\n\n    __applySplices(splices) {\n      let selected = this.__selectedMap;\n      // Adjust selected indices and mark removals\n      for (let i=0; i<splices.length; i++) {\n        let s = splices[i];\n        selected.forEach((idx, item) => {\n          if (idx < s.index) {\n            // no change\n          } else if (idx >= s.index + s.removed.length) {\n            // adjust index\n            selected.set(item, idx + s.addedCount - s.removed.length);\n          } else {\n            // remove index\n            selected.set(item, -1);\n          }\n        });\n        for (let j=0; j<s.addedCount; j++) {\n          let idx = s.index + j;\n          if (selected.has(this.items[idx])) {\n            selected.set(this.items[idx], idx);\n          }\n        }\n      }\n      // Update linked paths\n      this.__updateLinks();\n      // Remove selected items that were removed from the items array\n      let sidx = 0;\n      selected.forEach((idx, item) => {\n        if (idx < 0) {\n          if (this.multi) {\n            this.splice(JSCompiler_renameProperty('selected', this), sidx, 1);\n          } else {\n            this.selected = this.selectedItem = null;\n          }\n          selected.delete(item);\n        } else {\n          sidx++;\n        }\n      });\n    }\n\n    __updateLinks() {\n      this.__dataLinkedPaths = {};\n      if (this.multi) {\n        let sidx = 0;\n        this.__selectedMap.forEach(idx => {\n          if (idx >= 0) {\n            this.linkPaths(\n                `${JSCompiler_renameProperty('items', this)}.${idx}`,\n                `${JSCompiler_renameProperty('selected', this)}.${sidx++}`);\n          }\n        });\n      } else {\n        this.__selectedMap.forEach(idx => {\n          this.linkPaths(\n              JSCompiler_renameProperty('selected', this),\n              `${JSCompiler_renameProperty('items', this)}.${idx}`);\n          this.linkPaths(\n              JSCompiler_renameProperty('selectedItem', this),\n              `${JSCompiler_renameProperty('items', this)}.${idx}`);\n        });\n      }\n    }\n\n    /**\n     * Clears the selection state.\n     * @override\n     * @return {void}\n     */\n    clearSelection() {\n      // Unbind previous selection\n      this.__dataLinkedPaths = {};\n      // The selected map stores 3 pieces of information:\n      // key: items array object\n      // value: items array index\n      // order: selected array index\n      this.__selectedMap = new Map();\n      // Initialize selection\n      this.selected = this.multi ? [] : null;\n      this.selectedItem = null;\n    }\n\n    /**\n     * Returns whether the item is currently selected.\n     *\n     * @override\n     * @param {*} item Item from `items` array to test\n     * @return {boolean} Whether the item is selected\n     */\n    isSelected(item) {\n      return this.__selectedMap.has(item);\n    }\n\n    /**\n     * Returns whether the item is currently selected.\n     *\n     * @override\n     * @param {number} idx Index from `items` array to test\n     * @return {boolean} Whether the item is selected\n     */\n    isIndexSelected(idx) {\n      return this.isSelected(this.items[idx]);\n    }\n\n    __deselectChangedIdx(idx) {\n      let sidx = this.__selectedIndexForItemIndex(idx);\n      if (sidx >= 0) {\n        let i = 0;\n        this.__selectedMap.forEach((idx, item) => {\n          if (sidx == i++) {\n            this.deselect(item);\n          }\n        });\n      }\n    }\n\n    __selectedIndexForItemIndex(idx) {\n      let selected = this.__dataLinkedPaths[`${JSCompiler_renameProperty('items', this)}.${idx}`];\n      if (selected) {\n        return parseInt(selected.slice(`${JSCompiler_renameProperty('selected', this)}.`.length), 10);\n      }\n    }\n\n    /**\n     * Deselects the given item if it is already selected.\n     *\n     * @override\n     * @param {*} item Item from `items` array to deselect\n     * @return {void}\n     */\n    deselect(item) {\n      let idx = this.__selectedMap.get(item);\n      if (idx >= 0) {\n        this.__selectedMap.delete(item);\n        let sidx;\n        if (this.multi) {\n          sidx = this.__selectedIndexForItemIndex(idx);\n        }\n        this.__updateLinks();\n        if (this.multi) {\n          this.splice(JSCompiler_renameProperty('selected', this), sidx, 1);\n        } else {\n          this.selected = this.selectedItem = null;\n        }\n      }\n    }\n\n    /**\n     * Deselects the given index if it is already selected.\n     *\n     * @override\n     * @param {number} idx Index from `items` array to deselect\n     * @return {void}\n     */\n    deselectIndex(idx) {\n      this.deselect(this.items[idx]);\n    }\n\n    /**\n     * Selects the given item.  When `toggle` is true, this will automatically\n     * deselect the item if already selected.\n     *\n     * @override\n     * @param {*} item Item from `items` array to select\n     * @return {void}\n     */\n    select(item) {\n      this.selectIndex(this.items.indexOf(item));\n    }\n\n    /**\n     * Selects the given index.  When `toggle` is true, this will automatically\n     * deselect the item if already selected.\n     *\n     * @override\n     * @param {number} idx Index from `items` array to select\n     * @return {void}\n     */\n    selectIndex(idx) {\n      let item = this.items[idx];\n      if (!this.isSelected(item)) {\n        if (!this.multi) {\n          this.__selectedMap.clear();\n        }\n        this.__selectedMap.set(item, idx);\n        this.__updateLinks();\n        if (this.multi) {\n          this.push(JSCompiler_renameProperty('selected', this), item);\n        } else {\n          this.selected = this.selectedItem = item;\n        }\n      } else if (this.toggle) {\n        this.deselectIndex(idx);\n      }\n    }\n\n  }\n\n  return ArraySelectorMixin;\n\n});\n\n// export mixin\nexport { ArraySelectorMixin };\n\n/**\n * @constructor\n * @extends {PolymerElement}\n * @implements {Polymer_ArraySelectorMixin}\n * @private\n */\nlet baseArraySelector = ArraySelectorMixin(PolymerElement);\n\n/**\n * Element implementing the `ArraySelector` mixin, which records\n * dynamic associations between item paths in a master `items` array and a\n * `selected` array such that path changes to the master array (at the host)\n * element or elsewhere via data-binding) are correctly propagated to items\n * in the selected array and vice-versa.\n *\n * The `items` property accepts an array of user data, and via the\n * `select(item)` and `deselect(item)` API, updates the `selected` property\n * which may be bound to other parts of the application, and any changes to\n * sub-fields of `selected` item(s) will be kept in sync with items in the\n * `items` array.  When `multi` is false, `selected` is a property\n * representing the last selected item.  When `multi` is true, `selected`\n * is an array of multiply selected items.\n *\n * Example:\n *\n * ```js\n * import {PolymerElement} from '@polymer/polymer';\n * import '@polymer/polymer/lib/elements/array-selector.js';\n *\n * class EmployeeList extends PolymerElement {\n *   static get _template() {\n *     return html`\n *         <div> Employee list: </div>\n *         <dom-repeat id=\"employeeList\" items=\"{{employees}}\">\n *           <template>\n *             <div>First name: <span>{{item.first}}</span></div>\n *               <div>Last name: <span>{{item.last}}</span></div>\n *               <button on-click=\"toggleSelection\">Select</button>\n *           </template>\n *         </dom-repeat>\n *\n *         <array-selector id=\"selector\"\n *                         items=\"{{employees}}\"\n *                         selected=\"{{selected}}\"\n *                         multi toggle></array-selector>\n *\n *         <div> Selected employees: </div>\n *         <dom-repeat items=\"{{selected}}\">\n *           <template>\n *             <div>First name: <span>{{item.first}}</span></div>\n *             <div>Last name: <span>{{item.last}}</span></div>\n *           </template>\n *         </dom-repeat>`;\n *   }\n *   static get is() { return 'employee-list'; }\n *   static get properties() {\n *     return {\n *       employees: {\n *         value() {\n *           return [\n *             {first: 'Bob', last: 'Smith'},\n *             {first: 'Sally', last: 'Johnson'},\n *             ...\n *           ];\n *         }\n *       }\n *     };\n *   }\n *   toggleSelection(e) {\n *     const item = this.$.employeeList.itemForElement(e.target);\n *     this.$.selector.select(item);\n *   }\n * }\n * ```\n *\n * @polymer\n * @customElement\n * @extends {baseArraySelector}\n * @appliesMixin ArraySelectorMixin\n * @summary Custom element that links paths between an input `items` array and\n *   an output `selected` item or array based on calls to its selection API.\n */\nclass ArraySelector extends baseArraySelector {\n  // Not needed to find template; can be removed once the analyzer\n  // can find the tag name from customElements.define call\n  static get is() { return 'array-selector'; }\n  static get template() { return null; }\n}\ncustomElements.define(ArraySelector.is, ArraySelector);\nexport { ArraySelector };\n"
  },
  {
    "path": "lib/elements/custom-style.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n\nimport {cssFromModules} from '../utils/style-gather.js';\n\nexport {CustomStyle};\n\n/**\n * Custom element for defining styles in the main document that can take\n * advantage of [shady DOM](https://github.com/webcomponents/shadycss) shims\n * for style encapsulation, custom properties, and custom mixins.\n *\n * - Document styles defined in a `<custom-style>` are shimmed to ensure they\n *   do not leak into local DOM when running on browsers without native\n *   Shadow DOM.\n * - Custom properties can be defined in a `<custom-style>`. Use the `html` selector\n *   to define custom properties that apply to all custom elements.\n * - Custom mixins can be defined in a `<custom-style>`, if you import the optional\n *   [apply shim](https://github.com/webcomponents/shadycss#about-applyshim)\n *   (`shadycss/apply-shim.html`).\n *\n * To use:\n *\n * - Import `custom-style.html`.\n * - Place a `<custom-style>` element in the main document, wrapping an inline `<style>` tag that\n *   contains the CSS rules you want to shim.\n *\n * For example:\n *\n * ```html\n * <!-- import apply shim--only required if using mixins -->\n * <link rel=\"import\" href=\"bower_components/shadycss/apply-shim.html\">\n * <!-- import custom-style element -->\n * <link rel=\"import\" href=\"bower_components/polymer/lib/elements/custom-style.html\">\n *\n * <custom-style>\n *   <style>\n *     html {\n *       --custom-color: blue;\n *       --custom-mixin: {\n *         font-weight: bold;\n *         color: red;\n *       };\n *     }\n *   </style>\n * </custom-style>\n * ```\n */\ndeclare class CustomStyle extends HTMLElement {\n\n  /**\n   * Returns the light-DOM `<style>` child this element wraps.  Upon first\n   * call any style modules referenced via the `include` attribute will be\n   * concatenated to this element's `<style>`.\n   *\n   * @returns This element's light-DOM `<style>`\n   */\n  getStyle(): HTMLStyleElement|null;\n}\n\ndeclare global {\n\n  interface HTMLElementTagNameMap {\n    \"custom-style\": CustomStyle;\n  }\n}\n"
  },
  {
    "path": "lib/elements/custom-style.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport '@webcomponents/shadycss/entrypoints/custom-style-interface.js';\n\nimport { cssFromModules } from '../utils/style-gather.js';\n\nconst attr = 'include';\n\nconst CustomStyleInterface = window.ShadyCSS.CustomStyleInterface;\n\n/**\n * Custom element for defining styles in the main document that can take\n * advantage of [shady DOM](https://github.com/webcomponents/shadycss) shims\n * for style encapsulation, custom properties, and custom mixins.\n *\n * - Document styles defined in a `<custom-style>` are shimmed to ensure they\n *   do not leak into local DOM when running on browsers without native\n *   Shadow DOM.\n * - Custom properties can be defined in a `<custom-style>`. Use the `html` selector\n *   to define custom properties that apply to all custom elements.\n * - Custom mixins can be defined in a `<custom-style>`, if you import the optional\n *   [apply shim](https://github.com/webcomponents/shadycss#about-applyshim)\n *   (`shadycss/apply-shim.html`).\n *\n * To use:\n *\n * - Import `custom-style.html`.\n * - Place a `<custom-style>` element in the main document, wrapping an inline `<style>` tag that\n *   contains the CSS rules you want to shim.\n *\n * For example:\n *\n * ```html\n * <!-- import apply shim--only required if using mixins -->\n * <link rel=\"import\" href=\"bower_components/shadycss/apply-shim.html\">\n * <!-- import custom-style element -->\n * <link rel=\"import\" href=\"bower_components/polymer/lib/elements/custom-style.html\">\n *\n * <custom-style>\n *   <style>\n *     html {\n *       --custom-color: blue;\n *       --custom-mixin: {\n *         font-weight: bold;\n *         color: red;\n *       };\n *     }\n *   </style>\n * </custom-style>\n * ```\n *\n * @customElement\n * @extends HTMLElement\n * @summary Custom element for defining styles in the main document that can\n *   take advantage of Polymer's style scoping and custom properties shims.\n */\nexport class CustomStyle extends HTMLElement {\n  constructor() {\n    super();\n    this._style = null;\n    CustomStyleInterface.addCustomStyle(this);\n  }\n  /**\n   * Returns the light-DOM `<style>` child this element wraps.  Upon first\n   * call any style modules referenced via the `include` attribute will be\n   * concatenated to this element's `<style>`.\n   *\n   * @export\n   * @return {HTMLStyleElement} This element's light-DOM `<style>`\n   */\n  getStyle() {\n    if (this._style) {\n      return this._style;\n    }\n    const style = /** @type {HTMLStyleElement} */(this.querySelector('style'));\n    if (!style) {\n      return null;\n    }\n    this._style = style;\n    const include = style.getAttribute(attr);\n    if (include) {\n      style.removeAttribute(attr);\n      /** @suppress {deprecated} */\n      style.textContent = cssFromModules(include) + style.textContent;\n    }\n    /*\n    HTML Imports styling the main document are deprecated in Chrome\n    https://crbug.com/523952\n\n    If this element is not in the main document, then it must be in an HTML Import document.\n    In that case, move the custom style to the main document.\n\n    The ordering of `<custom-style>` should stay the same as when loaded by HTML Imports, but there may be odd\n    cases of ordering w.r.t the main document styles.\n    */\n    if (this.ownerDocument !== window.document) {\n      window.document.head.appendChild(this);\n    }\n    return this._style;\n  }\n}\n\nwindow.customElements.define('custom-style', CustomStyle);\n"
  },
  {
    "path": "lib/elements/dom-bind.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n\nimport {PropertyEffects} from '../mixins/property-effects.js';\n\nimport {OptionalMutableData} from '../mixins/mutable-data.js';\n\nimport {GestureEventListeners} from '../mixins/gesture-event-listeners.js';\n\nimport {hideElementsGlobally} from '../utils/hide-template-controls.js';\n\nexport {DomBind};\n\n/**\n * Custom element to allow using Polymer's template features (data binding,\n * declarative event listeners, etc.) in the main document without defining\n * a new custom element.\n *\n * `<template>` tags utilizing bindings may be wrapped with the `<dom-bind>`\n * element, which will immediately stamp the wrapped template into the main\n * document and bind elements to the `dom-bind` element itself as the\n * binding scope.\n */\ndeclare class DomBind extends\n  PropertyEffects(\n  OptionalMutableData(\n  GestureEventListeners(\n  HTMLElement))) {\n\n  /**\n   * @param name Name of attribute that changed\n   * @param old Old attribute value\n   * @param value New attribute value\n   * @param namespace Attribute namespace.\n   */\n  attributeChangedCallback(name: string, old: string|null, value: string|null, namespace: string|null): void;\n  connectedCallback(): void;\n  disconnectedCallback(): void;\n\n  /**\n   * Forces the element to render its content. This is typically only\n   * necessary to call if HTMLImports with the async attribute are used.\n   */\n  render(): void;\n}\n\ndeclare global {\n\n  interface HTMLElementTagNameMap {\n    \"dom-bind\": DomBind;\n  }\n}\n"
  },
  {
    "path": "lib/elements/dom-bind.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport '../utils/boot.js';\n\nimport { PropertyEffects } from '../mixins/property-effects.js';\nimport { OptionalMutableData } from '../mixins/mutable-data.js';\nimport { GestureEventListeners } from '../mixins/gesture-event-listeners.js';\nimport { strictTemplatePolicy } from '../utils/settings.js';\nimport { wrap } from '../utils/wrap.js';\nimport { hideElementsGlobally } from '../utils/hide-template-controls.js';\n\n/**\n * @constructor\n * @extends {HTMLElement}\n * @implements {Polymer_PropertyEffects}\n * @implements {Polymer_OptionalMutableData}\n * @implements {Polymer_GestureEventListeners}\n * @private\n */\nconst domBindBase =\n  GestureEventListeners(\n    OptionalMutableData(\n      PropertyEffects(HTMLElement)));\n\n/**\n * Custom element to allow using Polymer's template features (data binding,\n * declarative event listeners, etc.) in the main document without defining\n * a new custom element.\n *\n * `<template>` tags utilizing bindings may be wrapped with the `<dom-bind>`\n * element, which will immediately stamp the wrapped template into the main\n * document and bind elements to the `dom-bind` element itself as the\n * binding scope.\n *\n * @polymer\n * @customElement\n * @appliesMixin PropertyEffects\n * @appliesMixin OptionalMutableData\n * @appliesMixin GestureEventListeners\n * @extends {domBindBase}\n * @summary Custom element to allow using Polymer's template features (data\n *   binding, declarative event listeners, etc.) in the main document.\n */\nexport class DomBind extends domBindBase {\n\n  static get observedAttributes() { return ['mutable-data']; }\n\n  constructor() {\n    super();\n    if (strictTemplatePolicy) {\n      throw new Error(`strictTemplatePolicy: dom-bind not allowed`);\n    }\n    this.root = null;\n    this.$ = null;\n    this.__children = null;\n  }\n\n  /* eslint-disable no-unused-vars */\n  /**\n   * @override\n   * @param {string} name Name of attribute that changed\n   * @param {?string} old Old attribute value\n   * @param {?string} value New attribute value\n   * @param {?string} namespace Attribute namespace.\n   * @return {void}\n   */\n  attributeChangedCallback(name, old, value, namespace) {\n    // assumes only one observed attribute\n    this.mutableData = true;\n  }\n\n  /**\n   * @override\n   * @return {void}\n   */\n  connectedCallback() {\n    if (!hideElementsGlobally()) {\n      this.style.display = 'none';\n    }\n    this.render();\n  }\n\n  /**\n   * @override\n   * @return {void}\n   */\n  disconnectedCallback() {\n    this.__removeChildren();\n  }\n\n  __insertChildren() {\n    wrap(wrap(this).parentNode).insertBefore(this.root, this);\n  }\n\n  __removeChildren() {\n    if (this.__children) {\n      for (let i=0; i<this.__children.length; i++) {\n        this.root.appendChild(this.__children[i]);\n      }\n    }\n  }\n\n  /**\n   * Forces the element to render its content. This is typically only\n   * necessary to call if HTMLImports with the async attribute are used.\n   * @return {void}\n   */\n  render() {\n    let template;\n    if (!this.__children) {\n      template = /** @type {?HTMLTemplateElement} */(template || this.querySelector('template'));\n      if (!template) {\n        // Wait until childList changes and template should be there by then\n        let observer = new MutationObserver(() => {\n          template = /** @type {HTMLTemplateElement} */(this.querySelector('template'));\n          if (template) {\n            observer.disconnect();\n            this.render();\n          } else {\n            throw new Error('dom-bind requires a <template> child');\n          }\n        });\n        observer.observe(this, {childList: true});\n        return;\n      }\n      this.root = this._stampTemplate(\n        /** @type {!HTMLTemplateElement} */(template));\n      this.$ = this.root.$;\n      this.__children = [];\n      for (let n=this.root.firstChild; n; n=n.nextSibling) {\n        this.__children[this.__children.length] = n;\n      }\n      this._enableProperties();\n    }\n    this.__insertChildren();\n    this.dispatchEvent(new CustomEvent('dom-change', {\n      bubbles: true,\n      composed: true\n    }));\n  }\n\n}\n\ncustomElements.define('dom-bind', DomBind);\n"
  },
  {
    "path": "lib/elements/dom-if.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n\nimport {PolymerElement} from '../../polymer-element.js';\n\nimport {Debouncer} from '../utils/debounce.js';\n\nimport {enqueueDebouncer, flush} from '../utils/flush.js';\n\nimport {microTask} from '../utils/async.js';\n\nimport {root} from '../utils/path.js';\n\nimport {hideElementsGlobally} from '../utils/hide-template-controls.js';\n\nimport {showHideChildren, templatize} from '../utils/templatize.js';\n\ndeclare class DomIfBase extends PolymerElement {\n  _templateInfo: TemplateInfo|undefined;\n\n  /**\n   * A boolean indicating whether this template should stamp.\n   */\n  if: boolean|null|undefined;\n\n  /**\n   * When true, elements will be removed from DOM and discarded when `if`\n   * becomes false and re-created and added back to the DOM when `if`\n   * becomes true.  By default, stamped elements will be hidden but left\n   * in the DOM when `if` becomes false, which is generally results\n   * in better performance.\n   */\n  restamp: boolean|null|undefined;\n\n  /**\n   * When the global `suppressTemplateNotifications` setting is used, setting\n   * `notifyDomChange: true` will enable firing `dom-change` events on this\n   * element.\n   */\n  notifyDomChange: boolean|null|undefined;\n  connectedCallback(): void;\n  disconnectedCallback(): void;\n\n  /**\n   * Forces the element to render its content. Normally rendering is\n   * asynchronous to a provoking change. This is done for efficiency so\n   * that multiple changes trigger only a single render. The render method\n   * should be called if, for example, template rendering is required to\n   * validate application state.\n   */\n  render(): void;\n\n  /**\n   * Abstract API to be implemented by subclass: Returns true if a template\n   * instance has been created and inserted.\n   *\n   * @returns True when an instance has been created.\n   */\n  __hasInstance(): boolean;\n\n  /**\n   * Abstract API to be implemented by subclass: Returns the child nodes stamped\n   * from a template instance.\n   *\n   * @returns Array of child nodes stamped from the template\n   * instance.\n   */\n  __getInstanceNodes(): Array<Node|null>|null;\n\n  /**\n   * Abstract API to be implemented by subclass: Creates an instance of the\n   * template and inserts it into the given parent node.\n   *\n   * @param parentNode The parent node to insert the instance into\n   */\n  __createAndInsertInstance(parentNode: Node|null): void;\n\n  /**\n   * Abstract API to be implemented by subclass: Removes nodes created by an\n   * instance of a template and any associated cleanup.\n   */\n  __teardownInstance(): void;\n\n  /**\n   * Abstract API to be implemented by subclass: Shows or hides any template\n   * instance childNodes based on the `if` state of the element and its\n   * `__hideTemplateChildren__` property.\n   */\n  _showHideChildren(): void;\n}\n\ndeclare global {\n\n  interface HTMLElementTagNameMap {\n    \"dom-if\": DomIfBase;\n  }\n}\n\n/**\n * The version of DomIf used when `fastDomIf` setting is in use, which is\n * optimized for first-render (but adds a tax to all subsequent property updates\n * on the host, whether they were used in a given `dom-if` or not).\n *\n * This implementation avoids use of `Templatizer`, which introduces a new scope\n * (a non-element PropertyEffects instance), which is not strictly necessary\n * since `dom-if` never introduces new properties to its scope (unlike\n * `dom-repeat`). Taking advantage of this fact, the `dom-if` reaches up to its\n * `__dataHost` and stamps the template directly from the host using the host's\n * runtime `_stampTemplate` API, which binds the property effects of the\n * template directly to the host. This both avoids the intermediary\n * `Templatizer` instance, but also avoids the need to bind host properties to\n * the `<template>` element and forward those into the template instance.\n *\n * In this version of `dom-if`, the `this.__instance` method is the\n * `DocumentFragment` returned from `_stampTemplate`, which also serves as the\n * handle for later removing it using the `_removeBoundDom` method.\n */\ndeclare class DomIfFast extends DomIfBase {\n  constructor();\n\n  /**\n   * Implementation of abstract API needed by DomIfBase.\n   *\n   * Shows or hides the template instance top level child nodes. For\n   * text nodes, `textContent` is removed while \"hidden\" and replaced when\n   * \"shown.\"\n   */\n  _showHideChildren(): void;\n}\n\n/**\n * The \"legacy\" implementation of `dom-if`, implemented using `Templatizer`.\n *\n * In this version, `this.__instance` is the `TemplateInstance` returned\n * from the templatized constructor.\n */\ndeclare class DomIfLegacy extends DomIfBase {\n  constructor();\n\n  /**\n   * Implementation of abstract API needed by DomIfBase.\n   *\n   * Shows or hides the template instance top level child elements. For\n   * text nodes, `textContent` is removed while \"hidden\" and replaced when\n   * \"shown.\"\n   */\n  _showHideChildren(): void;\n}\n\nexport {DomIf};\n\n/**\n * The `<dom-if>` element will stamp a light-dom `<template>` child when\n * the `if` property becomes truthy, and the template can use Polymer\n * data-binding and declarative event features when used in the context of\n * a Polymer element's template.\n *\n * When `if` becomes falsy, the stamped content is hidden but not\n * removed from dom. When `if` subsequently becomes truthy again, the content\n * is simply re-shown. This approach is used due to its favorable performance\n * characteristics: the expense of creating template content is paid only\n * once and lazily.\n *\n * Set the `restamp` property to true to force the stamped content to be\n * created / destroyed when the `if` condition changes.\n */\ndeclare class DomIf extends DomIfBase {\n}\n\nimport {TemplateInfo} from '../../interfaces';\n"
  },
  {
    "path": "lib/elements/dom-if.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport { PolymerElement } from '../../polymer-element.js';\n\nimport { Debouncer } from '../utils/debounce.js';\nimport { enqueueDebouncer, flush } from '../utils/flush.js';\nimport { microTask } from '../utils/async.js';\nimport { root } from '../utils/path.js';\nimport { wrap } from '../utils/wrap.js';\nimport { hideElementsGlobally } from '../utils/hide-template-controls.js';\nimport { fastDomIf, strictTemplatePolicy, suppressTemplateNotifications } from '../utils/settings.js';\nimport { showHideChildren, templatize } from '../utils/templatize.js';\n\n/**\n * @customElement\n * @polymer\n * @extends PolymerElement\n * @summary Base class for dom-if element; subclassed into concrete\n *   implementation.\n */\nclass DomIfBase extends PolymerElement {\n\n  // Not needed to find template; can be removed once the analyzer\n  // can find the tag name from customElements.define call\n  static get is() { return 'dom-if'; }\n\n  static get template() { return null; }\n\n  static get properties() {\n\n    return {\n\n      /**\n       * Fired whenever DOM is added or removed/hidden by this template (by\n       * default, rendering occurs lazily).  To force immediate rendering, call\n       * `render`.\n       *\n       * @event dom-change\n       */\n\n      /**\n       * A boolean indicating whether this template should stamp.\n       */\n      if: {\n        type: Boolean,\n        observer: '__debounceRender'\n      },\n\n      /**\n       * When true, elements will be removed from DOM and discarded when `if`\n       * becomes false and re-created and added back to the DOM when `if`\n       * becomes true.  By default, stamped elements will be hidden but left\n       * in the DOM when `if` becomes false, which is generally results\n       * in better performance.\n       */\n      restamp: {\n        type: Boolean,\n        observer: '__debounceRender'\n      },\n\n      /**\n       * When the global `suppressTemplateNotifications` setting is used, setting\n       * `notifyDomChange: true` will enable firing `dom-change` events on this\n       * element.\n       */\n      notifyDomChange: {\n        type: Boolean\n      }\n    };\n\n  }\n\n  constructor() {\n    super();\n    this.__renderDebouncer = null;\n    this._lastIf = false;\n    this.__hideTemplateChildren__ = false;\n    /** @type {!HTMLTemplateElement|undefined} */\n    this.__template;\n    /** @type {!TemplateInfo|undefined} */\n    this._templateInfo;\n  }\n\n  __debounceRender() {\n    // Render is async for 2 reasons:\n    // 1. To eliminate dom creation trashing if user code thrashes `if` in the\n    //    same turn. This was more common in 1.x where a compound computed\n    //    property could result in the result changing multiple times, but is\n    //    mitigated to a large extent by batched property processing in 2.x.\n    // 2. To avoid double object propagation when a bag including values bound\n    //    to the `if` property as well as one or more hostProps could enqueue\n    //    the <dom-if> to flush before the <template>'s host property\n    //    forwarding. In that scenario creating an instance would result in\n    //    the host props being set once, and then the enqueued changes on the\n    //    template would set properties a second time, potentially causing an\n    //    object to be set to an instance more than once.  Creating the\n    //    instance async from flushing data ensures this doesn't happen. If\n    //    we wanted a sync option in the future, simply having <dom-if> flush\n    //    (or clear) its template's pending host properties before creating\n    //    the instance would also avoid the problem.\n    this.__renderDebouncer = Debouncer.debounce(\n          this.__renderDebouncer\n        , microTask\n        , () => this.__render());\n    enqueueDebouncer(this.__renderDebouncer);\n  }\n\n  /**\n   * @override\n   * @return {void}\n   */\n  disconnectedCallback() {\n    super.disconnectedCallback();\n    const parent = wrap(this).parentNode;\n    if (!parent || (parent.nodeType == Node.DOCUMENT_FRAGMENT_NODE &&\n        !wrap(parent).host)) {\n      this.__teardownInstance();\n    }\n  }\n\n  /**\n   * @override\n   * @return {void}\n   */\n  connectedCallback() {\n    super.connectedCallback();\n    if (!hideElementsGlobally()) {\n      this.style.display = 'none';\n    }\n    if (this.if) {\n      this.__debounceRender();\n    }\n  }\n\n  /**\n   * Ensures a template has been assigned to `this.__template`.  If it has not\n   * yet been, it querySelectors for it in its children and if it does not yet\n   * exist (e.g. in parser-generated case), opens a mutation observer and\n   * waits for it to appear (returns false if it has not yet been found,\n   * otherwise true).  In the `removeNestedTemplates` case, the \"template\" will\n   * be the `dom-if` element itself.\n   *\n   * @return {boolean} True when a template has been found, false otherwise\n   */\n  __ensureTemplate() {\n    if (!this.__template) {\n      // When `removeNestedTemplates` is true, the \"template\" is the element\n      // itself, which has been given a `_templateInfo` property\n      const thisAsTemplate = /** @type {!HTMLTemplateElement} */ (\n          /** @type {!HTMLElement} */ (this));\n      let template = thisAsTemplate._templateInfo ?\n          thisAsTemplate :\n          /** @type {!HTMLTemplateElement} */\n          (wrap(thisAsTemplate).querySelector('template'));\n      if (!template) {\n        // Wait until childList changes and template should be there by then\n        let observer = new MutationObserver(() => {\n          if (wrap(this).querySelector('template')) {\n            observer.disconnect();\n            this.__render();\n          } else {\n            throw new Error('dom-if requires a <template> child');\n          }\n        });\n        observer.observe(this, {childList: true});\n        return false;\n      }\n      this.__template = template;\n    }\n    return true;\n  }\n\n  /**\n   * Ensures a an instance of the template has been created and inserted. This\n   * method may return false if the template has not yet been found or if\n   * there is no `parentNode` to insert the template into (in either case,\n   * connection or the template-finding mutation observer firing will queue\n   * another render, causing this method to be called again at a more\n   * appropriate time).\n   *\n   * Subclasses should implement the following methods called here:\n   * - `__hasInstance`\n   * - `__createAndInsertInstance`\n   * - `__getInstanceNodes`\n   *\n   * @return {boolean} True if the instance was created, false otherwise.\n   */\n  __ensureInstance() {\n    let parentNode = wrap(this).parentNode;\n    if (!this.__hasInstance()) {\n      // Guard against element being detached while render was queued\n      if (!parentNode) {\n        return false;\n      }\n      // Find the template (when false, there was no template yet)\n      if (!this.__ensureTemplate()) {\n        return false;\n      }\n      this.__createAndInsertInstance(parentNode);\n    } else {\n      // Move instance children if necessary\n      let children = this.__getInstanceNodes();\n      if (children && children.length) {\n        // Detect case where dom-if was re-attached in new position\n        let lastChild = wrap(this).previousSibling;\n        if (lastChild !== children[children.length-1]) {\n          for (let i=0, n; (i<children.length) && (n=children[i]); i++) {\n            wrap(parentNode).insertBefore(n, this);\n          }\n        }\n      }\n    }\n    return true;\n  }\n\n  /**\n   * Forces the element to render its content. Normally rendering is\n   * asynchronous to a provoking change. This is done for efficiency so\n   * that multiple changes trigger only a single render. The render method\n   * should be called if, for example, template rendering is required to\n   * validate application state.\n   *\n   * @return {void}\n   */\n  render() {\n    flush();\n  }\n\n  /**\n   * Performs the key rendering steps:\n   * 1. Ensure a template instance has been stamped (when true)\n   * 2. Remove the template instance (when false and restamp:true)\n   * 3. Sync the hidden state of the instance nodes with the if/restamp state\n   * 4. Fires the `dom-change` event when necessary\n   *\n   * @return {void}\n   */\n  __render() {\n    if (this.if) {\n      if (!this.__ensureInstance()) {\n        // No template found yet\n        return;\n      }\n    } else if (this.restamp) {\n      this.__teardownInstance();\n    }\n    this._showHideChildren();\n    if ((!suppressTemplateNotifications || this.notifyDomChange)\n        && this.if != this._lastIf) {\n      this.dispatchEvent(new CustomEvent('dom-change', {\n        bubbles: true,\n        composed: true\n      }));\n      this._lastIf = this.if;\n    }\n  }\n\n  // Ideally these would be annotated as abstract methods in an abstract class,\n  // but closure compiler is finnicky\n  /* eslint-disable valid-jsdoc */\n  /**\n   * Abstract API to be implemented by subclass: Returns true if a template\n   * instance has been created and inserted.\n   *\n   * @protected\n   * @return {boolean} True when an instance has been created.\n   */\n  __hasInstance() { }\n\n  /**\n   * Abstract API to be implemented by subclass: Returns the child nodes stamped\n   * from a template instance.\n   *\n   * @protected\n   * @return {Array<Node>} Array of child nodes stamped from the template\n   * instance.\n   */\n  __getInstanceNodes() { }\n\n  /**\n   * Abstract API to be implemented by subclass: Creates an instance of the\n   * template and inserts it into the given parent node.\n   *\n   * @protected\n   * @param {Node} parentNode The parent node to insert the instance into\n   * @return {void}\n   */\n  __createAndInsertInstance(parentNode) { } // eslint-disable-line no-unused-vars\n\n  /**\n   * Abstract API to be implemented by subclass: Removes nodes created by an\n   * instance of a template and any associated cleanup.\n   *\n   * @protected\n   * @return {void}\n   */\n  __teardownInstance() { }\n\n  /**\n   * Abstract API to be implemented by subclass: Shows or hides any template\n   * instance childNodes based on the `if` state of the element and its\n   * `__hideTemplateChildren__` property.\n   *\n   * @protected\n   * @return {void}\n   */\n  _showHideChildren() { }\n  /* eslint-enable valid-jsdoc */\n}\n\n/**\n * The version of DomIf used when `fastDomIf` setting is in use, which is\n * optimized for first-render (but adds a tax to all subsequent property updates\n * on the host, whether they were used in a given `dom-if` or not).\n *\n * This implementation avoids use of `Templatizer`, which introduces a new scope\n * (a non-element PropertyEffects instance), which is not strictly necessary\n * since `dom-if` never introduces new properties to its scope (unlike\n * `dom-repeat`). Taking advantage of this fact, the `dom-if` reaches up to its\n * `__dataHost` and stamps the template directly from the host using the host's\n * runtime `_stampTemplate` API, which binds the property effects of the\n * template directly to the host. This both avoids the intermediary\n * `Templatizer` instance, but also avoids the need to bind host properties to\n * the `<template>` element and forward those into the template instance.\n *\n * In this version of `dom-if`, the `this.__instance` method is the\n * `DocumentFragment` returned from `_stampTemplate`, which also serves as the\n * handle for later removing it using the `_removeBoundDom` method.\n */\nclass DomIfFast extends DomIfBase {\n\n  constructor() {\n    super();\n    this.__instance = null;\n    this.__syncInfo = null;\n  }\n\n  /**\n   * Implementation of abstract API needed by DomIfBase.\n   *\n   * @override\n   * @return {boolean} True when an instance has been created.\n   */\n  __hasInstance() {\n    return Boolean(this.__instance);\n  }\n\n  /**\n   * Implementation of abstract API needed by DomIfBase.\n   *\n   * @override\n   * @return {Array<Node>} Array of child nodes stamped from the template\n   * instance.\n   */\n  __getInstanceNodes() {\n    return this.__instance.templateInfo.childNodes;\n  }\n\n  /**\n   * Implementation of abstract API needed by DomIfBase.\n   *\n   * Stamps the template by calling `_stampTemplate` on the `__dataHost` of this\n   * element and then inserts the resulting nodes into the given `parentNode`.\n   *\n   * @override\n   * @param {Node} parentNode The parent node to insert the instance into\n   * @return {void}\n   */\n  __createAndInsertInstance(parentNode) {\n    const host = this.__dataHost || this;\n    if (strictTemplatePolicy) {\n      if (!this.__dataHost) {\n        throw new Error('strictTemplatePolicy: template owner not trusted');\n      }\n    }\n    // Pre-bind and link the template into the effects system\n    const templateInfo = host._bindTemplate(\n        /** @type {!HTMLTemplateElement} */ (this.__template), true);\n    // Install runEffects hook that prevents running property effects\n    // (and any nested template effects) when the `if` is false\n    templateInfo.runEffects = (runEffects, changedProps, hasPaths) => {\n      let syncInfo = this.__syncInfo;\n      if (this.if) {\n        // Mix any props that changed while the `if` was false into `changedProps`\n        if (syncInfo) {\n          // If there were properties received while the `if` was false, it is\n          // important to sync the hidden state with the element _first_, so that\n          // new bindings to e.g. `textContent` do not get stomped on by\n          // pre-hidden values if `_showHideChildren` were to be called later at\n          // the next render. Clearing `__invalidProps` here ensures\n          // `_showHideChildren`'s call to `__syncHostProperties` no-ops, so\n          // that we don't call `runEffects` more often than necessary.\n          this.__syncInfo = null;\n          this._showHideChildren();\n          changedProps = Object.assign(syncInfo.changedProps, changedProps);\n        }\n        runEffects(changedProps, hasPaths);\n      } else {\n        // Accumulate any values changed while `if` was false, along with the\n        // runEffects method to sync them, so that we can replay them once `if`\n        // becomes true\n        if (this.__instance) {\n          if (!syncInfo) {\n            syncInfo = this.__syncInfo = { runEffects, changedProps: {} };\n          }\n          if (hasPaths) {\n            // Store root object of any paths; this will ensure direct bindings\n            // like [[obj.foo]] bindings run after a `set('obj.foo', v)`, but\n            // note that path notifications like `set('obj.foo.bar', v)` will\n            // not propagate. Since batched path notifications are not\n            // supported, we cannot simply accumulate path notifications. This\n            // is equivalent to the non-fastDomIf case, which stores root(p) in\n            // __invalidProps.\n            for (const p in changedProps) {\n              const rootProp = root(p);\n              syncInfo.changedProps[rootProp] = this.__dataHost[rootProp];\n            }\n          } else {\n            Object.assign(syncInfo.changedProps, changedProps);\n          }\n        }\n      }\n    };\n    // Stamp the template, and set its DocumentFragment to the \"instance\"\n    this.__instance = host._stampTemplate(\n        /** @type {!HTMLTemplateElement} */ (this.__template), templateInfo);\n    wrap(parentNode).insertBefore(this.__instance, this);\n  }\n\n  /**\n   * Run effects for any properties that changed while the `if` was false.\n   *\n   * @return {void}\n   */\n  __syncHostProperties() {\n    const syncInfo = this.__syncInfo;\n    if (syncInfo) {\n      this.__syncInfo = null;\n      syncInfo.runEffects(syncInfo.changedProps, false);\n    }\n  }\n\n  /**\n   * Implementation of abstract API needed by DomIfBase.\n   *\n   * Remove the instance and any nodes it created.  Uses the `__dataHost`'s\n   * runtime `_removeBoundDom` method.\n   *\n   * @override\n   * @return {void}\n   */\n  __teardownInstance() {\n    const host = this.__dataHost || this;\n    if (this.__instance) {\n      host._removeBoundDom(this.__instance);\n      this.__instance = null;\n      this.__syncInfo = null;\n    }\n  }\n\n  /**\n   * Implementation of abstract API needed by DomIfBase.\n   *\n   * Shows or hides the template instance top level child nodes. For\n   * text nodes, `textContent` is removed while \"hidden\" and replaced when\n   * \"shown.\"\n   *\n   * @override\n   * @return {void}\n   * @protected\n   * @suppress {visibility}\n   */\n  _showHideChildren() {\n    const hidden = this.__hideTemplateChildren__ || !this.if;\n    if (this.__instance && Boolean(this.__instance.__hidden) !== hidden) {\n      this.__instance.__hidden = hidden;\n      showHideChildren(hidden, this.__instance.templateInfo.childNodes);\n    }\n    if (!hidden) {\n      this.__syncHostProperties();\n    }\n  }\n}\n\n/**\n * The \"legacy\" implementation of `dom-if`, implemented using `Templatizer`.\n *\n * In this version, `this.__instance` is the `TemplateInstance` returned\n * from the templatized constructor.\n */\nclass DomIfLegacy extends DomIfBase {\n\n  constructor() {\n    super();\n    this.__ctor = null;\n    this.__instance = null;\n    this.__invalidProps = null;\n  }\n\n  /**\n   * Implementation of abstract API needed by DomIfBase.\n   *\n   * @override\n   * @return {boolean} True when an instance has been created.\n   */\n  __hasInstance() {\n    return Boolean(this.__instance);\n  }\n\n  /**\n   * Implementation of abstract API needed by DomIfBase.\n   *\n   * @override\n   * @return {Array<Node>} Array of child nodes stamped from the template\n   * instance.\n   */\n  __getInstanceNodes() {\n    return this.__instance.children;\n  }\n\n  /**\n   * Implementation of abstract API needed by DomIfBase.\n   *\n   * Stamps the template by creating a new instance of the templatized\n   * constructor (which is created lazily if it does not yet exist), and then\n   * inserts its resulting `root` doc fragment into the given `parentNode`.\n   *\n   * @override\n   * @param {Node} parentNode The parent node to insert the instance into\n   * @return {void}\n   */\n  __createAndInsertInstance(parentNode) {\n    // Ensure we have an instance constructor\n    if (!this.__ctor) {\n      this.__ctor = templatize(\n          /** @type {!HTMLTemplateElement} */ (this.__template), this, {\n            // dom-if templatizer instances require `mutable: true`, as\n            // `__syncHostProperties` relies on that behavior to sync objects\n            mutableData: true,\n            /**\n             * @param {string} prop Property to forward\n             * @param {*} value Value of property\n             * @this {DomIfLegacy}\n             */\n            forwardHostProp: function(prop, value) {\n              if (this.__instance) {\n                if (this.if) {\n                  this.__instance.forwardHostProp(prop, value);\n                } else {\n                  // If we have an instance but are squelching host property\n                  // forwarding due to if being false, note the invalidated\n                  // properties so `__syncHostProperties` can sync them the next\n                  // time `if` becomes true\n                  this.__invalidProps =\n                      this.__invalidProps || Object.create(null);\n                  this.__invalidProps[root(prop)] = true;\n                }\n              }\n            }\n          });\n    }\n    // Create and insert the instance\n    this.__instance = new this.__ctor();\n    wrap(parentNode).insertBefore(this.__instance.root, this);\n  }\n\n  /**\n   * Implementation of abstract API needed by DomIfBase.\n   *\n   * Removes the instance and any nodes it created.\n   *\n   * @override\n   * @return {void}\n   */\n  __teardownInstance() {\n    if (this.__instance) {\n      let c$ = this.__instance.children;\n      if (c$ && c$.length) {\n        // use first child parent, for case when dom-if may have been detached\n        let parent = wrap(c$[0]).parentNode;\n        // Instance children may be disconnected from parents when dom-if\n        // detaches if a tree was innerHTML'ed\n        if (parent) {\n          parent = wrap(parent);\n          for (let i=0, n; (i<c$.length) && (n=c$[i]); i++) {\n            parent.removeChild(n);\n          }\n        }\n      }\n      this.__invalidProps = null;\n      this.__instance = null;\n    }\n  }\n\n  /**\n   * Forwards any properties that changed while the `if` was false into the\n   * template instance and flushes it.\n   *\n   * @return {void}\n   */\n  __syncHostProperties() {\n    let props = this.__invalidProps;\n    if (props) {\n      this.__invalidProps = null;\n      for (let prop in props) {\n        this.__instance._setPendingProperty(prop, this.__dataHost[prop]);\n      }\n      this.__instance._flushProperties();\n    }\n  }\n\n  /**\n   * Implementation of abstract API needed by DomIfBase.\n   *\n   * Shows or hides the template instance top level child elements. For\n   * text nodes, `textContent` is removed while \"hidden\" and replaced when\n   * \"shown.\"\n   *\n   * @override\n   * @protected\n   * @return {void}\n   * @suppress {visibility}\n   */\n  _showHideChildren() {\n    const hidden = this.__hideTemplateChildren__ || !this.if;\n    if (this.__instance && Boolean(this.__instance.__hidden) !== hidden) {\n      this.__instance.__hidden = hidden;\n      this.__instance._showHideChildren(hidden);\n    }\n    if (!hidden) {\n      this.__syncHostProperties();\n    }\n  }\n}\n\n/**\n * The `<dom-if>` element will stamp a light-dom `<template>` child when\n * the `if` property becomes truthy, and the template can use Polymer\n * data-binding and declarative event features when used in the context of\n * a Polymer element's template.\n *\n * When `if` becomes falsy, the stamped content is hidden but not\n * removed from dom. When `if` subsequently becomes truthy again, the content\n * is simply re-shown. This approach is used due to its favorable performance\n * characteristics: the expense of creating template content is paid only\n * once and lazily.\n *\n * Set the `restamp` property to true to force the stamped content to be\n * created / destroyed when the `if` condition changes.\n *\n * @customElement\n * @polymer\n * @extends DomIfBase\n * @constructor\n * @summary Custom element that conditionally stamps and hides or removes\n *   template content based on a boolean flag.\n */\nexport const DomIf = fastDomIf ? DomIfFast : DomIfLegacy;\n\ncustomElements.define(DomIf.is, DomIf);\n"
  },
  {
    "path": "lib/elements/dom-module.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n// tslint:disable:no-any describes the API as best we are able today\n\nimport {resolveUrl, pathFromUrl} from '../utils/resolve-url.js';\n\nexport {DomModule};\n\n/**\n * The `dom-module` element registers the dom it contains to the name given\n * by the module's id attribute. It provides a unified database of dom\n * accessible via its static `import` API.\n *\n * A key use case of `dom-module` is for providing custom element `<template>`s\n * via HTML imports that are parsed by the native HTML parser, that can be\n * relocated during a bundling pass and still looked up by `id`.\n *\n * Example:\n *\n *     <dom-module id=\"foo\">\n *       <img src=\"stuff.png\">\n *     </dom-module>\n *\n * Then in code in some other location that cannot access the dom-module above\n *\n *     let img = customElements.get('dom-module').import('foo', 'img');\n */\ndeclare class DomModule extends HTMLElement {\n\n  /**\n   * The absolute URL of the original location of this `dom-module`.\n   *\n   * This value will differ from this element's `ownerDocument` in the\n   * following ways:\n   * - Takes into account any `assetpath` attribute added during bundling\n   *   to indicate the original location relative to the bundled location\n   * - Uses the HTMLImports polyfill's `importForElement` API to ensure\n   *   the path is relative to the import document's location since\n   *   `ownerDocument` is not currently polyfilled\n   *    \n   */\n  readonly assetpath: any;\n\n  /**\n   * Retrieves the element specified by the css `selector` in the module\n   * registered by `id`. For example, this.import('foo', 'img');\n   *\n   * @param id The id of the dom-module in which to search.\n   * @param selector The css selector by which to find the element.\n   * @returns Returns the element which matches `selector` in the\n   * module registered at the specified `id`.\n   */\n  static import(id: string, selector?: string): Element|null;\n\n  /**\n   * @param name Name of attribute.\n   * @param old Old value of attribute.\n   * @param value Current value of attribute.\n   * @param namespace Attribute namespace.\n   */\n  attributeChangedCallback(name: string, old: string|null, value: string|null, namespace: string|null): void;\n\n  /**\n   * Registers the dom-module at a given id. This method should only be called\n   * when a dom-module is imperatively created. For\n   * example, `document.createElement('dom-module').register('foo')`.\n   *\n   * @param id The id at which to register the dom-module.\n   */\n  register(id?: string): void;\n}\n\ndeclare global {\n\n  interface HTMLElementTagNameMap {\n    \"dom-module\": DomModule;\n  }\n}\n"
  },
  {
    "path": "lib/elements/dom-module.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport '../utils/boot.js';\n\nimport { resolveUrl, pathFromUrl } from '../utils/resolve-url.js';\nimport { strictTemplatePolicy } from '../utils/settings.js';\n\nlet modules = {};\nlet lcModules = {};\n/**\n * Sets a dom-module into the global registry by id.\n *\n * @param {string} id dom-module id\n * @param {DomModule} module dom-module instance\n * @return {void}\n */\nfunction setModule(id, module) {\n  // store id separate from lowercased id so that\n  // in all cases mixedCase id will stored distinctly\n  // and lowercase version is a fallback\n  modules[id] = lcModules[id.toLowerCase()] = module;\n}\n/**\n * Retrieves a dom-module from the global registry by id.\n *\n * @param {string} id dom-module id\n * @return {DomModule!} dom-module instance\n */\nfunction findModule(id) {\n  return modules[id] || lcModules[id.toLowerCase()];\n}\n\nfunction styleOutsideTemplateCheck(inst) {\n  if (inst.querySelector('style')) {\n    console.warn('dom-module %s has style outside template', inst.id);\n  }\n}\n\n/**\n * The `dom-module` element registers the dom it contains to the name given\n * by the module's id attribute. It provides a unified database of dom\n * accessible via its static `import` API.\n *\n * A key use case of `dom-module` is for providing custom element `<template>`s\n * via HTML imports that are parsed by the native HTML parser, that can be\n * relocated during a bundling pass and still looked up by `id`.\n *\n * Example:\n *\n *     <dom-module id=\"foo\">\n *       <img src=\"stuff.png\">\n *     </dom-module>\n *\n * Then in code in some other location that cannot access the dom-module above\n *\n *     let img = customElements.get('dom-module').import('foo', 'img');\n *\n * @customElement\n * @extends HTMLElement\n * @summary Custom element that provides a registry of relocatable DOM content\n *   by `id` that is agnostic to bundling.\n * @unrestricted\n */\nexport class DomModule extends HTMLElement {\n\n  /** @override */\n  static get observedAttributes() { return ['id']; }\n\n  /**\n   * Retrieves the element specified by the css `selector` in the module\n   * registered by `id`. For example, this.import('foo', 'img');\n   * @param {string} id The id of the dom-module in which to search.\n   * @param {string=} selector The css selector by which to find the element.\n   * @return {Element} Returns the element which matches `selector` in the\n   * module registered at the specified `id`.\n   *\n   * @export\n   * @nocollapse Referred to indirectly in style-gather.js\n   */\n  static import(id, selector) {\n    if (id) {\n      let m = findModule(id);\n      if (m && selector) {\n        return m.querySelector(selector);\n      }\n      return m;\n    }\n    return null;\n  }\n\n  /* eslint-disable no-unused-vars */\n  /**\n   * @param {string} name Name of attribute.\n   * @param {?string} old Old value of attribute.\n   * @param {?string} value Current value of attribute.\n   * @param {?string} namespace Attribute namespace.\n   * @return {void}\n   * @override\n   */\n  attributeChangedCallback(name, old, value, namespace) {\n    if (old !== value) {\n      this.register();\n    }\n  }\n  /* eslint-enable no-unused-args */\n\n  /**\n   * The absolute URL of the original location of this `dom-module`.\n   *\n   * This value will differ from this element's `ownerDocument` in the\n   * following ways:\n   * - Takes into account any `assetpath` attribute added during bundling\n   *   to indicate the original location relative to the bundled location\n   * - Uses the HTMLImports polyfill's `importForElement` API to ensure\n   *   the path is relative to the import document's location since\n   *   `ownerDocument` is not currently polyfilled\n   */\n  get assetpath() {\n    // Don't override existing assetpath.\n    if (!this.__assetpath) {\n      // note: assetpath set via an attribute must be relative to this\n      // element's location; accommodate polyfilled HTMLImports\n      const owner = window.HTMLImports && HTMLImports.importForElement ?\n        HTMLImports.importForElement(this) || document : this.ownerDocument;\n      const url = resolveUrl(\n        this.getAttribute('assetpath') || '', owner.baseURI);\n      this.__assetpath = pathFromUrl(url);\n    }\n    return this.__assetpath;\n  }\n\n  /**\n   * Registers the dom-module at a given id. This method should only be called\n   * when a dom-module is imperatively created. For\n   * example, `document.createElement('dom-module').register('foo')`.\n   * @param {string=} id The id at which to register the dom-module.\n   * @return {void}\n   */\n  register(id) {\n    id = id || this.id;\n    if (id) {\n      // Under strictTemplatePolicy, reject and null out any re-registered\n      // dom-module since it is ambiguous whether first-in or last-in is trusted\n      if (strictTemplatePolicy && findModule(id) !== undefined) {\n        setModule(id, null);\n        throw new Error(`strictTemplatePolicy: dom-module ${id} re-registered`);\n      }\n      this.id = id;\n      setModule(id, this);\n      styleOutsideTemplateCheck(this);\n    }\n  }\n}\n\nDomModule.prototype['modules'] = modules;\n\ncustomElements.define('dom-module', DomModule);\n"
  },
  {
    "path": "lib/elements/dom-repeat.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n// tslint:disable:no-any describes the API as best we are able today\n\nimport {PolymerElement} from '../../polymer-element.js';\n\nimport {TemplateInstanceBase, templatize, modelForElement} from '../utils/templatize.js';\n\nimport {Debouncer} from '../utils/debounce.js';\n\nimport {enqueueDebouncer, flush} from '../utils/flush.js';\n\nimport {OptionalMutableData} from '../mixins/mutable-data.js';\n\nimport {matches, translate} from '../utils/path.js';\n\nimport {timeOut, microTask} from '../utils/async.js';\n\nimport {hideElementsGlobally} from '../utils/hide-template-controls.js';\n\nexport {DomRepeat};\n\n/**\n * The `<dom-repeat>` element will automatically stamp and binds one instance\n * of template content to each object in a user-provided array.\n * `dom-repeat` accepts an `items` property, and one instance of the template\n * is stamped for each item into the DOM at the location of the `dom-repeat`\n * element.  The `item` property will be set on each instance's binding\n * scope, thus templates should bind to sub-properties of `item`.\n *\n * Example:\n *\n * ```html\n * <dom-module id=\"employee-list\">\n *\n *   <template>\n *\n *     <div> Employee list: </div>\n *     <dom-repeat items=\"{{employees}}\">\n *       <template>\n *         <div>First name: <span>{{item.first}}</span></div>\n *         <div>Last name: <span>{{item.last}}</span></div>\n *       </template>\n *     </dom-repeat>\n *\n *   </template>\n *\n * </dom-module>\n * ```\n *\n * With the following custom element definition:\n *\n * ```js\n * class EmployeeList extends PolymerElement {\n *   static get is() { return 'employee-list'; }\n *   static get properties() {\n *     return {\n *       employees: {\n *         value() {\n *           return [\n *             {first: 'Bob', last: 'Smith'},\n *             {first: 'Sally', last: 'Johnson'},\n *             ...\n *           ];\n *         }\n *       }\n *     };\n *   }\n * }\n * ```\n *\n * Notifications for changes to items sub-properties will be forwarded to template\n * instances, which will update via the normal structured data notification system.\n *\n * Mutations to the `items` array itself should be made using the Array\n * mutation API's on the PropertyEffects mixin (`push`, `pop`, `splice`,\n * `shift`, `unshift`), and template instances will be kept in sync with the\n * data in the array.\n *\n * Events caught by event handlers within the `dom-repeat` template will be\n * decorated with a `model` property, which represents the binding scope for\n * each template instance.  The model should be used to manipulate data on the\n * instance, for example `event.model.set('item.checked', true);`.\n *\n * Alternatively, the model for a template instance for an element stamped by\n * a `dom-repeat` can be obtained using the `modelForElement` API on the\n * `dom-repeat` that stamped it, for example\n * `this.$.domRepeat.modelForElement(event.target).set('item.checked', true);`.\n * This may be useful for manipulating instance data of event targets obtained\n * by event handlers on parents of the `dom-repeat` (event delegation).\n *\n * A view-specific filter/sort may be applied to each `dom-repeat` by supplying a\n * `filter` and/or `sort` property.  This may be a string that names a function on\n * the host, or a function may be assigned to the property directly.  The functions\n * should implemented following the standard `Array` filter/sort API.\n *\n * In order to re-run the filter or sort functions based on changes to sub-fields\n * of `items`, the `observe` property may be set as a space-separated list of\n * `item` sub-fields that should cause a re-filter/sort when modified.  If\n * the filter or sort function depends on properties not contained in `items`,\n * the user should observe changes to those properties and call `render` to update\n * the view based on the dependency change.\n *\n * For example, for an `dom-repeat` with a filter of the following:\n *\n * ```js\n * isEngineer(item) {\n *   return item.type == 'engineer' || item.manager.type == 'engineer';\n * }\n * ```\n *\n * Then the `observe` property should be configured as follows:\n *\n * ```html\n * <dom-repeat items=\"{{employees}}\" filter=\"isEngineer\" observe=\"type manager.type\">\n * ```\n */\ndeclare class DomRepeat extends\n  OptionalMutableData(\n  PolymerElement) {\n  _templateInfo: TemplateInfo|null;\n\n  /**\n   * An array containing items determining how many instances of the template\n   * to stamp and that that each template instance should bind to.\n   */\n  items: any[]|null|undefined;\n\n  /**\n   * The name of the variable to add to the binding scope for the array\n   * element associated with a given template instance.\n   */\n  as: string|null|undefined;\n\n  /**\n   * The name of the variable to add to the binding scope with the index\n   * of the instance in the sorted and filtered list of rendered items.\n   * Note, for the index in the `this.items` array, use the value of the\n   * `itemsIndexAs` property.\n   */\n  indexAs: string|null|undefined;\n\n  /**\n   * The name of the variable to add to the binding scope with the index\n   * of the instance in the `this.items` array. Note, for the index of\n   * this instance in the sorted and filtered list of rendered items,\n   * use the value of the `indexAs` property.\n   */\n  itemsIndexAs: string|null|undefined;\n\n  /**\n   * A function that should determine the sort order of the items.  This\n   * property should either be provided as a string, indicating a method\n   * name on the element's host, or else be an actual function.  The\n   * function should match the sort function passed to `Array.sort`.\n   * Using a sort function has no effect on the underlying `items` array.\n   */\n  sort: Function|null|undefined;\n\n  /**\n   * A function that can be used to filter items out of the view.  This\n   * property should either be provided as a string, indicating a method\n   * name on the element's host, or else be an actual function.  The\n   * function should match the sort function passed to `Array.filter`.\n   * Using a filter function has no effect on the underlying `items` array.\n   */\n  filter: Function|null|undefined;\n\n  /**\n   * When using a `filter` or `sort` function, the `observe` property\n   * should be set to a space-separated list of the names of item\n   * sub-fields that should trigger a re-sort or re-filter when changed.\n   * These should generally be fields of `item` that the sort or filter\n   * function depends on.\n   */\n  observe: string|null|undefined;\n\n  /**\n   * When using a `filter` or `sort` function, the `delay` property\n   * determines a debounce time in ms after a change to observed item\n   * properties that must pass before the filter or sort is re-run.\n   * This is useful in rate-limiting shuffling of the view when\n   * item changes may be frequent.\n   */\n  delay: number|null|undefined;\n\n  /**\n   * Count of currently rendered items after `filter` (if any) has been applied.\n   * If \"chunking mode\" is enabled, `renderedItemCount` is updated each time a\n   * set of template instances is rendered.\n   */\n  readonly renderedItemCount: number|null|undefined;\n\n  /**\n   * When greater than zero, defines an initial count of template instances\n   * to render after setting the `items` array, before the next paint, and\n   * puts the `dom-repeat` into \"chunking mode\".  The remaining items (and\n   * any future items as a result of pushing onto the array) will be created\n   * and rendered incrementally at each animation frame thereof until all\n   * instances have been rendered.\n   */\n  initialCount: number|null|undefined;\n\n  /**\n   * When `initialCount` is used, this property defines a frame rate (in\n   * fps) to target by throttling the number of instances rendered each\n   * frame to not exceed the budget for the target frame rate.  The\n   * framerate is effectively the number of `requestAnimationFrame`s that\n   * it tries to allow to actually fire in a given second. It does this\n   * by measuring the time between `rAF`s and continuously adjusting the\n   * number of items created each `rAF` to maintain the target framerate.\n   * Setting this to a higher number allows lower latency and higher\n   * throughput for event handlers and other tasks, but results in a\n   * longer time for the remaining items to complete rendering.\n   */\n  targetFramerate: number|null|undefined;\n  readonly _targetFrameTime: number|null|undefined;\n\n  /**\n   * When the global `suppressTemplateNotifications` setting is used, setting\n   * `notifyDomChange: true` will enable firing `dom-change` events on this\n   * element.\n   */\n  notifyDomChange: boolean|null|undefined;\n\n  /**\n   * When chunking is enabled via `initialCount` and the `items` array is\n   * set to a new array, this flag controls whether the previously rendered\n   * instances are reused or not.\n   *\n   * When `true`, any previously rendered template instances are updated in\n   * place to their new item values synchronously in one shot, and then any\n   * further items (if any) are chunked out.  When `false`, the list is\n   * returned back to its `initialCount` (any instances over the initial\n   * count are discarded) and the remainder of the list is chunked back in.\n   * Set this to `true` to avoid re-creating the list and losing scroll\n   * position, although note that when changing the list to completely\n   * different data the render thread will be blocked until all existing\n   * instances are updated to their new data.\n   */\n  reuseChunkedInstances: boolean|null|undefined;\n  connectedCallback(): void;\n  disconnectedCallback(): void;\n\n  /**\n   * Forces the element to render its content. Normally rendering is\n   * asynchronous to a provoking change. This is done for efficiency so\n   * that multiple changes trigger only a single render. The render method\n   * should be called if, for example, template rendering is required to\n   * validate application state.\n   */\n  render(): void;\n\n  /**\n   * Shows or hides the template instance top level child elements. For\n   * text nodes, `textContent` is removed while \"hidden\" and replaced when\n   * \"shown.\"\n   *\n   * @param hidden Set to true to hide the children;\n   * set to false to show them.\n   */\n  _showHideChildren(hidden: boolean): void;\n\n  /**\n   * Returns the item associated with a given element stamped by\n   * this `dom-repeat`.\n   *\n   * Note, to modify sub-properties of the item,\n   * `modelForElement(el).set('item.<sub-prop>', value)`\n   * should be used.\n   *\n   * @param el Element for which to return the item.\n   * @returns Item associated with the element.\n   */\n  itemForElement(el: HTMLElement): any;\n\n  /**\n   * Returns the inst index for a given element stamped by this `dom-repeat`.\n   * If `sort` is provided, the index will reflect the sorted order (rather\n   * than the original array order).\n   *\n   * @param el Element for which to return the index.\n   * @returns Row index associated with the element (note this may\n   *   not correspond to the array index if a user `sort` is applied).\n   */\n  indexForElement(el: HTMLElement): number|null;\n\n  /**\n   * Returns the template \"model\" associated with a given element, which\n   * serves as the binding scope for the template instance the element is\n   * contained in. A template model\n   * should be used to manipulate data associated with this template instance.\n   *\n   * Example:\n   *\n   *   let model = modelForElement(el);\n   *   if (model.index < 10) {\n   *     model.set('item.checked', true);\n   *   }\n   *\n   * @param el Element for which to return a template model.\n   * @returns Model representing the binding scope for\n   *   the element.\n   */\n  modelForElement(el: HTMLElement): TemplateInstanceBase|null;\n}\n\ndeclare global {\n\n  interface HTMLElementTagNameMap {\n    \"dom-repeat\": DomRepeat;\n  }\n}\n\nimport {TemplateInfo} from '../../interfaces';\n"
  },
  {
    "path": "lib/elements/dom-repeat.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport { PolymerElement } from '../../polymer-element.js';\n\nimport { TemplateInstanceBase, templatize, modelForElement } from '../utils/templatize.js'; // eslint-disable-line no-unused-vars\nimport { Debouncer } from '../utils/debounce.js';\nimport { enqueueDebouncer, flush } from '../utils/flush.js';\nimport { OptionalMutableData } from '../mixins/mutable-data.js';\nimport { matches, translate } from '../utils/path.js';\nimport { timeOut, microTask } from '../utils/async.js';\nimport { wrap } from '../utils/wrap.js';\nimport { hideElementsGlobally } from '../utils/hide-template-controls.js';\nimport { suppressTemplateNotifications } from '../utils/settings.js';\n\n/**\n * @constructor\n * @implements {Polymer_OptionalMutableData}\n * @extends {PolymerElement}\n * @private\n */\nconst domRepeatBase = OptionalMutableData(PolymerElement);\n\n/**\n * The `<dom-repeat>` element will automatically stamp and binds one instance\n * of template content to each object in a user-provided array.\n * `dom-repeat` accepts an `items` property, and one instance of the template\n * is stamped for each item into the DOM at the location of the `dom-repeat`\n * element.  The `item` property will be set on each instance's binding\n * scope, thus templates should bind to sub-properties of `item`.\n *\n * Example:\n *\n * ```html\n * <dom-module id=\"employee-list\">\n *\n *   <template>\n *\n *     <div> Employee list: </div>\n *     <dom-repeat items=\"{{employees}}\">\n *       <template>\n *         <div>First name: <span>{{item.first}}</span></div>\n *         <div>Last name: <span>{{item.last}}</span></div>\n *       </template>\n *     </dom-repeat>\n *\n *   </template>\n *\n * </dom-module>\n * ```\n *\n * With the following custom element definition:\n *\n * ```js\n * class EmployeeList extends PolymerElement {\n *   static get is() { return 'employee-list'; }\n *   static get properties() {\n *     return {\n *       employees: {\n *         value() {\n *           return [\n *             {first: 'Bob', last: 'Smith'},\n *             {first: 'Sally', last: 'Johnson'},\n *             ...\n *           ];\n *         }\n *       }\n *     };\n *   }\n * }\n * ```\n *\n * Notifications for changes to items sub-properties will be forwarded to template\n * instances, which will update via the normal structured data notification system.\n *\n * Mutations to the `items` array itself should be made using the Array\n * mutation API's on the PropertyEffects mixin (`push`, `pop`, `splice`,\n * `shift`, `unshift`), and template instances will be kept in sync with the\n * data in the array.\n *\n * Events caught by event handlers within the `dom-repeat` template will be\n * decorated with a `model` property, which represents the binding scope for\n * each template instance.  The model should be used to manipulate data on the\n * instance, for example `event.model.set('item.checked', true);`.\n *\n * Alternatively, the model for a template instance for an element stamped by\n * a `dom-repeat` can be obtained using the `modelForElement` API on the\n * `dom-repeat` that stamped it, for example\n * `this.$.domRepeat.modelForElement(event.target).set('item.checked', true);`.\n * This may be useful for manipulating instance data of event targets obtained\n * by event handlers on parents of the `dom-repeat` (event delegation).\n *\n * A view-specific filter/sort may be applied to each `dom-repeat` by supplying a\n * `filter` and/or `sort` property.  This may be a string that names a function on\n * the host, or a function may be assigned to the property directly.  The functions\n * should implemented following the standard `Array` filter/sort API.\n *\n * In order to re-run the filter or sort functions based on changes to sub-fields\n * of `items`, the `observe` property may be set as a space-separated list of\n * `item` sub-fields that should cause a re-filter/sort when modified.  If\n * the filter or sort function depends on properties not contained in `items`,\n * the user should observe changes to those properties and call `render` to update\n * the view based on the dependency change.\n *\n * For example, for an `dom-repeat` with a filter of the following:\n *\n * ```js\n * isEngineer(item) {\n *   return item.type == 'engineer' || item.manager.type == 'engineer';\n * }\n * ```\n *\n * Then the `observe` property should be configured as follows:\n *\n * ```html\n * <dom-repeat items=\"{{employees}}\" filter=\"isEngineer\" observe=\"type manager.type\">\n * ```\n *\n * @customElement\n * @polymer\n * @extends {domRepeatBase}\n * @appliesMixin OptionalMutableData\n * @summary Custom element for stamping instance of a template bound to\n *   items in an array.\n */\nexport class DomRepeat extends domRepeatBase {\n\n  // Not needed to find template; can be removed once the analyzer\n  // can find the tag name from customElements.define call\n  static get is() { return 'dom-repeat'; }\n\n  static get template() { return null; }\n\n  static get properties() {\n\n    /**\n     * Fired whenever DOM is added or removed by this template (by\n     * default, rendering occurs lazily).  To force immediate rendering, call\n     * `render`.\n     *\n     * @event dom-change\n     */\n    return {\n\n      /**\n       * An array containing items determining how many instances of the template\n       * to stamp and that that each template instance should bind to.\n       */\n      items: {\n        type: Array\n      },\n\n      /**\n       * The name of the variable to add to the binding scope for the array\n       * element associated with a given template instance.\n       */\n      as: {\n        type: String,\n        value: 'item'\n      },\n\n      /**\n       * The name of the variable to add to the binding scope with the index\n       * of the instance in the sorted and filtered list of rendered items.\n       * Note, for the index in the `this.items` array, use the value of the\n       * `itemsIndexAs` property.\n       */\n      indexAs: {\n        type: String,\n        value: 'index'\n      },\n\n      /**\n       * The name of the variable to add to the binding scope with the index\n       * of the instance in the `this.items` array. Note, for the index of\n       * this instance in the sorted and filtered list of rendered items,\n       * use the value of the `indexAs` property.\n       */\n      itemsIndexAs: {\n        type: String,\n        value: 'itemsIndex'\n      },\n\n      /**\n       * A function that should determine the sort order of the items.  This\n       * property should either be provided as a string, indicating a method\n       * name on the element's host, or else be an actual function.  The\n       * function should match the sort function passed to `Array.sort`.\n       * Using a sort function has no effect on the underlying `items` array.\n       */\n      sort: {\n        type: Function,\n        observer: '__sortChanged'\n      },\n\n      /**\n       * A function that can be used to filter items out of the view.  This\n       * property should either be provided as a string, indicating a method\n       * name on the element's host, or else be an actual function.  The\n       * function should match the sort function passed to `Array.filter`.\n       * Using a filter function has no effect on the underlying `items` array.\n       */\n      filter: {\n        type: Function,\n        observer: '__filterChanged'\n      },\n\n      /**\n       * When using a `filter` or `sort` function, the `observe` property\n       * should be set to a space-separated list of the names of item\n       * sub-fields that should trigger a re-sort or re-filter when changed.\n       * These should generally be fields of `item` that the sort or filter\n       * function depends on.\n       */\n      observe: {\n        type: String,\n        observer: '__observeChanged'\n      },\n\n      /**\n       * When using a `filter` or `sort` function, the `delay` property\n       * determines a debounce time in ms after a change to observed item\n       * properties that must pass before the filter or sort is re-run.\n       * This is useful in rate-limiting shuffling of the view when\n       * item changes may be frequent.\n       */\n      delay: Number,\n\n      /**\n       * Count of currently rendered items after `filter` (if any) has been applied.\n       * If \"chunking mode\" is enabled, `renderedItemCount` is updated each time a\n       * set of template instances is rendered.\n       *\n       */\n      renderedItemCount: {\n        type: Number,\n        notify: !suppressTemplateNotifications,\n        readOnly: true\n      },\n\n      /**\n       * When greater than zero, defines an initial count of template instances\n       * to render after setting the `items` array, before the next paint, and\n       * puts the `dom-repeat` into \"chunking mode\".  The remaining items (and\n       * any future items as a result of pushing onto the array) will be created\n       * and rendered incrementally at each animation frame thereof until all\n       * instances have been rendered.\n       */\n      initialCount: {\n        type: Number\n      },\n\n      /**\n       * When `initialCount` is used, this property defines a frame rate (in\n       * fps) to target by throttling the number of instances rendered each\n       * frame to not exceed the budget for the target frame rate.  The\n       * framerate is effectively the number of `requestAnimationFrame`s that\n       * it tries to allow to actually fire in a given second. It does this\n       * by measuring the time between `rAF`s and continuously adjusting the\n       * number of items created each `rAF` to maintain the target framerate.\n       * Setting this to a higher number allows lower latency and higher\n       * throughput for event handlers and other tasks, but results in a\n       * longer time for the remaining items to complete rendering.\n       */\n      targetFramerate: {\n        type: Number,\n        value: 20\n      },\n\n      _targetFrameTime: {\n        type: Number,\n        computed: '__computeFrameTime(targetFramerate)'\n      },\n\n      /**\n       * When the global `suppressTemplateNotifications` setting is used, setting\n       * `notifyDomChange: true` will enable firing `dom-change` events on this\n       * element.\n       */\n      notifyDomChange: {\n        type: Boolean\n      },\n\n      /**\n       * When chunking is enabled via `initialCount` and the `items` array is\n       * set to a new array, this flag controls whether the previously rendered\n       * instances are reused or not.\n       *\n       * When `true`, any previously rendered template instances are updated in\n       * place to their new item values synchronously in one shot, and then any\n       * further items (if any) are chunked out.  When `false`, the list is\n       * returned back to its `initialCount` (any instances over the initial\n       * count are discarded) and the remainder of the list is chunked back in.\n       * Set this to `true` to avoid re-creating the list and losing scroll\n       * position, although note that when changing the list to completely\n       * different data the render thread will be blocked until all existing\n       * instances are updated to their new data.\n       */\n      reuseChunkedInstances: {\n        type: Boolean\n      }\n\n    };\n\n  }\n\n  static get observers() {\n    return [ '__itemsChanged(items.*)' ];\n  }\n\n  constructor() {\n    super();\n    this.__instances = [];\n    this.__renderDebouncer = null;\n    this.__itemsIdxToInstIdx = {};\n    this.__chunkCount = null;\n    this.__renderStartTime = null;\n    this.__itemsArrayChanged = false;\n    this.__shouldMeasureChunk = false;\n    this.__shouldContinueChunking = false;\n    this.__chunkingId = 0;\n    this.__sortFn = null;\n    this.__filterFn = null;\n    this.__observePaths = null;\n    /** @type {?function(new:TemplateInstanceBase, Object=)} */\n    this.__ctor = null;\n    this.__isDetached = true;\n    this.template = null;\n    /** @type {TemplateInfo} */\n    this._templateInfo;\n  }\n\n  /**\n   * @override\n   * @return {void}\n   */\n  disconnectedCallback() {\n    super.disconnectedCallback();\n    this.__isDetached = true;\n    for (let i=0; i<this.__instances.length; i++) {\n      this.__detachInstance(i);\n    }\n    // Stop chunking if one was in progress\n    if (this.__chunkingId) {\n      cancelAnimationFrame(this.__chunkingId);\n    }\n  }\n\n  /**\n   * @override\n   * @return {void}\n   */\n  connectedCallback() {\n    super.connectedCallback();\n    if (!hideElementsGlobally()) {\n      this.style.display = 'none';\n    }\n    // only perform attachment if the element was previously detached.\n    if (this.__isDetached) {\n      this.__isDetached = false;\n      let wrappedParent = wrap(wrap(this).parentNode);\n      for (let i=0; i<this.__instances.length; i++) {\n        this.__attachInstance(i, wrappedParent);\n      }\n      // Restart chunking if one was in progress when disconnected\n      if (this.__chunkingId) {\n        this.__render();\n      }\n    }\n  }\n\n  __ensureTemplatized() {\n    // Templatizing (generating the instance constructor) needs to wait\n    // until ready, since won't have its template content handed back to\n    // it until then\n    if (!this.__ctor) {\n      // When `removeNestedTemplates` is true, the \"template\" is the element\n      // itself, which has been given a `_templateInfo` property\n      const thisAsTemplate = /** @type {!HTMLTemplateElement} */ (\n          /** @type {!HTMLElement} */ (this));\n      let template = this.template = thisAsTemplate._templateInfo ?\n          thisAsTemplate :\n          /** @type {!HTMLTemplateElement} */ (this.querySelector('template'));\n      if (!template) {\n        // Wait until childList changes and template should be there by then\n        let observer = new MutationObserver(() => {\n          if (this.querySelector('template')) {\n            observer.disconnect();\n            this.__render();\n          } else {\n            throw new Error('dom-repeat requires a <template> child');\n          }\n        });\n        observer.observe(this, {childList: true});\n        return false;\n      }\n      // Template instance props that should be excluded from forwarding\n      let instanceProps = {};\n      instanceProps[this.as] = true;\n      instanceProps[this.indexAs] = true;\n      instanceProps[this.itemsIndexAs] = true;\n      this.__ctor = templatize(template, this, {\n        mutableData: this.mutableData,\n        parentModel: true,\n        instanceProps: instanceProps,\n        /**\n         * @this {DomRepeat}\n         * @param {string} prop Property to set\n         * @param {*} value Value to set property to\n         */\n        forwardHostProp: function(prop, value) {\n          let i$ = this.__instances;\n          for (let i=0, inst; (i<i$.length) && (inst=i$[i]); i++) {\n            inst.forwardHostProp(prop, value);\n          }\n        },\n        /**\n         * @this {DomRepeat}\n         * @param {Object} inst Instance to notify\n         * @param {string} prop Property to notify\n         * @param {*} value Value to notify\n         */\n        notifyInstanceProp: function(inst, prop, value) {\n          if (matches(this.as, prop)) {\n            let idx = inst[this.itemsIndexAs];\n            if (prop == this.as) {\n              this.items[idx] = value;\n            }\n            let path = translate(this.as, `${JSCompiler_renameProperty('items', this)}.${idx}`, prop);\n            this.notifyPath(path, value);\n          }\n        }\n      });\n    }\n    return true;\n  }\n\n  __getMethodHost() {\n    // Technically this should be the owner of the outermost template.\n    // In shadow dom, this is always getRootNode().host, but we can\n    // approximate this via cooperation with our dataHost always setting\n    // `_methodHost` as long as there were bindings (or id's) on this\n    // instance causing it to get a dataHost.\n    return this.__dataHost._methodHost || this.__dataHost;\n  }\n\n  __functionFromPropertyValue(functionOrMethodName) {\n    if (typeof functionOrMethodName === 'string') {\n      let methodName = functionOrMethodName;\n      let obj = this.__getMethodHost();\n      return function() { return obj[methodName].apply(obj, arguments); };\n    }\n\n    return functionOrMethodName;\n  }\n\n  __sortChanged(sort) {\n    this.__sortFn = this.__functionFromPropertyValue(sort);\n    if (this.items) { this.__debounceRender(this.__render); }\n  }\n\n  __filterChanged(filter) {\n    this.__filterFn = this.__functionFromPropertyValue(filter);\n    if (this.items) { this.__debounceRender(this.__render); }\n  }\n\n  __computeFrameTime(rate) {\n    return Math.ceil(1000/rate);\n  }\n\n  __observeChanged() {\n    this.__observePaths = this.observe &&\n      this.observe.replace('.*', '.').split(' ');\n  }\n\n  __handleObservedPaths(path) {\n    // Handle cases where path changes should cause a re-sort/filter\n    if (this.__sortFn || this.__filterFn) {\n      if (!path) {\n        // Always re-render if the item itself changed\n        this.__debounceRender(this.__render, this.delay);\n      } else if (this.__observePaths) {\n        // Otherwise, re-render if the path changed matches an observed path\n        let paths = this.__observePaths;\n        for (let i=0; i<paths.length; i++) {\n          if (path.indexOf(paths[i]) === 0) {\n            this.__debounceRender(this.__render, this.delay);\n          }\n        }\n      }\n    }\n  }\n\n  __itemsChanged(change) {\n    if (this.items && !Array.isArray(this.items)) {\n      console.warn('dom-repeat expected array for `items`, found', this.items);\n    }\n    // If path was to an item (e.g. 'items.3' or 'items.3.foo'), forward the\n    // path to that instance synchronously (returns false for non-item paths)\n    if (!this.__handleItemPath(change.path, change.value)) {\n      // Otherwise, the array was reset ('items') or spliced ('items.splices'),\n      // so queue a render.  Restart chunking when the items changed (for\n      // backward compatibility), unless `reuseChunkedInstances` option is set\n      if (change.path === 'items') {\n        this.__itemsArrayChanged = true;\n      }\n      this.__debounceRender(this.__render);\n    }\n  }\n\n  /**\n   * @param {function(this:DomRepeat)} fn Function to debounce.\n   * @param {number=} delay Delay in ms to debounce by.\n   */\n  __debounceRender(fn, delay = 0) {\n    this.__renderDebouncer = Debouncer.debounce(\n          this.__renderDebouncer\n        , delay > 0 ? timeOut.after(delay) : microTask\n        , fn.bind(this));\n    enqueueDebouncer(this.__renderDebouncer);\n  }\n\n  /**\n   * Forces the element to render its content. Normally rendering is\n   * asynchronous to a provoking change. This is done for efficiency so\n   * that multiple changes trigger only a single render. The render method\n   * should be called if, for example, template rendering is required to\n   * validate application state.\n   * @return {void}\n   */\n  render() {\n    // Queue this repeater, then flush all in order\n    this.__debounceRender(this.__render);\n    flush();\n  }\n\n  __render() {\n    if (!this.__ensureTemplatized()) {\n      // No template found yet\n      return;\n    }\n    let items = this.items || [];\n    // Sort and filter the items into a mapping array from instance->item\n    const isntIdxToItemsIdx = this.__sortAndFilterItems(items);\n    // If we're chunking, increase the limit if there are new instances to\n    // create and schedule the next chunk\n    const limit = this.__calculateLimit(isntIdxToItemsIdx.length);\n    // Create, update, and/or remove instances\n    this.__updateInstances(items, limit, isntIdxToItemsIdx);\n    // If we're chunking, schedule a rAF task to measure/continue chunking.     \n    // Do this before any notifying events (renderedItemCount & dom-change)\n    // since those could modify items and enqueue a new full render which will\n    // pre-empt this measurement.\n    if (this.initialCount &&\n       (this.__shouldMeasureChunk || this.__shouldContinueChunking)) {\n      cancelAnimationFrame(this.__chunkingId);\n      this.__chunkingId = requestAnimationFrame(() => {\n        this.__chunkingId = null;\n        this.__continueChunking();\n      });\n    }\n    // Set rendered item count\n    this._setRenderedItemCount(this.__instances.length);\n    // Notify users\n    if (!suppressTemplateNotifications || this.notifyDomChange) {\n      this.dispatchEvent(new CustomEvent('dom-change', {\n        bubbles: true,\n        composed: true\n      }));\n    }\n  }\n\n  __sortAndFilterItems(items) {\n    // Generate array maping the instance index to the items array index\n    let isntIdxToItemsIdx = new Array(items.length);\n    for (let i=0; i<items.length; i++) {\n      isntIdxToItemsIdx[i] = i;\n    }\n    // Apply user filter\n    if (this.__filterFn) {\n      isntIdxToItemsIdx = isntIdxToItemsIdx.filter((i, idx, array) =>\n        this.__filterFn(items[i], idx, array));\n    }\n    // Apply user sort\n    if (this.__sortFn) {\n      isntIdxToItemsIdx.sort((a, b) => this.__sortFn(items[a], items[b]));\n    }\n    return isntIdxToItemsIdx;\n  }\n\n  __calculateLimit(filteredItemCount) {\n    let limit = filteredItemCount;\n    const currentCount = this.__instances.length;\n    // When chunking, we increase the limit from the currently rendered count\n    // by the chunk count that is re-calculated after each rAF (with special\n    // cases for resetting the limit to initialCount after changing items)\n    if (this.initialCount) {\n      let newCount;\n      if (!this.__chunkCount ||\n        (this.__itemsArrayChanged && !this.reuseChunkedInstances)) {\n        // Limit next render to the initial count\n        limit = Math.min(filteredItemCount, this.initialCount);\n        // Subtract off any existing instances to determine the number of\n        // instances that will be created\n        newCount = Math.max(limit - currentCount, 0);\n        // Initialize the chunk size with how many items we're creating\n        this.__chunkCount = newCount || 1;\n      } else {\n        // The number of new instances that will be created is based on the\n        // existing instances, the new list size, and the chunk size\n        newCount = Math.min(\n          Math.max(filteredItemCount - currentCount, 0), \n          this.__chunkCount);\n        // Update the limit based on how many new items we're making, limited\n        // buy the total size of the list\n        limit = Math.min(currentCount + newCount, filteredItemCount);\n      }\n      // Record some state about chunking for use in `__continueChunking`\n      this.__shouldMeasureChunk = newCount === this.__chunkCount;\n      this.__shouldContinueChunking = limit < filteredItemCount;\n      this.__renderStartTime = performance.now();\n    }\n    this.__itemsArrayChanged = false;\n    return limit;\n  }\n\n  __continueChunking() {\n    // Simple auto chunkSize throttling algorithm based on feedback loop:\n    // measure actual time between frames and scale chunk count by ratio of\n    // target/actual frame time.  Only modify chunk size if our measurement\n    // reflects the cost of a creating a full chunk's worth of instances; this\n    // avoids scaling up the chunk size if we e.g. quickly re-rendered instances\n    // in place\n    if (this.__shouldMeasureChunk) {\n      const renderTime = performance.now() - this.__renderStartTime;\n      const ratio = this._targetFrameTime / renderTime;\n      this.__chunkCount = Math.round(this.__chunkCount * ratio) || 1;\n    }\n    // Enqueue a new render if we haven't reached the full size of the list\n    if (this.__shouldContinueChunking) {\n      this.__debounceRender(this.__render);\n    }\n  }\n  \n  __updateInstances(items, limit, isntIdxToItemsIdx) {\n    // items->inst map kept for item path forwarding\n    const itemsIdxToInstIdx = this.__itemsIdxToInstIdx = {};\n    let instIdx;\n    // Generate instances and assign items\n    for (instIdx=0; instIdx<limit; instIdx++) {\n      let inst = this.__instances[instIdx];\n      let itemIdx = isntIdxToItemsIdx[instIdx];\n      let item = items[itemIdx];\n      itemsIdxToInstIdx[itemIdx] = instIdx;\n      if (inst) {\n        inst._setPendingProperty(this.as, item);\n        inst._setPendingProperty(this.indexAs, instIdx);\n        inst._setPendingProperty(this.itemsIndexAs, itemIdx);\n        inst._flushProperties();\n      } else {\n        this.__insertInstance(item, instIdx, itemIdx);\n      }\n    }\n    // Remove any extra instances from previous state\n    for (let i=this.__instances.length-1; i>=instIdx; i--) {\n      this.__detachAndRemoveInstance(i);\n    }\n  }\n\n  __detachInstance(idx) {\n    let inst = this.__instances[idx];\n    const wrappedRoot = wrap(inst.root);\n    for (let i=0; i<inst.children.length; i++) {\n      let el = inst.children[i];\n      wrappedRoot.appendChild(el);\n    }\n    return inst;\n  }\n\n  __attachInstance(idx, parent) {\n    let inst = this.__instances[idx];\n    // Note, this is pre-wrapped as an optimization\n    parent.insertBefore(inst.root, this);\n  }\n\n  __detachAndRemoveInstance(idx) {\n    this.__detachInstance(idx);\n    this.__instances.splice(idx, 1);\n  }\n\n  __stampInstance(item, instIdx, itemIdx) {\n    let model = {};\n    model[this.as] = item;\n    model[this.indexAs] = instIdx;\n    model[this.itemsIndexAs] = itemIdx;\n    return new this.__ctor(model);\n  }\n\n  __insertInstance(item, instIdx, itemIdx) {\n    const inst = this.__stampInstance(item, instIdx, itemIdx);\n    let beforeRow = this.__instances[instIdx + 1];\n    let beforeNode = beforeRow ? beforeRow.children[0] : this;\n    wrap(wrap(this).parentNode).insertBefore(inst.root, beforeNode);\n    this.__instances[instIdx] = inst;\n    return inst;\n  }\n\n  // Implements extension point from Templatize mixin\n  /**\n   * Shows or hides the template instance top level child elements. For\n   * text nodes, `textContent` is removed while \"hidden\" and replaced when\n   * \"shown.\"\n   * @param {boolean} hidden Set to true to hide the children;\n   * set to false to show them.\n   * @return {void}\n   * @protected\n   */\n  _showHideChildren(hidden) {\n    for (let i=0; i<this.__instances.length; i++) {\n      this.__instances[i]._showHideChildren(hidden);\n    }\n  }\n\n  // Called as a side effect of a host items.<key>.<path> path change,\n  // responsible for notifying item.<path> changes to inst for key\n  __handleItemPath(path, value) {\n    let itemsPath = path.slice(6); // 'items.'.length == 6\n    let dot = itemsPath.indexOf('.');\n    let itemsIdx = dot < 0 ? itemsPath : itemsPath.substring(0, dot);\n    // If path was index into array...\n    if (itemsIdx == parseInt(itemsIdx, 10)) {\n      let itemSubPath = dot < 0 ? '' : itemsPath.substring(dot+1);\n      // If the path is observed, it will trigger a full refresh\n      this.__handleObservedPaths(itemSubPath);\n      // Note, even if a rull refresh is triggered, always do the path\n      // notification because unless mutableData is used for dom-repeat\n      // and all elements in the instance subtree, a full refresh may\n      // not trigger the proper update.\n      let instIdx = this.__itemsIdxToInstIdx[itemsIdx];\n      let inst = this.__instances[instIdx];\n      if (inst) {\n        let itemPath = this.as + (itemSubPath ? '.' + itemSubPath : '');\n        // This is effectively `notifyPath`, but avoids some of the overhead\n        // of the public API\n        inst._setPendingPropertyOrPath(itemPath, value, false, true);\n        inst._flushProperties();\n      }\n      return true;\n    }\n  }\n\n  /**\n   * Returns the item associated with a given element stamped by\n   * this `dom-repeat`.\n   *\n   * Note, to modify sub-properties of the item,\n   * `modelForElement(el).set('item.<sub-prop>', value)`\n   * should be used.\n   *\n   * @param {!HTMLElement} el Element for which to return the item.\n   * @return {*} Item associated with the element.\n   */\n  itemForElement(el) {\n    let instance = this.modelForElement(el);\n    return instance && instance[this.as];\n  }\n\n  /**\n   * Returns the inst index for a given element stamped by this `dom-repeat`.\n   * If `sort` is provided, the index will reflect the sorted order (rather\n   * than the original array order).\n   *\n   * @param {!HTMLElement} el Element for which to return the index.\n   * @return {?number} Row index associated with the element (note this may\n   *   not correspond to the array index if a user `sort` is applied).\n   */\n  indexForElement(el) {\n    let instance = this.modelForElement(el);\n    return instance && instance[this.indexAs];\n  }\n\n  /**\n   * Returns the template \"model\" associated with a given element, which\n   * serves as the binding scope for the template instance the element is\n   * contained in. A template model\n   * should be used to manipulate data associated with this template instance.\n   *\n   * Example:\n   *\n   *   let model = modelForElement(el);\n   *   if (model.index < 10) {\n   *     model.set('item.checked', true);\n   *   }\n   *\n   * @param {!HTMLElement} el Element for which to return a template model.\n   * @return {TemplateInstanceBase} Model representing the binding scope for\n   *   the element.\n   */\n  modelForElement(el) {\n    return modelForElement(this.template, el);\n  }\n\n}\n\ncustomElements.define(DomRepeat.is, DomRepeat);\n"
  },
  {
    "path": "lib/legacy/class.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n// tslint:disable:no-any describes the API as best we are able today\n\nimport {LegacyElementMixin} from './legacy-element-mixin.js';\n\nexport {mixinBehaviors};\n\n\n/**\n * Applies a \"legacy\" behavior or array of behaviors to the provided class.\n *\n * Note: this method will automatically also apply the `LegacyElementMixin`\n * to ensure that any legacy behaviors can rely on legacy Polymer API on\n * the underlying element.\n *\n * @returns Returns a new Element class extended by the\n * passed in `behaviors` and also by `LegacyElementMixin`.\n */\ndeclare function mixinBehaviors<T>(behaviors: object|object[], klass: {new(): T}): {new(): T};\n\nexport {Class};\n\n\n/**\n * Generates a class that extends `LegacyElement` based on the\n * provided info object.  Metadata objects on the `info` object\n * (`properties`, `observers`, `listeners`, `behaviors`, `is`) are used\n * for Polymer's meta-programming systems, and any functions are copied\n * to the generated class.\n *\n * Valid \"metadata\" values are as follows:\n *\n * `is`: String providing the tag name to register the element under. In\n * addition, if a `dom-module` with the same id exists, the first template\n * in that `dom-module` will be stamped into the shadow root of this element,\n * with support for declarative event listeners (`on-...`), Polymer data\n * bindings (`[[...]]` and `{{...}}`), and id-based node finding into\n * `this.$`.\n *\n * `properties`: Object describing property-related metadata used by Polymer\n * features (key: property names, value: object containing property metadata).\n * Valid keys in per-property metadata include:\n * - `type` (String|Number|Object|Array|...): Used by\n *   `attributeChangedCallback` to determine how string-based attributes\n *   are deserialized to JavaScript property values.\n * - `notify` (boolean): Causes a change in the property to fire a\n *   non-bubbling event called `<property>-changed`. Elements that have\n *   enabled two-way binding to the property use this event to observe changes.\n * - `readOnly` (boolean): Creates a getter for the property, but no setter.\n *   To set a read-only property, use the private setter method\n *   `_setProperty(property, value)`.\n * - `observer` (string): Observer method name that will be called when\n *   the property changes. The arguments of the method are\n *   `(value, previousValue)`.\n * - `computed` (string): String describing method and dependent properties\n *   for computing the value of this property (e.g. `'computeFoo(bar, zot)'`).\n *   Computed properties are read-only by default and can only be changed\n *   via the return value of the computing method.\n *\n * `observers`: Array of strings describing multi-property observer methods\n *  and their dependent properties (e.g. `'observeABC(a, b, c)'`).\n *\n * `listeners`: Object describing event listeners to be added to each\n *  instance of this element (key: event name, value: method name).\n *\n * `behaviors`: Array of additional `info` objects containing metadata\n * and callbacks in the same format as the `info` object here which are\n * merged into this element.\n *\n * `hostAttributes`: Object listing attributes to be applied to the host\n *  once created (key: attribute name, value: attribute value).  Values\n *  are serialized based on the type of the value.  Host attributes should\n *  generally be limited to attributes such as `tabIndex` and `aria-...`.\n *  Attributes in `hostAttributes` are only applied if a user-supplied\n *  attribute is not already present (attributes in markup override\n *  `hostAttributes`).\n *\n * In addition, the following Polymer-specific callbacks may be provided:\n * - `registered`: called after first instance of this element,\n * - `created`: called during `constructor`\n * - `attached`: called during `connectedCallback`\n * - `detached`: called during `disconnectedCallback`\n * - `ready`: called before first `attached`, after all properties of\n *   this element have been propagated to its template and all observers\n *   have run\n *\n * @returns Generated class\n */\ndeclare function Class<T>(info: PolymerInit, mixin?: (p0: T) => T): {new(): HTMLElement};\n\nimport {PolymerInit} from '../../interfaces';\n"
  },
  {
    "path": "lib/legacy/class.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\nimport { LegacyElementMixin } from './legacy-element-mixin.js';\nimport { legacyOptimizations } from '../utils/settings.js';\n\nconst lifecycleProps = {\n  attached: true,\n  detached: true,\n  ready: true,\n  created: true,\n  beforeRegister: true,\n  registered: true,\n  attributeChanged: true,\n  listeners: true,\n  hostAttributes: true\n};\n\nconst excludeOnInfo = {\n  attached: true,\n  detached: true,\n  ready: true,\n  created: true,\n  beforeRegister: true,\n  registered: true,\n  attributeChanged: true,\n  behaviors: true,\n  _noAccessors: true\n};\n\nconst excludeOnBehaviors = Object.assign({\n  listeners: true,\n  hostAttributes: true,\n  properties: true,\n  observers: true,\n}, excludeOnInfo);\n\nfunction copyProperties(source, target, excludeProps) {\n  const noAccessors = source._noAccessors;\n  const propertyNames = Object.getOwnPropertyNames(source);\n  for (let i = 0; i < propertyNames.length; i++) {\n    let p = propertyNames[i];\n    if (p in excludeProps) {\n      continue;\n    }\n    if (noAccessors) {\n      target[p] = source[p];\n    } else {\n      let pd = Object.getOwnPropertyDescriptor(source, p);\n      if (pd) {\n        // ensure property is configurable so that a later behavior can\n        // re-configure it.\n        pd.configurable = true;\n        Object.defineProperty(target, p, pd);\n      }\n    }\n  }\n}\n\n/**\n * Applies a \"legacy\" behavior or array of behaviors to the provided class.\n *\n * Note: this method will automatically also apply the `LegacyElementMixin`\n * to ensure that any legacy behaviors can rely on legacy Polymer API on\n * the underlying element.\n *\n * @function\n * @template T\n * @param {!Object|!Array<!Object>} behaviors Behavior object or array of behaviors.\n * @param {function(new:T)} klass Element class.\n * @return {?} Returns a new Element class extended by the\n * passed in `behaviors` and also by `LegacyElementMixin`.\n * @suppress {invalidCasts, checkTypes}\n */\nexport function mixinBehaviors(behaviors, klass) {\n  return GenerateClassFromInfo({}, LegacyElementMixin(klass), behaviors);\n}\n\n// NOTE:\n// 1.x\n// Behaviors were mixed in *in reverse order* and de-duped on the fly.\n// The rule was that behavior properties were copied onto the element\n// prototype if and only if the property did not already exist.\n// Given: Polymer{ behaviors: [A, B, C, A, B]}, property copy order was:\n// (1), B, (2), A, (3) C. This means prototype properties win over\n// B properties win over A win over C. This mirrors what would happen\n// with inheritance if element extended B extended A extended C.\n//\n// Again given, Polymer{ behaviors: [A, B, C, A, B]}, the resulting\n// `behaviors` array was [C, A, B].\n// Behavior lifecycle methods were called in behavior array order\n// followed by the element, e.g. (1) C.created, (2) A.created,\n// (3) B.created, (4) element.created. There was no support for\n// super, and \"super-behavior\" methods were callable only by name).\n//\n// 2.x\n// Behaviors are made into proper mixins which live in the\n// element's prototype chain. Behaviors are placed in the element prototype\n// eldest to youngest and de-duped youngest to oldest:\n// So, first [A, B, C, A, B] becomes [C, A, B] then,\n// the element prototype becomes (oldest) (1) PolymerElement, (2) class(C),\n// (3) class(A), (4) class(B), (5) class(Polymer({...})).\n// Result:\n// This means element properties win over B properties win over A win\n// over C. (same as 1.x)\n// If lifecycle is called (super then me), order is\n// (1) C.created, (2) A.created, (3) B.created, (4) element.created\n// (again same as 1.x)\nfunction applyBehaviors(proto, behaviors, lifecycle) {\n  for (let i=0; i<behaviors.length; i++) {\n    applyInfo(proto, behaviors[i], lifecycle, excludeOnBehaviors);\n  }\n}\n\nfunction applyInfo(proto, info, lifecycle, excludeProps) {\n  copyProperties(info, proto, excludeProps);\n  for (let p in lifecycleProps) {\n    if (info[p]) {\n      lifecycle[p] = lifecycle[p] || [];\n      lifecycle[p].push(info[p]);\n    }\n  }\n}\n\n/**\n * @param {Array} behaviors List of behaviors to flatten.\n * @param {Array=} list Target list to flatten behaviors into.\n * @param {Array=} exclude List of behaviors to exclude from the list.\n * @return {!Array} Returns the list of flattened behaviors.\n */\nfunction flattenBehaviors(behaviors, list, exclude) {\n  list = list || [];\n  for (let i=behaviors.length-1; i >= 0; i--) {\n    let b = behaviors[i];\n    if (b) {\n      if (Array.isArray(b)) {\n        flattenBehaviors(b, list);\n      } else {\n        // dedup\n        if (list.indexOf(b) < 0 && (!exclude || exclude.indexOf(b) < 0)) {\n          list.unshift(b);\n        }\n      }\n    } else {\n      console.warn('behavior is null, check for missing or 404 import');\n    }\n  }\n  return list;\n}\n\n/**\n * Copies property descriptors from source to target, overwriting all fields\n * of any previous descriptor for a property *except* for `value`, which is\n * merged in from the target if it does not exist on the source.\n *\n * @param {*} target Target properties object\n * @param {*} source Source properties object\n */\nfunction mergeProperties(target, source) {\n  for (const p in source) {\n    const targetInfo = target[p];\n    const sourceInfo = source[p];\n    if (!('value' in sourceInfo) && targetInfo && ('value' in targetInfo)) {\n      target[p] = Object.assign({value: targetInfo.value}, sourceInfo);\n    } else {\n      target[p] = sourceInfo;\n    }\n  }\n}\n\nconst LegacyElement = LegacyElementMixin(HTMLElement);\n\n/* Note about construction and extension of legacy classes.\n  [Changed in Q4 2018 to optimize performance.]\n\n  When calling `Polymer` or `mixinBehaviors`, the generated class below is\n  made. The list of behaviors was previously made into one generated class per\n  behavior, but this is no longer the case as behaviors are now called\n  manually. Note, there may *still* be multiple generated classes in the\n  element's prototype chain if extension is used with `mixinBehaviors`.\n\n  The generated class is directly tied to the info object and behaviors\n  used to create it. That list of behaviors is filtered so it's only the\n  behaviors not active on the superclass. In order to call through to the\n  entire list of lifecycle methods, it's important to call `super`.\n\n  The element's `properties` and `observers` are controlled via the finalization\n  mechanism provided by `PropertiesMixin`. `Properties` and `observers` are\n  collected by manually traversing the prototype chain and merging.\n\n  To limit changes, the `_registered` method is called via `_initializeProperties`\n  and not `_finalizeClass`.\n\n*/\n/**\n * @param {!PolymerInit} info Polymer info object\n * @param {function(new:HTMLElement)} Base base class to extend with info object\n * @param {Object=} behaviors behaviors to copy into the element\n * @return {function(new:HTMLElement)} Generated class\n * @suppress {checkTypes}\n * @private\n */\nfunction GenerateClassFromInfo(info, Base, behaviors) {\n\n  // manages behavior and lifecycle processing (filled in after class definition)\n  let behaviorList;\n  const lifecycle = {};\n\n  /** @private */\n  class PolymerGenerated extends Base {\n\n    // explicitly not calling super._finalizeClass\n    /** @nocollapse */\n    static _finalizeClass() {\n      // if calling via a subclass that hasn't been generated, pass through to super\n      if (!this.hasOwnProperty(JSCompiler_renameProperty('generatedFrom', this))) {\n        // TODO(https://github.com/google/closure-compiler/issues/3240):\n        //     Change back to just super.methodCall()\n        Base._finalizeClass.call(this);\n      } else {\n        // interleave properties and observers per behavior and `info`\n        if (behaviorList) {\n          for (let i=0, b; i < behaviorList.length; i++) {\n            b = behaviorList[i];\n            if (b.properties) {\n              this.createProperties(b.properties);\n            }\n            if (b.observers) {\n              this.createObservers(b.observers, b.properties);\n            }\n          }\n        }\n        if (info.properties) {\n          this.createProperties(info.properties);\n        }\n        if (info.observers) {\n          this.createObservers(info.observers, info.properties);\n        }\n        // make sure to prepare the element template\n        this._prepareTemplate();\n      }\n    }\n\n    /** @nocollapse */\n    static get properties() {\n      const properties = {};\n      if (behaviorList) {\n        for (let i=0; i < behaviorList.length; i++) {\n          mergeProperties(properties, behaviorList[i].properties);\n        }\n      }\n      mergeProperties(properties, info.properties);\n      return properties;\n    }\n\n    /** @nocollapse */\n    static get observers() {\n      let observers = [];\n      if (behaviorList) {\n        for (let i=0, b; i < behaviorList.length; i++) {\n          b = behaviorList[i];\n          if (b.observers) {\n            observers = observers.concat(b.observers);\n          }\n        }\n      }\n      if (info.observers) {\n        observers = observers.concat(info.observers);\n      }\n      return observers;\n    }\n\n    /**\n     * @return {void}\n     */\n    created() {\n      super.created();\n      const list = lifecycle.created;\n      if (list) {\n        for (let i=0; i < list.length; i++) {\n          list[i].call(this);\n        }\n      }\n    }\n\n    /**\n     * @return {void}\n     */\n    _registered() {\n      /* NOTE: `beforeRegister` is called here for bc, but the behavior\n        is different than in 1.x. In 1.0, the method was called *after*\n        mixing prototypes together but *before* processing of meta-objects.\n        However, dynamic effects can still be set here and can be done either\n        in `beforeRegister` or `registered`. It is no longer possible to set\n        `is` in `beforeRegister` as you could in 1.x.\n      */\n      // only proceed if the generated class' prototype has not been registered.\n      const generatedProto = PolymerGenerated.prototype;\n      if (!generatedProto.hasOwnProperty(JSCompiler_renameProperty('__hasRegisterFinished', generatedProto))) {\n        generatedProto.__hasRegisterFinished = true;\n        // ensure superclass is registered first.\n        super._registered();\n        // copy properties onto the generated class lazily if we're optimizing,\n        if (legacyOptimizations) {\n          copyPropertiesToProto(generatedProto);\n        }\n        // make sure legacy lifecycle is called on the *element*'s prototype\n        // and not the generated class prototype; if the element has been\n        // extended, these are *not* the same.\n        const proto = Object.getPrototypeOf(this);\n        let list = lifecycle.beforeRegister;\n        if (list) {\n          for (let i=0; i < list.length; i++) {\n            list[i].call(proto);\n          }\n        }\n        list = lifecycle.registered;\n        if (list) {\n          for (let i=0; i < list.length; i++) {\n            list[i].call(proto);\n          }\n        }\n      }\n    }\n\n    /**\n     * @return {void}\n     */\n    _applyListeners() {\n      super._applyListeners();\n      const list = lifecycle.listeners;\n      if (list) {\n        for (let i=0; i < list.length; i++) {\n          const listeners = list[i];\n          if (listeners) {\n            for (let l in listeners) {\n              this._addMethodEventListenerToNode(this, l, listeners[l]);\n            }\n          }\n        }\n      }\n    }\n\n    // note: exception to \"super then me\" rule;\n    // do work before calling super so that super attributes\n    // only apply if not already set.\n    /**\n     * @return {void}\n     */\n    _ensureAttributes() {\n      const list = lifecycle.hostAttributes;\n      if (list) {\n        for (let i=list.length-1; i >= 0; i--) {\n          const hostAttributes = list[i];\n          for (let a in hostAttributes) {\n              this._ensureAttribute(a, hostAttributes[a]);\n            }\n        }\n      }\n      super._ensureAttributes();\n    }\n\n    /**\n     * @return {void}\n     */\n    ready() {\n      super.ready();\n      let list = lifecycle.ready;\n      if (list) {\n        for (let i=0; i < list.length; i++) {\n          list[i].call(this);\n        }\n      }\n    }\n\n    /**\n     * @return {void}\n     */\n    attached() {\n      super.attached();\n      let list = lifecycle.attached;\n      if (list) {\n        for (let i=0; i < list.length; i++) {\n          list[i].call(this);\n        }\n      }\n    }\n\n    /**\n     * @return {void}\n     */\n    detached() {\n      super.detached();\n      let list = lifecycle.detached;\n      if (list) {\n        for (let i=0; i < list.length; i++) {\n          list[i].call(this);\n        }\n      }\n    }\n\n    /**\n     * Implements native Custom Elements `attributeChangedCallback` to\n     * set an attribute value to a property via `_attributeToProperty`.\n     *\n     * @param {string} name Name of attribute that changed\n     * @param {?string} old Old attribute value\n     * @param {?string} value New attribute value\n     * @return {void}\n     */\n    attributeChanged(name, old, value) {\n      super.attributeChanged();\n      let list = lifecycle.attributeChanged;\n      if (list) {\n        for (let i=0; i < list.length; i++) {\n          list[i].call(this, name, old, value);\n        }\n      }\n    }\n  }\n\n  // apply behaviors, note actual copying is done lazily at first instance creation\n  if (behaviors) {\n    // NOTE: ensure the behavior is extending a class with\n    // legacy element api. This is necessary since behaviors expect to be able\n    // to access 1.x legacy api.\n    if (!Array.isArray(behaviors)) {\n      behaviors = [behaviors];\n    }\n    let superBehaviors = Base.prototype.behaviors;\n    // get flattened, deduped list of behaviors *not* already on super class\n    behaviorList = flattenBehaviors(behaviors, null, superBehaviors);\n    PolymerGenerated.prototype.behaviors = superBehaviors ?\n      superBehaviors.concat(behaviors) : behaviorList;\n  }\n\n  const copyPropertiesToProto = (proto) => {\n    if (behaviorList) {\n      applyBehaviors(proto, behaviorList, lifecycle);\n    }\n    applyInfo(proto, info, lifecycle, excludeOnInfo);\n  };\n\n  // copy properties if we're not optimizing\n  if (!legacyOptimizations) {\n    copyPropertiesToProto(PolymerGenerated.prototype);\n  }\n\n  PolymerGenerated.generatedFrom = info;\n\n  return PolymerGenerated;\n}\n\n/**\n * Generates a class that extends `LegacyElement` based on the\n * provided info object.  Metadata objects on the `info` object\n * (`properties`, `observers`, `listeners`, `behaviors`, `is`) are used\n * for Polymer's meta-programming systems, and any functions are copied\n * to the generated class.\n *\n * Valid \"metadata\" values are as follows:\n *\n * `is`: String providing the tag name to register the element under. In\n * addition, if a `dom-module` with the same id exists, the first template\n * in that `dom-module` will be stamped into the shadow root of this element,\n * with support for declarative event listeners (`on-...`), Polymer data\n * bindings (`[[...]]` and `{{...}}`), and id-based node finding into\n * `this.$`.\n *\n * `properties`: Object describing property-related metadata used by Polymer\n * features (key: property names, value: object containing property metadata).\n * Valid keys in per-property metadata include:\n * - `type` (String|Number|Object|Array|...): Used by\n *   `attributeChangedCallback` to determine how string-based attributes\n *   are deserialized to JavaScript property values.\n * - `notify` (boolean): Causes a change in the property to fire a\n *   non-bubbling event called `<property>-changed`. Elements that have\n *   enabled two-way binding to the property use this event to observe changes.\n * - `readOnly` (boolean): Creates a getter for the property, but no setter.\n *   To set a read-only property, use the private setter method\n *   `_setProperty(property, value)`.\n * - `observer` (string): Observer method name that will be called when\n *   the property changes. The arguments of the method are\n *   `(value, previousValue)`.\n * - `computed` (string): String describing method and dependent properties\n *   for computing the value of this property (e.g. `'computeFoo(bar, zot)'`).\n *   Computed properties are read-only by default and can only be changed\n *   via the return value of the computing method.\n *\n * `observers`: Array of strings describing multi-property observer methods\n *  and their dependent properties (e.g. `'observeABC(a, b, c)'`).\n *\n * `listeners`: Object describing event listeners to be added to each\n *  instance of this element (key: event name, value: method name).\n *\n * `behaviors`: Array of additional `info` objects containing metadata\n * and callbacks in the same format as the `info` object here which are\n * merged into this element.\n *\n * `hostAttributes`: Object listing attributes to be applied to the host\n *  once created (key: attribute name, value: attribute value).  Values\n *  are serialized based on the type of the value.  Host attributes should\n *  generally be limited to attributes such as `tabIndex` and `aria-...`.\n *  Attributes in `hostAttributes` are only applied if a user-supplied\n *  attribute is not already present (attributes in markup override\n *  `hostAttributes`).\n *\n * In addition, the following Polymer-specific callbacks may be provided:\n * - `registered`: called after first instance of this element,\n * - `created`: called during `constructor`\n * - `attached`: called during `connectedCallback`\n * - `detached`: called during `disconnectedCallback`\n * - `ready`: called before first `attached`, after all properties of\n *   this element have been propagated to its template and all observers\n *   have run\n *\n * @param {!PolymerInit} info Object containing Polymer metadata and functions\n *   to become class methods.\n * @template T\n * @param {function(T):T} mixin Optional mixin to apply to legacy base class\n *   before extending with Polymer metaprogramming.\n * @return {function(new:HTMLElement)} Generated class\n */\nexport const Class = function(info, mixin) {\n  if (!info) {\n    console.warn('Polymer.Class requires `info` argument');\n  }\n  let klass = mixin ? mixin(LegacyElement) :\n      LegacyElement;\n  klass = GenerateClassFromInfo(info, klass, info.behaviors);\n  // decorate klass with registration info\n  klass.is = klass.prototype.is = info.is;\n  return klass;\n};\n"
  },
  {
    "path": "lib/legacy/legacy-data-mixin.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n// tslint:disable:no-any describes the API as best we are able today\n\nimport {Class} from './class.js';\n\nimport {Polymer} from '../../polymer-legacy.js';\n\nimport {dedupingMixin} from '../utils/mixin.js';\n\nimport {templatize} from '../utils/templatize.js';\n\ndeclare class UndefinedArgumentError extends Error {\n  constructor(message: any, arg: any);\n}\n\nexport {LegacyDataMixin};\n\n\n/**\n * Mixin to selectively add back Polymer 1.x's `undefined` rules\n * governing when observers & computing functions run based\n * on all arguments being defined (reference https://www.polymer-project.org/1.0/docs/devguide/observers#multi-property-observers).\n *\n * When loaded, all legacy elements (defined with `Polymer({...})`)\n * will have the mixin applied. The mixin only restores legacy data handling\n * if `_legacyUndefinedCheck: true` is set on the element's prototype.\n *\n * This mixin is intended for use to help migration from Polymer 1.x to\n * 2.x+ by allowing legacy code to work while identifying observers and\n * computing functions that need undefined checks to work without\n * the mixin in Polymer 2.\n */\ndeclare function LegacyDataMixin<T extends new (...args: any[]) => {}>(base: T): T & LegacyDataMixinConstructor;\n\ninterface LegacyDataMixinConstructor {\n  new(...args: any[]): LegacyDataMixin;\n}\n\nexport {LegacyDataMixinConstructor};\n\ninterface LegacyDataMixin {\n}\n\ndeclare function TemplatizeMixin<T extends new (...args: any[]) => {}>(base: T): T & TemplatizeMixinConstructor;\n\ninterface TemplatizeMixinConstructor {\n  new(...args: any[]): TemplatizeMixin;\n}\n\nexport {TemplatizeMixinConstructor};\n\ninterface TemplatizeMixin {\n}\n\ndeclare class legacyBase extends HTMLElement {\n}\n"
  },
  {
    "path": "lib/legacy/legacy-data-mixin.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\nimport { Polymer } from '../../polymer-legacy.js';\nimport { dedupingMixin } from '../utils/mixin.js';\nimport { templatize } from '../utils/templatize.js';\n\nconst UndefinedArgumentError = class extends Error {\n  constructor(message, arg) {\n    super(message);\n    this.arg = arg;\n    this.name = this.constructor.name;\n    // Affordances for ensuring instanceof works after babel ES5 compilation\n    // TODO(kschaaf): Remove after polymer CLI updates to newer Babel that\n    // sets the constructor/prototype correctly for subclassed builtins\n    this.constructor = UndefinedArgumentError;\n    this.__proto__ = UndefinedArgumentError.prototype;\n  }\n};\n\n/**\n * Wraps effect functions to catch `UndefinedArgumentError`s and warn.\n *\n * @param {Object=} effect Effect metadata object\n * @param {Object=} fnName Name of user function, if known\n * @return {?Object|undefined} Effect metadata object\n */\nfunction wrapEffect(effect, fnName) {\n  if (effect && effect.fn) {\n    const fn = effect.fn;\n    effect.fn = function() {\n      try {\n        fn.apply(this, arguments);\n      } catch (e) {\n        if (e instanceof UndefinedArgumentError) {\n          console.warn(`Argument '${e.arg}'${fnName ?` for method '${fnName}'` : ''} was undefined. Ensure it has a default value, or else ensure the method handles the argument being undefined.`);\n        } else {\n          throw e;\n        }\n      }\n    };\n  }\n  return effect;\n}\n\n/**\n * Mixin to selectively add back Polymer 1.x's `undefined` rules\n * governing when observers & computing functions run based\n * on all arguments being defined (reference https://www.polymer-project.org/1.0/docs/devguide/observers#multi-property-observers).\n *\n * When loaded, all legacy elements (defined with `Polymer({...})`)\n * will have the mixin applied. The mixin only restores legacy data handling\n * if `_legacyUndefinedCheck: true` is set on the element's prototype.\n *\n * This mixin is intended for use to help migration from Polymer 1.x to\n * 2.x+ by allowing legacy code to work while identifying observers and\n * computing functions that need undefined checks to work without\n * the mixin in Polymer 2.\n *\n * @mixinFunction\n * @polymer\n * @summary Mixin to selectively add back Polymer 1.x's `undefined` rules\n * governing when observers & computing functions run.\n */\nexport const LegacyDataMixin = dedupingMixin(superClass => {\n\n  /**\n   * @unrestricted\n   * @private\n   */\n  class LegacyDataMixin extends superClass {\n    /**\n     * Overrides `Polymer.PropertyEffects` to add `undefined` argument\n     * checking to match Polymer 1.x style rules\n     *\n     * @param {!Array<!MethodArg>} args Array of argument metadata\n     * @param {string} path Property/path name that triggered the method effect\n     * @param {Object} props Bag of current property changes\n     * @return {Array<*>} Array of argument values\n     * @private\n     */\n    _marshalArgs(args, path, props) {\n      const vals = super._marshalArgs(args, path, props);\n      // Per legacy data rules, single-property observers (whether in `properties`\n      // and in `observers`) are called regardless of whether their argument is\n      // undefined or not. Multi-property observers must have all arguments defined\n      if (this._legacyUndefinedCheck && vals.length > 1) {\n        for (let i=0; i<vals.length; i++) {\n          if (vals[i] === undefined ||\n              (args[i].wildcard && vals[i].base === undefined)) {\n            // Break out of effect's control flow; will be caught in\n            // wrapped property effect function below\n            const name = args[i].name;\n            throw new UndefinedArgumentError(`Argument '${name}' is undefined.`, name);\n          }\n        }\n      }\n      return vals;\n    }\n\n    /**\n     * Overrides `Polyer.PropertyEffects` to wrap effect functions to\n     * catch `UndefinedArgumentError`s and warn.\n     *\n     * @param {string} property Property that should trigger the effect\n     * @param {string} type Effect type, from this.PROPERTY_EFFECT_TYPES\n     * @param {Object=} effect Effect metadata object\n     * @return {void}\n     * @protected\n     */\n    _addPropertyEffect(property, type, effect) {\n      return super._addPropertyEffect(property, type,\n        wrapEffect(effect, effect && effect.info && effect.info.methodName));\n    }\n\n    /**\n     * Overrides `Polyer.PropertyEffects` to wrap effect functions to\n     * catch `UndefinedArgumentError`s and warn.\n     *\n     * @param {Object} templateInfo Template metadata to add effect to\n     * @param {string} prop Property that should trigger the effect\n     * @param {Object=} effect Effect metadata object\n     * @return {void}\n     * @protected\n     * @nocollapse\n     */\n    static _addTemplatePropertyEffect(templateInfo, prop, effect) {\n      // TODO(https://github.com/google/closure-compiler/issues/3240):\n      //     Change back to just super.methodCall()\n      return superClass._addTemplatePropertyEffect.call(\n          this, templateInfo, prop, wrapEffect(effect));\n    }\n\n  }\n\n  return LegacyDataMixin;\n\n});\n\n// LegacyDataMixin is applied to base class _before_ metaprogramming, to\n// ensure override of _addPropertyEffect et.al. are used by metaprogramming\n// performed in _finalizeClass\nconst Class = Polymer.Class;\nPolymer.Class = (info, mixin) => Class(info,\n  superClass => mixin ?\n    mixin(LegacyDataMixin(superClass)) :\n    LegacyDataMixin(superClass)\n);\n\n// Apply LegacyDataMixin to Templatizer instances as well, and defer\n// runtime switch to the root's host (_methodHost)\n/**\n * @mixinFunction\n * @polymer\n */\nconst TemplatizeMixin =\n  dedupingMixin(superClass => {\n    /**\n     * @constructor\n     * @extends {HTMLElement}\n     */\n    const legacyBase = LegacyDataMixin(superClass);\n    /**\n     * @private\n     */\n    class TemplateLegacy extends legacyBase {\n      get _legacyUndefinedCheck() {\n        return this._methodHost && this._methodHost._legacyUndefinedCheck;\n      }\n    }\n    /** @type {!Polymer_PropertyEffects} */\n    TemplateLegacy.prototype._methodHost;\n    return TemplateLegacy;\n  });\n\nconst existingTemplatizeMixin = templatize.mixin;\ntemplatize.mixin = existingTemplatizeMixin ?\n    (s) => TemplatizeMixin(existingTemplatizeMixin(s)) :\n    TemplatizeMixin;\n\nconsole.info('LegacyDataMixin will be applied to all legacy elements.\\n' +\n              'Set `_legacyUndefinedCheck: true` on element class to enable.');\n"
  },
  {
    "path": "lib/legacy/legacy-element-mixin.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n// tslint:disable:no-any describes the API as best we are able today\n\nimport {ElementMixin} from '../mixins/element-mixin.js';\n\nimport {GestureEventListeners} from '../mixins/gesture-event-listeners.js';\n\nimport {DirMixin} from '../mixins/dir-mixin.js';\n\nimport {dedupingMixin} from '../utils/mixin.js';\n\nimport {dom, matchesSelector} from './polymer.dom.js';\n\nimport {setTouchAction} from '../utils/gestures.js';\n\nimport {Debouncer} from '../utils/debounce.js';\n\nimport {timeOut, microTask} from '../utils/async.js';\n\nimport {get} from '../utils/path.js';\n\nimport {scopeSubtree} from '../utils/scope-subtree.js';\n\nimport {findObservedAttributesGetter} from '../mixins/disable-upgrade-mixin.js';\n\nimport {register} from '../utils/telemetry.js';\n\nexport {LegacyElementMixin};\n\n\n/**\n * Element class mixin that provides Polymer's \"legacy\" API intended to be\n * backward-compatible to the greatest extent possible with the API\n * found on the Polymer 1.x `Polymer.Base` prototype applied to all elements\n * defined using the `Polymer({...})` function.\n */\ndeclare function LegacyElementMixin<T extends new (...args: any[]) => {}>(base: T): T & LegacyElementMixinConstructor & ElementMixinConstructor & PropertyEffectsConstructor & TemplateStampConstructor & PropertyAccessorsConstructor & PropertiesChangedConstructor & PropertiesMixinConstructor & GestureEventListenersConstructor & DirMixinConstructor;\n\nimport {ElementMixinConstructor} from '../mixins/element-mixin.js';\n\nimport {PropertyEffectsConstructor, PropertyEffects} from '../mixins/property-effects.js';\n\nimport {TemplateStampConstructor, TemplateStamp} from '../mixins/template-stamp.js';\n\nimport {PropertyAccessorsConstructor, PropertyAccessors} from '../mixins/property-accessors.js';\n\nimport {PropertiesChangedConstructor, PropertiesChanged} from '../mixins/properties-changed.js';\n\nimport {PropertiesMixinConstructor, PropertiesMixin} from '../mixins/properties-mixin.js';\n\nimport {GestureEventListenersConstructor} from '../mixins/gesture-event-listeners.js';\n\nimport {DirMixinConstructor} from '../mixins/dir-mixin.js';\n\ninterface LegacyElementMixinConstructor {\n  new(...args: any[]): LegacyElementMixin;\n}\n\nexport {LegacyElementMixinConstructor};\n\ninterface LegacyElementMixin extends ElementMixin, PropertyEffects, TemplateStamp, PropertyAccessors, PropertiesChanged, PropertiesMixin, GestureEventListeners, DirMixin {\n  isAttached: boolean;\n  _debouncers: {[key: string]: Function|null}|null;\n  _legacyForceObservedAttributes: boolean|undefined;\n\n  /**\n   * Return the element whose local dom within which this element\n   * is contained. This is a shorthand for\n   * `this.getRootNode().host`.\n   */\n  readonly domHost: Node|null;\n  is: string;\n\n  /**\n   * Overrides the default `Polymer.PropertyEffects` implementation to\n   * add support for installing `hostAttributes` and `listeners`.\n   */\n  ready(): void;\n\n  /**\n   * Overrides the default `Polymer.PropertyEffects` implementation to\n   * add support for class initialization via the `_registered` callback.\n   * This is called only when the first instance of the element is created.\n   */\n  _initializeProperties(): void;\n  _enableProperties(): void;\n\n  /**\n   * Provides an override implementation of `attributeChangedCallback`\n   * which adds the Polymer legacy API's `attributeChanged` method.\n   *\n   * @param name Name of attribute.\n   * @param old Old value of attribute.\n   * @param value Current value of attribute.\n   * @param namespace Attribute namespace.\n   */\n  attributeChangedCallback(name: string, old: string|null, value: string|null, namespace: string|null): void;\n\n  /**\n   * Provides an implementation of `connectedCallback`\n   * which adds Polymer legacy API's `attached` method.\n   */\n  connectedCallback(): void;\n\n  /**\n   * Provides an implementation of `disconnectedCallback`\n   * which adds Polymer legacy API's `detached` method.\n   */\n  disconnectedCallback(): void;\n  _canApplyPropertyDefault(property: any): any;\n\n  /**\n   * Legacy callback called during the `constructor`, for overriding\n   * by the user.\n   */\n  created(): void;\n\n  /**\n   * Sets the value of an attribute.\n   * @param name The name of the attribute to change.\n   * @param value The new attribute value.\n   */\n  setAttribute(name: string, value: string): void;\n\n  /**\n   * Removes an attribute.\n   *\n   * @param name The name of the attribute to remove.\n   */\n  removeAttribute(name: string): void;\n\n  /**\n   * Legacy callback called during `connectedCallback`, for overriding\n   * by the user.\n   */\n  attached(): void;\n\n  /**\n   * Legacy callback called during `disconnectedCallback`, for overriding\n   * by the user.\n   */\n  detached(): void;\n\n  /**\n   * Legacy callback called during `attributeChangedChallback`, for overriding\n   * by the user.\n   *\n   * @param name Name of attribute.\n   * @param old Old value of attribute.\n   * @param value Current value of attribute.\n   */\n  attributeChanged(name: string, old: string|null, value: string|null): void;\n  _takeAttributes(): void;\n\n  /**\n   * Called automatically when an element is initializing.\n   * Users may override this method to perform class registration time\n   * work. The implementation should ensure the work is performed\n   * only once for the class.\n   */\n  _registered(): void;\n\n  /**\n   * Ensures an element has required attributes. Called when the element\n   * is being readied via `ready`. Users should override to set the\n   * element's required attributes. The implementation should be sure\n   * to check and not override existing attributes added by\n   * the user of the element. Typically, setting attributes should be left\n   * to the element user and not done here; reasonable exceptions include\n   * setting aria roles and focusability.\n   */\n  _ensureAttributes(): void;\n\n  /**\n   * Adds element event listeners. Called when the element\n   * is being readied via `ready`. Users should override to\n   * add any required element event listeners.\n   * In performance critical elements, the work done here should be kept\n   * to a minimum since it is done before the element is rendered. In\n   * these elements, consider adding listeners asynchronously so as not to\n   * block render.\n   */\n  _applyListeners(): void;\n\n  /**\n   * Converts a typed JavaScript value to a string.\n   *\n   * Note this method is provided as backward-compatible legacy API\n   * only.  It is not directly called by any Polymer features. To customize\n   * how properties are serialized to attributes for attribute bindings and\n   * `reflectToAttribute: true` properties as well as this method, override\n   * the `_serializeValue` method provided by `Polymer.PropertyAccessors`.\n   *\n   * @param value Value to deserialize\n   * @returns Serialized value\n   */\n  serialize(value: any): string|undefined;\n\n  /**\n   * Converts a string to a typed JavaScript value.\n   *\n   * Note this method is provided as backward-compatible legacy API\n   * only.  It is not directly called by any Polymer features.  To customize\n   * how attributes are deserialized to properties for in\n   * `attributeChangedCallback`, override `_deserializeValue` method\n   * provided by `Polymer.PropertyAccessors`.\n   *\n   * @param value String to deserialize\n   * @param type Type to deserialize the string to\n   * @returns Returns the deserialized value in the `type` given.\n   */\n  deserialize(value: string, type: any): any;\n\n  /**\n   * Serializes a property to its associated attribute.\n   *\n   * Note this method is provided as backward-compatible legacy API\n   * only.  It is not directly called by any Polymer features.\n   *\n   * @param property Property name to reflect.\n   * @param attribute Attribute name to reflect.\n   * @param value Property value to reflect.\n   */\n  reflectPropertyToAttribute(property: string, attribute?: string, value?: any): void;\n\n  /**\n   * Sets a typed value to an HTML attribute on a node.\n   *\n   * Note this method is provided as backward-compatible legacy API\n   * only.  It is not directly called by any Polymer features.\n   *\n   * @param value Value to serialize.\n   * @param attribute Attribute name to serialize to.\n   * @param node Element to set attribute to.\n   */\n  serializeValueToAttribute(value: any, attribute: string, node: Element|null): void;\n\n  /**\n   * Copies own properties (including accessor descriptors) from a source\n   * object to a target object.\n   *\n   * @param prototype Target object to copy properties to.\n   * @param api Source object to copy properties from.\n   * @returns prototype object that was passed as first argument.\n   */\n  extend(prototype: object|null, api: object|null): object|null;\n\n  /**\n   * Copies props from a source object to a target object.\n   *\n   * Note, this method uses a simple `for...in` strategy for enumerating\n   * properties.  To ensure only `ownProperties` are copied from source\n   * to target and that accessor implementations are copied, use `extend`.\n   *\n   * @param target Target object to copy properties to.\n   * @param source Source object to copy properties from.\n   * @returns Target object that was passed as first argument.\n   */\n  mixin(target: object, source: object): object;\n\n  /**\n   * Sets the prototype of an object.\n   *\n   * Note this method is provided as backward-compatible legacy API\n   * only.  It is not directly called by any Polymer features.\n   *\n   * @param object The object on which to set the prototype.\n   * @param prototype The prototype that will be set on the given\n   * `object`.\n   * @returns Returns the given `object` with its prototype set\n   * to the given `prototype` object.\n   */\n  chainObject(object: object|null, prototype: object|null): object|null;\n\n  /**\n   * Calls `importNode` on the `content` of the `template` specified and\n   * returns a document fragment containing the imported content.\n   *\n   * @param template HTML template element to instance.\n   * @returns Document fragment containing the imported\n   *   template content.\n   */\n  instanceTemplate(template: HTMLTemplateElement|null): DocumentFragment;\n\n  /**\n   * Dispatches a custom event with an optional detail value.\n   *\n   * @param type Name of event type.\n   * @param detail Detail value containing event-specific\n   *   payload.\n   * @param options Object specifying options.  These may include:\n   *  `bubbles` (boolean, defaults to `true`),\n   *  `cancelable` (boolean, defaults to false), and\n   *  `node` on which to fire the event (HTMLElement, defaults to `this`).\n   * @returns The new event that was fired.\n   */\n  fire(type: string, detail?: any, options?: {bubbles?: boolean, cancelable?: boolean, composed?: boolean}): Event;\n\n  /**\n   * Convenience method to add an event listener on a given element,\n   * late bound to a named method on this element.\n   *\n   * @param node Element to add event listener to.\n   * @param eventName Name of event to listen for.\n   * @param methodName Name of handler method on `this` to call.\n   */\n  listen(node: EventTarget|null, eventName: string, methodName: string): void;\n\n  /**\n   * Convenience method to remove an event listener from a given element,\n   * late bound to a named method on this element.\n   *\n   * @param node Element to remove event listener from.\n   * @param eventName Name of event to stop listening to.\n   * @param methodName Name of handler method on `this` to not call\n   *      anymore.\n   */\n  unlisten(node: EventTarget|null, eventName: string, methodName: string): void;\n\n  /**\n   * Override scrolling behavior to all direction, one direction, or none.\n   *\n   * Valid scroll directions:\n   *   - 'all': scroll in any direction\n   *   - 'x': scroll only in the 'x' direction\n   *   - 'y': scroll only in the 'y' direction\n   *   - 'none': disable scrolling for this node\n   *\n   * @param direction Direction to allow scrolling\n   * Defaults to `all`.\n   * @param node Element to apply scroll direction setting.\n   * Defaults to `this`.\n   */\n  setScrollDirection(direction?: string, node?: Element|null): void;\n\n  /**\n   * Convenience method to run `querySelector` on this local DOM scope.\n   *\n   * This function calls `Polymer.dom(this.root).querySelector(slctr)`.\n   *\n   * @param slctr Selector to run on this local DOM scope\n   * @returns Element found by the selector, or null if not found.\n   */\n  $$(slctr: string): Element|null;\n\n  /**\n   * Force this element to distribute its children to its local dom.\n   * This should not be necessary as of Polymer 2.0.2 and is provided only\n   * for backwards compatibility.\n   */\n  distributeContent(): void;\n\n  /**\n   * Returns a list of nodes that are the effective childNodes. The effective\n   * childNodes list is the same as the element's childNodes except that\n   * any `<content>` elements are replaced with the list of nodes distributed\n   * to the `<content>`, the result of its `getDistributedNodes` method.\n   *\n   * @returns List of effective child nodes.\n   */\n  getEffectiveChildNodes(): Node[];\n\n  /**\n   * Returns a list of nodes distributed within this element that match\n   * `selector`. These can be dom children or elements distributed to\n   * children that are insertion points.\n   *\n   * @param selector Selector to run.\n   * @returns List of distributed elements that match selector.\n   */\n  queryDistributedElements(selector: string): Node[];\n\n  /**\n   * Returns a list of elements that are the effective children. The effective\n   * children list is the same as the element's children except that\n   * any `<content>` elements are replaced with the list of elements\n   * distributed to the `<content>`.\n   *\n   * @returns List of effective children.\n   */\n  getEffectiveChildren(): Node[];\n\n  /**\n   * Returns a string of text content that is the concatenation of the\n   * text content's of the element's effective childNodes (the elements\n   * returned by <a href=\"#getEffectiveChildNodes>getEffectiveChildNodes</a>.\n   *\n   * @returns List of effective children.\n   */\n  getEffectiveTextContent(): string;\n\n  /**\n   * Returns the first effective childNode within this element that\n   * match `selector`. These can be dom child nodes or elements distributed\n   * to children that are insertion points.\n   *\n   * @param selector Selector to run.\n   * @returns First effective child node that matches selector.\n   */\n  queryEffectiveChildren(selector: string): Node|null;\n\n  /**\n   * Returns a list of effective childNodes within this element that\n   * match `selector`. These can be dom child nodes or elements distributed\n   * to children that are insertion points.\n   *\n   * @param selector Selector to run.\n   * @returns List of effective child nodes that match\n   *     selector.\n   */\n  queryAllEffectiveChildren(selector: string): Node[];\n\n  /**\n   * Returns a list of nodes distributed to this element's `<slot>`.\n   *\n   * If this element contains more than one `<slot>` in its local DOM,\n   * an optional selector may be passed to choose the desired content.\n   *\n   * @param slctr CSS selector to choose the desired\n   *   `<slot>`.  Defaults to `content`.\n   * @returns List of distributed nodes for the `<slot>`.\n   */\n  getContentChildNodes(slctr?: string): Node[];\n\n  /**\n   * Returns a list of element children distributed to this element's\n   * `<slot>`.\n   *\n   * If this element contains more than one `<slot>` in its\n   * local DOM, an optional selector may be passed to choose the desired\n   * content.  This method differs from `getContentChildNodes` in that only\n   * elements are returned.\n   *\n   * @param slctr CSS selector to choose the desired\n   *   `<content>`.  Defaults to `content`.\n   * @returns List of distributed nodes for the\n   *   `<slot>`.\n   */\n  getContentChildren(slctr?: string): HTMLElement[];\n\n  /**\n   * Checks whether an element is in this element's light DOM tree.\n   *\n   * @param node The element to be checked.\n   * @returns true if node is in this element's light DOM tree.\n   */\n  isLightDescendant(node: Node|null): boolean;\n\n  /**\n   * Checks whether an element is in this element's local DOM tree.\n   *\n   * @param node The element to be checked.\n   * @returns true if node is in this element's local DOM tree.\n   */\n  isLocalDescendant(node: Element): boolean;\n\n  /**\n   * No-op for backwards compatibility. This should now be handled by\n   * ShadyCss library.\n   *\n   * @param container Container element to scope\n   * @param shouldObserve if true, start a mutation observer for added nodes to the container\n   * @returns Returns a new MutationObserver on `container` if `shouldObserve` is true.\n   */\n  scopeSubtree(container: Element, shouldObserve?: boolean): MutationObserver|null;\n\n  /**\n   * Returns the computed style value for the given property.\n   *\n   * @param property The css property name.\n   * @returns Returns the computed css property value for the given\n   * `property`.\n   */\n  getComputedStyleValue(property: string): string;\n\n  /**\n   * Call `debounce` to collapse multiple requests for a named task into\n   * one invocation which is made after the wait time has elapsed with\n   * no new request.  If no wait time is given, the callback will be called\n   * at microtask timing (guaranteed before paint).\n   *\n   *     debouncedClickAction(e) {\n   *       // will not call `processClick` more than once per 100ms\n   *       this.debounce('click', function() {\n   *        this.processClick();\n   *       } 100);\n   *     }\n   *\n   * @param jobName String to identify the debounce job.\n   * @param callback Function that is called (with `this`\n   *   context) when the wait time elapses.\n   * @param wait Optional wait time in milliseconds (ms) after the\n   *   last signal that must elapse before invoking `callback`\n   * @returns Returns a debouncer object on which exists the\n   * following methods: `isActive()` returns true if the debouncer is\n   * active; `cancel()` cancels the debouncer if it is active;\n   * `flush()` immediately invokes the debounced callback if the debouncer\n   * is active.\n   */\n  debounce(jobName: string, callback: () => void, wait?: number): object;\n\n  /**\n   * Returns whether a named debouncer is active.\n   *\n   * @param jobName The name of the debouncer started with `debounce`\n   * @returns Whether the debouncer is active (has not yet fired).\n   */\n  isDebouncerActive(jobName: string): boolean;\n\n  /**\n   * Immediately calls the debouncer `callback` and inactivates it.\n   *\n   * @param jobName The name of the debouncer started with `debounce`\n   */\n  flushDebouncer(jobName: string): void;\n\n  /**\n   * Cancels an active debouncer.  The `callback` will not be called.\n   *\n   * @param jobName The name of the debouncer started with `debounce`\n   */\n  cancelDebouncer(jobName: string): void;\n\n  /**\n   * Runs a callback function asynchronously.\n   *\n   * By default (if no waitTime is specified), async callbacks are run at\n   * microtask timing, which will occur before paint.\n   *\n   * @param callback The callback function to run, bound to\n   *     `this`.\n   * @param waitTime Time to wait before calling the\n   *   `callback`.  If unspecified or 0, the callback will be run at microtask\n   *   timing (before paint).\n   * @returns Handle that may be used to cancel the async job.\n   */\n  async(callback: Function, waitTime?: number): number;\n\n  /**\n   * Cancels an async operation started with `async`.\n   *\n   * @param handle Handle returned from original `async` call to\n   *   cancel.\n   */\n  cancelAsync(handle: number): void;\n\n  /**\n   * Convenience method for creating an element and configuring it.\n   *\n   * @param tag HTML element tag to create.\n   * @param props Object of properties to configure on the\n   *    instance.\n   * @returns Newly created and configured element.\n   */\n  create(tag: string, props?: object|null): Element;\n\n  /**\n   * Polyfill for Element.prototype.matches, which is sometimes still\n   * prefixed.\n   *\n   * @param selector Selector to test.\n   * @param node Element to test the selector against.\n   * @returns Whether the element matches the selector.\n   */\n  elementMatches(selector: string, node?: Element): boolean;\n\n  /**\n   * Toggles an HTML attribute on or off.\n   *\n   * @param name HTML attribute name\n   * @param bool Boolean to force the attribute on or off.\n   *    When unspecified, the state of the attribute will be reversed.\n   * @returns true if the attribute now exists\n   */\n  toggleAttribute(name: string, bool?: boolean): boolean;\n\n  /**\n   * Toggles a CSS class on or off.\n   *\n   * @param name CSS class name\n   * @param bool Boolean to force the class on or off.\n   *    When unspecified, the state of the class will be reversed.\n   * @param node Node to target.  Defaults to `this`.\n   */\n  toggleClass(name: string, bool?: boolean, node?: Element|null): void;\n\n  /**\n   * Cross-platform helper for setting an element's CSS `transform` property.\n   *\n   * @param transformText Transform setting.\n   * @param node Element to apply the transform to.\n   * Defaults to `this`\n   */\n  transform(transformText: string, node?: Element|null): void;\n\n  /**\n   * Cross-platform helper for setting an element's CSS `translate3d`\n   * property.\n   *\n   * @param x X offset.\n   * @param y Y offset.\n   * @param z Z offset.\n   * @param node Element to apply the transform to.\n   * Defaults to `this`.\n   */\n  translate3d(x: number|string, y: number|string, z: number|string, node?: Element|null): void;\n\n  /**\n   * Removes an item from an array, if it exists.\n   *\n   * If the array is specified by path, a change notification is\n   * generated, so that observers, data bindings and computed\n   * properties watching that path can update.\n   *\n   * If the array is passed directly, **no change\n   * notification is generated**.\n   *\n   * @param arrayOrPath Path to array from\n   *     which to remove the item\n   *   (or the array itself).\n   * @param item Item to remove.\n   * @returns Array containing item removed.\n   */\n  arrayDelete(arrayOrPath: string|Array<number|string>, item: any): any[]|null;\n\n  /**\n   * Facades `console.log`/`warn`/`error` as override point.\n   *\n   * @param level One of 'log', 'warn', 'error'\n   * @param args Array of strings or objects to log\n   */\n  _logger(level: string, args: any[]|null): void;\n\n  /**\n   * Facades `console.log` as an override point.\n   *\n   * @param args Array of strings or objects to log\n   */\n  _log(...args: any[]): void;\n\n  /**\n   * Facades `console.warn` as an override point.\n   *\n   * @param args Array of strings or objects to log\n   */\n  _warn(...args: any[]): void;\n\n  /**\n   * Facades `console.error` as an override point.\n   *\n   * @param args Array of strings or objects to log\n   */\n  _error(...args: any[]): void;\n\n  /**\n   * Formats a message using the element type an a method name.\n   *\n   * @param methodName Method name to associate with message\n   * @param args Array of strings or objects to log\n   * @returns Array with formatting information for `console`\n   *   logging.\n   */\n  _logf(methodName: string, ...args: any[]): any[];\n}\n"
  },
  {
    "path": "lib/legacy/legacy-element-mixin.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport '@webcomponents/shadycss/entrypoints/apply-shim.js';\nimport { ElementMixin, builtCSS } from '../mixins/element-mixin.js';\nimport { GestureEventListeners } from '../mixins/gesture-event-listeners.js';\nimport { DirMixin } from '../mixins/dir-mixin.js';\nimport { dedupingMixin } from '../utils/mixin.js';\nimport '../utils/render-status.js';\nimport '../utils/unresolved.js';\nimport { dom, matchesSelector } from './polymer.dom.js';\nimport { setTouchAction } from '../utils/gestures.js';\nimport { Debouncer } from '../utils/debounce.js';\nimport { timeOut, microTask } from '../utils/async.js';\nimport { get } from '../utils/path.js';\nimport { wrap } from '../utils/wrap.js';\nimport { scopeSubtree } from '../utils/scope-subtree.js';\nimport { legacyOptimizations, legacyNoObservedAttributes } from '../utils/settings.js';\nimport { findObservedAttributesGetter } from '../mixins/disable-upgrade-mixin.js';\nimport { register } from '../utils/telemetry.js';\n\nconst DISABLED_ATTR = 'disable-upgrade';\n\nlet styleInterface = window.ShadyCSS;\n\n/**\n * Element class mixin that provides Polymer's \"legacy\" API intended to be\n * backward-compatible to the greatest extent possible with the API\n * found on the Polymer 1.x `Polymer.Base` prototype applied to all elements\n * defined using the `Polymer({...})` function.\n *\n * @mixinFunction\n * @polymer\n * @appliesMixin ElementMixin\n * @appliesMixin GestureEventListeners\n * @appliesMixin DirMixin\n * @property isAttached {boolean} Set to `true` in this element's\n *   `connectedCallback` and `false` in `disconnectedCallback`\n * @summary Element class mixin that provides Polymer's \"legacy\" API\n */\nexport const LegacyElementMixin = dedupingMixin((base) => {\n\n  // TODO(kschaaf): Note, the `@implements {Polymer_DirMixin}` is required here\n  // (rather than on legacyElementBase) for unknown reasons.\n  /**\n   * @constructor\n   * @implements {Polymer_ElementMixin}\n   * @implements {Polymer_GestureEventListeners}\n   * @implements {Polymer_DirMixin}\n   * @extends {HTMLElement}\n   * @private\n   */\n  const GesturesElement = GestureEventListeners(ElementMixin(base));\n\n  // Note, the DirMixin does nothing if css is built so avoid including it\n  // in that case.\n\n  /**\n   * @constructor\n   * @extends {GesturesElement}\n   * @private\n   */\n  const legacyElementBase = builtCSS ? GesturesElement :\n    DirMixin(GesturesElement);\n\n  const observedAttributesGetter = findObservedAttributesGetter(legacyElementBase);\n\n  /**\n   * Map of simple names to touch action names\n   * @dict\n   */\n  const DIRECTION_MAP = {\n    'x': 'pan-x',\n    'y': 'pan-y',\n    'none': 'none',\n    'all': 'auto'\n  };\n\n  /**\n   * @polymer\n   * @mixinClass\n   * @extends {legacyElementBase}\n   * @implements {Polymer_LegacyElementMixin}\n   * @unrestricted\n   */\n  class LegacyElement extends legacyElementBase {\n\n    constructor() {\n      super();\n      /** @type {boolean} */\n      this.isAttached;\n      /** @type {?WeakMap<!Element, !Object<string, !Function>>} */\n      this.__boundListeners;\n      /** @type {?Object<string, ?Function>} */\n      this._debouncers;\n      // NOTE: Inlined for perf from version of DisableUpgradeMixin.\n      /** @type {boolean|undefined} */\n      this.__isUpgradeDisabled;\n      /** @type {boolean|undefined} */\n      this.__needsAttributesAtConnected;\n      /** @type {boolean|undefined} */\n      this._legacyForceObservedAttributes;\n    }\n\n    /**\n     * Forwards `importMeta` from the prototype (i.e. from the info object\n     * passed to `Polymer({...})`) to the static API.\n     *\n     * @return {!Object} The `import.meta` object set on the prototype\n     * @suppress {missingProperties} `this` is always in the instance in\n     *  closure for some reason even in a static method, rather than the class\n     * @nocollapse\n     */\n    static get importMeta() {\n      return this.prototype.importMeta;\n    }\n\n    /**\n     * Legacy callback called during the `constructor`, for overriding\n     * by the user.\n     * @override\n     * @return {void}\n     */\n    created() {}\n\n    /**\n     * Processes an attribute reaction when the `legacyNoObservedAttributes`\n     * setting is in use.\n     * @param {string} name Name of attribute that changed\n     * @param {?string} old Old attribute value\n     * @param {?string} value New attribute value\n     * @return {void}\n     */\n    __attributeReaction(name, old, value) {\n      if ((this.__dataAttributes && this.__dataAttributes[name]) || name === DISABLED_ATTR) {\n        this.attributeChangedCallback(name, old, value, null);\n      }\n    }\n\n    /**\n     * Sets the value of an attribute.\n     * @override\n     */\n    setAttribute(name, value) {\n      if (legacyNoObservedAttributes && !this._legacyForceObservedAttributes) {\n        const oldValue = this.getAttribute(name);\n        super.setAttribute(name, value);\n        // value coerced to String for closure's benefit\n        this.__attributeReaction(name, oldValue, String(value));\n      } else {\n        super.setAttribute(name, value);\n      }\n    }\n\n    /**\n     * Removes an attribute.\n     * @override\n     */\n    removeAttribute(name) {\n      if (legacyNoObservedAttributes && !this._legacyForceObservedAttributes) {\n        const oldValue = this.getAttribute(name);\n        super.removeAttribute(name);\n        this.__attributeReaction(name, oldValue, null);\n      } else {\n        super.removeAttribute(name);\n      }\n    }\n\n    // NOTE: Inlined for perf from version of DisableUpgradeMixin.\n    static get observedAttributes() {\n      if (legacyNoObservedAttributes && !this.prototype._legacyForceObservedAttributes) {\n        // Ensure this element is property registered with the telemetry system.\n        if (!this.hasOwnProperty(JSCompiler_renameProperty('__observedAttributes', this))) {\n          this.__observedAttributes = [];\n          register(this.prototype);\n        }\n        return this.__observedAttributes;\n      } else {\n        return observedAttributesGetter.call(this).concat(DISABLED_ATTR);\n      }\n    }\n\n    // NOTE: Inlined for perf from version of DisableUpgradeMixin.\n    // Prevent element from enabling properties when it's upgrade disabled.\n    // Normally overriding connectedCallback would be enough, but dom-* elements\n    /** @override */\n    _enableProperties() {\n      if (!this.__isUpgradeDisabled) {\n        super._enableProperties();\n      }\n    }\n\n    // NOTE: Inlined for perf from version of DisableUpgradeMixin.\n    // If the element starts upgrade-disabled and a property is set for\n    // which an accessor exists, the default should not be applied.\n    // This additional check is needed because defaults are applied via\n    // `_initializeProperties` which is called after initial properties\n    // have been set when the element starts upgrade-disabled.\n    /** @override */\n    _canApplyPropertyDefault(property) {\n      return super._canApplyPropertyDefault(property) &&\n        !(this.__isUpgradeDisabled && this._isPropertyPending(property));\n    }\n\n    /**\n     * Provides an implementation of `connectedCallback`\n     * which adds Polymer legacy API's `attached` method.\n     * @return {void}\n     * @override\n     */\n    connectedCallback() {\n      if (this.__needsAttributesAtConnected) {\n        this._takeAttributes();\n      }\n      // NOTE: Inlined for perf from version of DisableUpgradeMixin.\n      if (!this.__isUpgradeDisabled) {\n        super.connectedCallback();\n        this.isAttached = true;\n        this.attached();\n      }\n    }\n\n    /**\n     * Legacy callback called during `connectedCallback`, for overriding\n     * by the user.\n     * @override\n     * @return {void}\n     */\n    attached() {}\n\n    /**\n     * Provides an implementation of `disconnectedCallback`\n     * which adds Polymer legacy API's `detached` method.\n     * @return {void}\n     * @override\n     */\n    disconnectedCallback() {\n      // NOTE: Inlined for perf from version of DisableUpgradeMixin.\n      if (!this.__isUpgradeDisabled) {\n        super.disconnectedCallback();\n        this.isAttached = false;\n        this.detached();\n      }\n    }\n\n    /**\n     * Legacy callback called during `disconnectedCallback`, for overriding\n     * by the user.\n     * @override\n     * @return {void}\n     */\n    detached() {}\n\n    /**\n     * Provides an override implementation of `attributeChangedCallback`\n     * which adds the Polymer legacy API's `attributeChanged` method.\n     * @param {string} name Name of attribute.\n     * @param {?string} old Old value of attribute.\n     * @param {?string} value Current value of attribute.\n     * @param {?string} namespace Attribute namespace.\n     * @return {void}\n     * @override\n     */\n    attributeChangedCallback(name, old, value, namespace) {\n      if (old !== value) {\n        // NOTE: Inlined for perf from version of DisableUpgradeMixin.\n        if (name == DISABLED_ATTR) {\n          // When disable-upgrade is removed, intialize properties and\n          // provoke connectedCallback if the element is already connected.\n          if (this.__isUpgradeDisabled && value == null) {\n            this._initializeProperties();\n            this.__isUpgradeDisabled = false;\n            if (wrap(this).isConnected) {\n              this.connectedCallback();\n            }\n          }\n        } else {\n          super.attributeChangedCallback(name, old, value, namespace);\n          this.attributeChanged(name, old, value);\n        }\n      }\n    }\n\n    /**\n     * Legacy callback called during `attributeChangedChallback`, for overriding\n     * by the user.\n     * @param {string} name Name of attribute.\n     * @param {?string} old Old value of attribute.\n     * @param {?string} value Current value of attribute.\n     * @return {void}\n     * @override\n     */\n    attributeChanged(name, old, value) {} // eslint-disable-line no-unused-vars\n\n    /**\n     * Overrides the default `Polymer.PropertyEffects` implementation to\n     * add support for class initialization via the `_registered` callback.\n     * This is called only when the first instance of the element is created.\n     *\n     * @return {void}\n     * @override\n     * @suppress {invalidCasts}\n     */\n    _initializeProperties() {\n      // NOTE: Inlined for perf from version of DisableUpgradeMixin.\n      // Only auto-use disable-upgrade if legacyOptimizations is set.\n      if (legacyOptimizations && this.hasAttribute(DISABLED_ATTR)) {\n        this.__isUpgradeDisabled = true;\n      } else {\n        let proto = Object.getPrototypeOf(this);\n        if (!proto.hasOwnProperty(JSCompiler_renameProperty('__hasRegisterFinished', proto))) {\n          this._registered();\n          // backstop in case the `_registered` implementation does not set this\n          proto.__hasRegisterFinished = true;\n        }\n        super._initializeProperties();\n        this.root = /** @type {HTMLElement} */(this);\n        this.created();\n        // Pull all attribute values 1x if `legacyNoObservedAttributes` is set.\n        if (legacyNoObservedAttributes && !this._legacyForceObservedAttributes) {\n          if (this.hasAttributes()) {\n            this._takeAttributes();\n          // Element created from scratch or parser generated\n          } else if (!this.parentNode) {\n            this.__needsAttributesAtConnected = true;\n          }\n        }\n        // Ensure listeners are applied immediately so that they are\n        // added before declarative event listeners. This allows an element to\n        // decorate itself via an event prior to any declarative listeners\n        // seeing the event. Note, this ensures compatibility with 1.x ordering.\n        this._applyListeners();\n      }\n    }\n\n    _takeAttributes() {\n      const a = this.attributes;\n      for (let i=0, l=a.length; i < l; i++) {\n        const attr = a[i];\n        this.__attributeReaction(attr.name, null, attr.value);\n      }\n    }\n\n    /**\n     * Called automatically when an element is initializing.\n     * Users may override this method to perform class registration time\n     * work. The implementation should ensure the work is performed\n     * only once for the class.\n     * @protected\n     * @return {void}\n     * @override\n     */\n    _registered() {}\n\n    /**\n     * Overrides the default `Polymer.PropertyEffects` implementation to\n     * add support for installing `hostAttributes` and `listeners`.\n     *\n     * @return {void}\n     * @override\n     */\n    ready() {\n      this._ensureAttributes();\n      super.ready();\n    }\n\n    /**\n     * Ensures an element has required attributes. Called when the element\n     * is being readied via `ready`. Users should override to set the\n     * element's required attributes. The implementation should be sure\n     * to check and not override existing attributes added by\n     * the user of the element. Typically, setting attributes should be left\n     * to the element user and not done here; reasonable exceptions include\n     * setting aria roles and focusability.\n     * @protected\n     * @return {void}\n     * @override\n     */\n    _ensureAttributes() {}\n\n    /**\n     * Adds element event listeners. Called when the element\n     * is being readied via `ready`. Users should override to\n     * add any required element event listeners.\n     * In performance critical elements, the work done here should be kept\n     * to a minimum since it is done before the element is rendered. In\n     * these elements, consider adding listeners asynchronously so as not to\n     * block render.\n     * @protected\n     * @return {void}\n     * @override\n     */\n    _applyListeners() {}\n\n    /**\n     * Converts a typed JavaScript value to a string.\n     *\n     * Note this method is provided as backward-compatible legacy API\n     * only.  It is not directly called by any Polymer features. To customize\n     * how properties are serialized to attributes for attribute bindings and\n     * `reflectToAttribute: true` properties as well as this method, override\n     * the `_serializeValue` method provided by `Polymer.PropertyAccessors`.\n     *\n     * @param {*} value Value to deserialize\n     * @return {string | undefined} Serialized value\n     * @override\n     */\n    serialize(value) {\n      return this._serializeValue(value);\n    }\n\n    /**\n     * Converts a string to a typed JavaScript value.\n     *\n     * Note this method is provided as backward-compatible legacy API\n     * only.  It is not directly called by any Polymer features.  To customize\n     * how attributes are deserialized to properties for in\n     * `attributeChangedCallback`, override `_deserializeValue` method\n     * provided by `Polymer.PropertyAccessors`.\n     *\n     * @param {string} value String to deserialize\n     * @param {*} type Type to deserialize the string to\n     * @return {*} Returns the deserialized value in the `type` given.\n     * @override\n     */\n    deserialize(value, type) {\n      return this._deserializeValue(value, type);\n    }\n\n    /**\n     * Serializes a property to its associated attribute.\n     *\n     * Note this method is provided as backward-compatible legacy API\n     * only.  It is not directly called by any Polymer features.\n     *\n     * @param {string} property Property name to reflect.\n     * @param {string=} attribute Attribute name to reflect.\n     * @param {*=} value Property value to reflect.\n     * @return {void}\n     * @override\n     */\n    reflectPropertyToAttribute(property, attribute, value) {\n      this._propertyToAttribute(property, attribute, value);\n    }\n\n    /**\n     * Sets a typed value to an HTML attribute on a node.\n     *\n     * Note this method is provided as backward-compatible legacy API\n     * only.  It is not directly called by any Polymer features.\n     *\n     * @param {*} value Value to serialize.\n     * @param {string} attribute Attribute name to serialize to.\n     * @param {Element} node Element to set attribute to.\n     * @return {void}\n     * @override\n     */\n    serializeValueToAttribute(value, attribute, node) {\n      this._valueToNodeAttribute(/** @type {Element} */ (node || this), value, attribute);\n    }\n\n    /**\n     * Copies own properties (including accessor descriptors) from a source\n     * object to a target object.\n     *\n     * @param {Object} prototype Target object to copy properties to.\n     * @param {Object} api Source object to copy properties from.\n     * @return {Object} prototype object that was passed as first argument.\n     * @override\n     */\n    extend(prototype, api) {\n      if (!(prototype && api)) {\n        return prototype || api;\n      }\n      let n$ = Object.getOwnPropertyNames(api);\n      for (let i=0, n; (i<n$.length) && (n=n$[i]); i++) {\n        let pd = Object.getOwnPropertyDescriptor(api, n);\n        if (pd) {\n          Object.defineProperty(prototype, n, pd);\n        }\n      }\n      return prototype;\n    }\n\n    /**\n     * Copies props from a source object to a target object.\n     *\n     * Note, this method uses a simple `for...in` strategy for enumerating\n     * properties.  To ensure only `ownProperties` are copied from source\n     * to target and that accessor implementations are copied, use `extend`.\n     *\n     * @param {!Object} target Target object to copy properties to.\n     * @param {!Object} source Source object to copy properties from.\n     * @return {!Object} Target object that was passed as first argument.\n     * @override\n     */\n    mixin(target, source) {\n      for (let i in source) {\n        target[i] = source[i];\n      }\n      return target;\n    }\n\n    /**\n     * Sets the prototype of an object.\n     *\n     * Note this method is provided as backward-compatible legacy API\n     * only.  It is not directly called by any Polymer features.\n     * @param {Object} object The object on which to set the prototype.\n     * @param {Object} prototype The prototype that will be set on the given\n     * `object`.\n     * @return {Object} Returns the given `object` with its prototype set\n     * to the given `prototype` object.\n     * @override\n     */\n    chainObject(object, prototype) {\n      if (object && prototype && object !== prototype) {\n        object.__proto__ = prototype;\n      }\n      return object;\n    }\n\n    /* **** Begin Template **** */\n\n    /**\n     * Calls `importNode` on the `content` of the `template` specified and\n     * returns a document fragment containing the imported content.\n     *\n     * @param {HTMLTemplateElement} template HTML template element to instance.\n     * @return {!DocumentFragment} Document fragment containing the imported\n     *   template content.\n     * @override\n     * @suppress {missingProperties} go/missingfnprops\n     */\n    instanceTemplate(template) {\n      let content = this.constructor._contentForTemplate(template);\n      let dom = /** @type {!DocumentFragment} */\n        (document.importNode(content, true));\n      return dom;\n    }\n\n    /* **** Begin Events **** */\n\n\n\n    /**\n     * Dispatches a custom event with an optional detail value.\n     *\n     * @param {string} type Name of event type.\n     * @param {*=} detail Detail value containing event-specific\n     *   payload.\n     * @param {{ bubbles: (boolean|undefined), cancelable: (boolean|undefined),\n     *     composed: (boolean|undefined) }=}\n     *  options Object specifying options.  These may include:\n     *  `bubbles` (boolean, defaults to `true`),\n     *  `cancelable` (boolean, defaults to false), and\n     *  `node` on which to fire the event (HTMLElement, defaults to `this`).\n     * @return {!Event} The new event that was fired.\n     * @override\n     */\n    fire(type, detail, options) {\n      options = options || {};\n      detail = (detail === null || detail === undefined) ? {} : detail;\n      let event = new Event(type, {\n        bubbles: options.bubbles === undefined ? true : options.bubbles,\n        cancelable: Boolean(options.cancelable),\n        composed: options.composed === undefined ? true: options.composed\n      });\n      event.detail = detail;\n      let node = options.node || this;\n      wrap(node).dispatchEvent(event);\n      return event;\n    }\n\n    /**\n     * Convenience method to add an event listener on a given element,\n     * late bound to a named method on this element.\n     *\n     * @param {?EventTarget} node Element to add event listener to.\n     * @param {string} eventName Name of event to listen for.\n     * @param {string} methodName Name of handler method on `this` to call.\n     * @return {void}\n     * @override\n     */\n    listen(node, eventName, methodName) {\n      node = /** @type {!EventTarget} */ (node || this);\n      let hbl = this.__boundListeners ||\n        (this.__boundListeners = new WeakMap());\n      let bl = hbl.get(node);\n      if (!bl) {\n        bl = {};\n        hbl.set(node, bl);\n      }\n      let key = eventName + methodName;\n      if (!bl[key]) {\n        bl[key] = this._addMethodEventListenerToNode(\n            /** @type {!Node} */ (node), eventName, methodName, this);\n      }\n    }\n\n    /**\n     * Convenience method to remove an event listener from a given element,\n     * late bound to a named method on this element.\n     *\n     * @param {?EventTarget} node Element to remove event listener from.\n     * @param {string} eventName Name of event to stop listening to.\n     * @param {string} methodName Name of handler method on `this` to not call\n     anymore.\n     * @return {void}\n     * @override\n     */\n    unlisten(node, eventName, methodName) {\n      node = /** @type {!EventTarget} */ (node || this);\n      let bl = this.__boundListeners &&\n          this.__boundListeners.get(/** @type {!Element} */ (node));\n      let key = eventName + methodName;\n      let handler = bl && bl[key];\n      if (handler) {\n        this._removeEventListenerFromNode(\n            /** @type {!Node} */ (node), eventName, handler);\n        bl[key] = /** @type {?} */ (null);\n      }\n    }\n\n    /**\n     * Override scrolling behavior to all direction, one direction, or none.\n     *\n     * Valid scroll directions:\n     *   - 'all': scroll in any direction\n     *   - 'x': scroll only in the 'x' direction\n     *   - 'y': scroll only in the 'y' direction\n     *   - 'none': disable scrolling for this node\n     *\n     * @param {string=} direction Direction to allow scrolling\n     * Defaults to `all`.\n     * @param {Element=} node Element to apply scroll direction setting.\n     * Defaults to `this`.\n     * @return {void}\n     * @override\n     */\n    setScrollDirection(direction, node) {\n      setTouchAction(\n          /** @type {!Element} */ (node || this),\n          DIRECTION_MAP[direction] || 'auto');\n    }\n    /* **** End Events **** */\n\n    /**\n     * Convenience method to run `querySelector` on this local DOM scope.\n     *\n     * This function calls `Polymer.dom(this.root).querySelector(slctr)`.\n     *\n     * @param {string} slctr Selector to run on this local DOM scope\n     * @return {Element} Element found by the selector, or null if not found.\n     * @override\n     */\n    $$(slctr) {\n      // Note, no need to `wrap` this because root is always patched\n      return this.root.querySelector(slctr);\n    }\n\n    /**\n     * Return the element whose local dom within which this element\n     * is contained. This is a shorthand for\n     * `this.getRootNode().host`.\n     * @this {Element}\n     * @return {?Node} The element whose local dom within which this element is\n     * contained.\n     * @override\n     */\n    get domHost() {\n      let root = wrap(this).getRootNode();\n      return (root instanceof DocumentFragment) ? /** @type {ShadowRoot} */ (root).host : root;\n    }\n\n    /**\n     * Force this element to distribute its children to its local dom.\n     * This should not be necessary as of Polymer 2.0.2 and is provided only\n     * for backwards compatibility.\n     * @return {void}\n     * @override\n     */\n    distributeContent() {\n      const thisEl = /** @type {Element} */ (this);\n      const domApi = /** @type {PolymerDomApi} */(dom(thisEl));\n      if (window.ShadyDOM && domApi.shadowRoot) {\n        ShadyDOM.flush();\n      }\n    }\n\n    /**\n     * Returns a list of nodes that are the effective childNodes. The effective\n     * childNodes list is the same as the element's childNodes except that\n     * any `<content>` elements are replaced with the list of nodes distributed\n     * to the `<content>`, the result of its `getDistributedNodes` method.\n     * @return {!Array<!Node>} List of effective child nodes.\n     * @suppress {invalidCasts} LegacyElementMixin must be applied to an\n     *     HTMLElement\n     * @override\n     */\n    getEffectiveChildNodes() {\n      const thisEl = /** @type {Element} */ (this);\n      const domApi = /** @type {PolymerDomApi} */ (dom(thisEl));\n      return domApi.getEffectiveChildNodes();\n    }\n\n    /**\n     * Returns a list of nodes distributed within this element that match\n     * `selector`. These can be dom children or elements distributed to\n     * children that are insertion points.\n     * @param {string} selector Selector to run.\n     * @return {!Array<!Node>} List of distributed elements that match selector.\n     * @suppress {invalidCasts} LegacyElementMixin must be applied to an\n     * HTMLElement\n     * @override\n     */\n    queryDistributedElements(selector) {\n      const thisEl = /** @type {Element} */ (this);\n      const domApi = /** @type {PolymerDomApi} */ (dom(thisEl));\n      return domApi.queryDistributedElements(selector);\n    }\n\n    /**\n     * Returns a list of elements that are the effective children. The effective\n     * children list is the same as the element's children except that\n     * any `<content>` elements are replaced with the list of elements\n     * distributed to the `<content>`.\n     *\n     * @return {!Array<!Node>} List of effective children.\n     * @override\n     */\n    getEffectiveChildren() {\n      let list = this.getEffectiveChildNodes();\n      return list.filter(function(/** @type {!Node} */ n) {\n        return (n.nodeType === Node.ELEMENT_NODE);\n      });\n    }\n\n    /**\n     * Returns a string of text content that is the concatenation of the\n     * text content's of the element's effective childNodes (the elements\n     * returned by <a href=\"#getEffectiveChildNodes>getEffectiveChildNodes</a>.\n     *\n     * @return {string} List of effective children.\n     * @override\n     */\n    getEffectiveTextContent() {\n      let cn = this.getEffectiveChildNodes();\n      let tc = [];\n      for (let i=0, c; (c = cn[i]); i++) {\n        if (c.nodeType !== Node.COMMENT_NODE) {\n          tc.push(c.textContent);\n        }\n      }\n      return tc.join('');\n    }\n\n    /**\n     * Returns the first effective childNode within this element that\n     * match `selector`. These can be dom child nodes or elements distributed\n     * to children that are insertion points.\n     * @param {string} selector Selector to run.\n     * @return {Node} First effective child node that matches selector.\n     * @override\n     */\n    queryEffectiveChildren(selector) {\n      let e$ = this.queryDistributedElements(selector);\n      return e$ && e$[0];\n    }\n\n    /**\n     * Returns a list of effective childNodes within this element that\n     * match `selector`. These can be dom child nodes or elements distributed\n     * to children that are insertion points.\n     * @param {string} selector Selector to run.\n     * @return {!Array<!Node>} List of effective child nodes that match\n     *     selector.\n     * @override\n     */\n    queryAllEffectiveChildren(selector) {\n      return this.queryDistributedElements(selector);\n    }\n\n    /**\n     * Returns a list of nodes distributed to this element's `<slot>`.\n     *\n     * If this element contains more than one `<slot>` in its local DOM,\n     * an optional selector may be passed to choose the desired content.\n     *\n     * @param {string=} slctr CSS selector to choose the desired\n     *   `<slot>`.  Defaults to `content`.\n     * @return {!Array<!Node>} List of distributed nodes for the `<slot>`.\n     * @override\n     */\n    getContentChildNodes(slctr) {\n      // Note, no need to `wrap` this because root is always\n      let content = this.root.querySelector(slctr || 'slot');\n      return content ?\n          /** @type {PolymerDomApi} */ (dom(content)).getDistributedNodes() :\n          [];\n    }\n\n    /**\n     * Returns a list of element children distributed to this element's\n     * `<slot>`.\n     *\n     * If this element contains more than one `<slot>` in its\n     * local DOM, an optional selector may be passed to choose the desired\n     * content.  This method differs from `getContentChildNodes` in that only\n     * elements are returned.\n     *\n     * @param {string=} slctr CSS selector to choose the desired\n     *   `<content>`.  Defaults to `content`.\n     * @return {!Array<!HTMLElement>} List of distributed nodes for the\n     *   `<slot>`.\n     * @suppress {invalidCasts}\n     * @override\n     */\n    getContentChildren(slctr) {\n      let children = /** @type {!Array<!HTMLElement>} */(this.getContentChildNodes(slctr).filter(function(n) {\n        return (n.nodeType === Node.ELEMENT_NODE);\n      }));\n      return children;\n    }\n\n    /**\n     * Checks whether an element is in this element's light DOM tree.\n     *\n     * @param {?Node} node The element to be checked.\n     * @return {boolean} true if node is in this element's light DOM tree.\n     * @suppress {invalidCasts} LegacyElementMixin must be applied to an\n     * HTMLElement\n     * @override\n     */\n    isLightDescendant(node) {\n      const thisNode = /** @type {Node} */ (this);\n      return thisNode !== node && wrap(thisNode).contains(node) &&\n        wrap(thisNode).getRootNode() === wrap(node).getRootNode();\n    }\n\n    /**\n     * Checks whether an element is in this element's local DOM tree.\n     *\n     * @param {!Element} node The element to be checked.\n     * @return {boolean} true if node is in this element's local DOM tree.\n     * @override\n     */\n    isLocalDescendant(node) {\n      return this.root === wrap(node).getRootNode();\n    }\n\n    /**\n     * No-op for backwards compatibility. This should now be handled by\n     * ShadyCss library.\n     * @param  {!Element} container Container element to scope\n     * @param  {boolean=} shouldObserve if true, start a mutation observer for added nodes to the container\n     * @return {?MutationObserver} Returns a new MutationObserver on `container` if `shouldObserve` is true.\n     * @override\n     */\n    scopeSubtree(container, shouldObserve = false) {\n      return scopeSubtree(container, shouldObserve);\n    }\n\n    /**\n     * Returns the computed style value for the given property.\n     * @param {string} property The css property name.\n     * @return {string} Returns the computed css property value for the given\n     * `property`.\n     * @suppress {invalidCasts} LegacyElementMixin must be applied to an\n     *     HTMLElement\n     * @override\n     */\n    getComputedStyleValue(property) {\n      return styleInterface.getComputedStyleValue(/** @type {!Element} */(this), property);\n    }\n\n    // debounce\n\n    /**\n     * Call `debounce` to collapse multiple requests for a named task into\n     * one invocation which is made after the wait time has elapsed with\n     * no new request.  If no wait time is given, the callback will be called\n     * at microtask timing (guaranteed before paint).\n     *\n     *     debouncedClickAction(e) {\n     *       // will not call `processClick` more than once per 100ms\n     *       this.debounce('click', function() {\n     *        this.processClick();\n     *       } 100);\n     *     }\n     *\n     * @param {string} jobName String to identify the debounce job.\n     * @param {function():void} callback Function that is called (with `this`\n     *   context) when the wait time elapses.\n     * @param {number=} wait Optional wait time in milliseconds (ms) after the\n     *   last signal that must elapse before invoking `callback`\n     * @return {!Object} Returns a debouncer object on which exists the\n     * following methods: `isActive()` returns true if the debouncer is\n     * active; `cancel()` cancels the debouncer if it is active;\n     * `flush()` immediately invokes the debounced callback if the debouncer\n     * is active.\n     * @override\n     */\n    debounce(jobName, callback, wait) {\n      this._debouncers = this._debouncers || {};\n      return this._debouncers[jobName] = Debouncer.debounce(\n            this._debouncers[jobName]\n          , wait > 0 ? timeOut.after(wait) : microTask\n          , callback.bind(this));\n    }\n\n    /**\n     * Returns whether a named debouncer is active.\n     *\n     * @param {string} jobName The name of the debouncer started with `debounce`\n     * @return {boolean} Whether the debouncer is active (has not yet fired).\n     * @override\n     */\n    isDebouncerActive(jobName) {\n      this._debouncers = this._debouncers || {};\n      let debouncer = this._debouncers[jobName];\n      return !!(debouncer && debouncer.isActive());\n    }\n\n    /**\n     * Immediately calls the debouncer `callback` and inactivates it.\n     *\n     * @param {string} jobName The name of the debouncer started with `debounce`\n     * @return {void}\n     * @override\n     */\n    flushDebouncer(jobName) {\n      this._debouncers = this._debouncers || {};\n      let debouncer = this._debouncers[jobName];\n      if (debouncer) {\n        debouncer.flush();\n      }\n    }\n\n    /**\n     * Cancels an active debouncer.  The `callback` will not be called.\n     *\n     * @param {string} jobName The name of the debouncer started with `debounce`\n     * @return {void}\n     * @override\n     */\n    cancelDebouncer(jobName) {\n      this._debouncers = this._debouncers || {};\n      let debouncer = this._debouncers[jobName];\n      if (debouncer) {\n        debouncer.cancel();\n      }\n    }\n\n    /**\n     * Runs a callback function asynchronously.\n     *\n     * By default (if no waitTime is specified), async callbacks are run at\n     * microtask timing, which will occur before paint.\n     *\n     * @param {!Function} callback The callback function to run, bound to\n     *     `this`.\n     * @param {number=} waitTime Time to wait before calling the\n     *   `callback`.  If unspecified or 0, the callback will be run at microtask\n     *   timing (before paint).\n     * @return {number} Handle that may be used to cancel the async job.\n     * @override\n     */\n    async(callback, waitTime) {\n      return waitTime > 0 ? timeOut.run(callback.bind(this), waitTime) :\n          ~microTask.run(callback.bind(this));\n    }\n\n    /**\n     * Cancels an async operation started with `async`.\n     *\n     * @param {number} handle Handle returned from original `async` call to\n     *   cancel.\n     * @return {void}\n     * @override\n     */\n    cancelAsync(handle) {\n      handle < 0 ? microTask.cancel(~handle) :\n          timeOut.cancel(handle);\n    }\n\n    // other\n\n    /**\n     * Convenience method for creating an element and configuring it.\n     *\n     * @param {string} tag HTML element tag to create.\n     * @param {Object=} props Object of properties to configure on the\n     *    instance.\n     * @return {!Element} Newly created and configured element.\n     * @override\n     */\n    create(tag, props) {\n      let elt = document.createElement(tag);\n      if (props) {\n        if (elt.setProperties) {\n          elt.setProperties(props);\n        } else {\n          for (let n in props) {\n            elt[n] = props[n];\n          }\n        }\n      }\n      return elt;\n    }\n\n    /**\n     * Polyfill for Element.prototype.matches, which is sometimes still\n     * prefixed.\n     *\n     * @param {string} selector Selector to test.\n     * @param {!Element=} node Element to test the selector against.\n     * @return {boolean} Whether the element matches the selector.\n     * @override\n     */\n    elementMatches(selector, node) {\n      return matchesSelector( (node || this), selector);\n    }\n\n    /**\n     * Toggles an HTML attribute on or off.\n     *\n     * @param {string} name HTML attribute name\n     * @param {boolean=} bool Boolean to force the attribute on or off.\n     *    When unspecified, the state of the attribute will be reversed.\n     * @return {boolean} true if the attribute now exists\n     * @override\n     */\n    toggleAttribute(name, bool) {\n      let node = /** @type {Element} */(this);\n      if (arguments.length === 3) {\n        node = /** @type {Element} */(arguments[2]);\n      }\n      if (arguments.length == 1) {\n        bool = !node.hasAttribute(name);\n      }\n      if (bool) {\n        wrap(node).setAttribute(name, '');\n        return true;\n      } else {\n        wrap(node).removeAttribute(name);\n        return false;\n      }\n    }\n\n\n    /**\n     * Toggles a CSS class on or off.\n     *\n     * @param {string} name CSS class name\n     * @param {boolean=} bool Boolean to force the class on or off.\n     *    When unspecified, the state of the class will be reversed.\n     * @param {Element=} node Node to target.  Defaults to `this`.\n     * @return {void}\n     * @override\n     */\n    toggleClass(name, bool, node) {\n      node = /** @type {Element} */ (node || this);\n      if (arguments.length == 1) {\n        bool = !node.classList.contains(name);\n      }\n      if (bool) {\n        node.classList.add(name);\n      } else {\n        node.classList.remove(name);\n      }\n    }\n\n    /**\n     * Cross-platform helper for setting an element's CSS `transform` property.\n     *\n     * @param {string} transformText Transform setting.\n     * @param {Element=} node Element to apply the transform to.\n     * Defaults to `this`\n     * @return {void}\n     * @override\n     */\n    transform(transformText, node) {\n      node = /** @type {Element} */ (node || this);\n      node.style.webkitTransform = transformText;\n      node.style.transform = transformText;\n    }\n\n    /**\n     * Cross-platform helper for setting an element's CSS `translate3d`\n     * property.\n     *\n     * @param {number|string} x X offset.\n     * @param {number|string} y Y offset.\n     * @param {number|string} z Z offset.\n     * @param {Element=} node Element to apply the transform to.\n     * Defaults to `this`.\n     * @return {void}\n     * @override\n     */\n    translate3d(x, y, z, node) {\n      node = /** @type {Element} */ (node || this);\n      this.transform('translate3d(' + x + ',' + y + ',' + z + ')', node);\n    }\n\n    /**\n     * Removes an item from an array, if it exists.\n     *\n     * If the array is specified by path, a change notification is\n     * generated, so that observers, data bindings and computed\n     * properties watching that path can update.\n     *\n     * If the array is passed directly, **no change\n     * notification is generated**.\n     *\n     * @param {string | !Array<number|string>} arrayOrPath Path to array from\n     *     which to remove the item\n     *   (or the array itself).\n     * @param {*} item Item to remove.\n     * @return {Array} Array containing item removed.\n     * @override\n     */\n    arrayDelete(arrayOrPath, item) {\n      let index;\n      if (Array.isArray(arrayOrPath)) {\n        index = arrayOrPath.indexOf(item);\n        if (index >= 0) {\n          return arrayOrPath.splice(index, 1);\n        }\n      } else {\n        let arr = get(this, arrayOrPath);\n        index = arr.indexOf(item);\n        if (index >= 0) {\n          return this.splice(arrayOrPath, index, 1);\n        }\n      }\n      return null;\n    }\n\n    // logging\n\n    /**\n     * Facades `console.log`/`warn`/`error` as override point.\n     *\n     * @param {string} level One of 'log', 'warn', 'error'\n     * @param {Array} args Array of strings or objects to log\n     * @return {void}\n     * @override\n     */\n    _logger(level, args) {\n      // accept ['foo', 'bar'] and [['foo', 'bar']]\n      if (Array.isArray(args) && args.length === 1 && Array.isArray(args[0])) {\n        args = args[0];\n      }\n      switch(level) {\n        case 'log':\n        case 'warn':\n        case 'error':\n          console[level](...args);\n      }\n    }\n\n    /**\n     * Facades `console.log` as an override point.\n     *\n     * @param {...*} args Array of strings or objects to log\n     * @return {void}\n     * @override\n     */\n    _log(...args) {\n      this._logger('log', args);\n    }\n\n    /**\n     * Facades `console.warn` as an override point.\n     *\n     * @param {...*} args Array of strings or objects to log\n     * @return {void}\n     * @override\n     */\n    _warn(...args) {\n      this._logger('warn', args);\n    }\n\n    /**\n     * Facades `console.error` as an override point.\n     *\n     * @param {...*} args Array of strings or objects to log\n     * @return {void}\n     * @override\n     */\n    _error(...args) {\n      this._logger('error', args);\n    }\n\n    /**\n     * Formats a message using the element type an a method name.\n     *\n     * @param {string} methodName Method name to associate with message\n     * @param {...*} args Array of strings or objects to log\n     * @return {!Array} Array with formatting information for `console`\n     *   logging.\n     * @override\n     */\n    _logf(methodName, ...args) {\n      return ['[%s::%s]', this.is, methodName, ...args];\n    }\n\n  }\n\n  LegacyElement.prototype.is = '';\n\n  return LegacyElement;\n});\n"
  },
  {
    "path": "lib/legacy/mutable-data-behavior.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n// tslint:disable:no-any describes the API as best we are able today\n\nimport {MutableData} from '../mixins/mutable-data.js';\n\nexport {MutableDataBehavior};\n\n/**\n * Legacy element behavior to skip strict dirty-checking for objects and arrays,\n * (always consider them to be \"dirty\") for use on legacy API Polymer elements.\n *\n * By default, `Polymer.PropertyEffects` performs strict dirty checking on\n * objects, which means that any deep modifications to an object or array will\n * not be propagated unless \"immutable\" data patterns are used (i.e. all object\n * references from the root to the mutation were changed).\n *\n * Polymer also provides a proprietary data mutation and path notification API\n * (e.g. `notifyPath`, `set`, and array mutation API's) that allow efficient\n * mutation and notification of deep changes in an object graph to all elements\n * bound to the same object graph.\n *\n * In cases where neither immutable patterns nor the data mutation API can be\n * used, applying this mixin will cause Polymer to skip dirty checking for\n * objects and arrays (always consider them to be \"dirty\").  This allows a\n * user to make a deep modification to a bound object graph, and then either\n * simply re-set the object (e.g. `this.items = this.items`) or call `notifyPath`\n * (e.g. `this.notifyPath('items')`) to update the tree.  Note that all\n * elements that wish to be updated based on deep mutations must apply this\n * mixin or otherwise skip strict dirty checking for objects/arrays.\n * Specifically, any elements in the binding tree between the source of a\n * mutation and the consumption of it must apply this behavior or enable the\n * `Polymer.OptionalMutableDataBehavior`.\n *\n * In order to make the dirty check strategy configurable, see\n * `Polymer.OptionalMutableDataBehavior`.\n *\n * Note, the performance characteristics of propagating large object graphs\n * will be worse as opposed to using strict dirty checking with immutable\n * patterns or Polymer's path notification API.\n */\ninterface MutableDataBehavior {\n\n  /**\n   * Overrides `Polymer.PropertyEffects` to provide option for skipping\n   * strict equality checking for Objects and Arrays.\n   *\n   * This method pulls the value to dirty check against from the `__dataTemp`\n   * cache (rather than the normal `__data` cache) for Objects.  Since the temp\n   * cache is cleared at the end of a turn, this implementation allows\n   * side-effects of deep object changes to be processed by re-setting the\n   * same object (using the temp cache as an in-turn backstop to prevent\n   * cycles due to 2-way notification).\n   *\n   * @param property Property name\n   * @param value New property value\n   * @param old Previous property value\n   * @returns Whether the property should be considered a change\n   */\n  _shouldPropertyChange(property: string, value: any, old: any): boolean;\n}\n\ndeclare const MutableDataBehavior: object;\n\nexport {OptionalMutableDataBehavior};\n\n/**\n * Legacy element behavior to add the optional ability to skip strict\n * dirty-checking for objects and arrays (always consider them to be\n * \"dirty\") by setting a `mutable-data` attribute on an element instance.\n *\n * By default, `Polymer.PropertyEffects` performs strict dirty checking on\n * objects, which means that any deep modifications to an object or array will\n * not be propagated unless \"immutable\" data patterns are used (i.e. all object\n * references from the root to the mutation were changed).\n *\n * Polymer also provides a proprietary data mutation and path notification API\n * (e.g. `notifyPath`, `set`, and array mutation API's) that allow efficient\n * mutation and notification of deep changes in an object graph to all elements\n * bound to the same object graph.\n *\n * In cases where neither immutable patterns nor the data mutation API can be\n * used, applying this mixin will allow Polymer to skip dirty checking for\n * objects and arrays (always consider them to be \"dirty\").  This allows a\n * user to make a deep modification to a bound object graph, and then either\n * simply re-set the object (e.g. `this.items = this.items`) or call `notifyPath`\n * (e.g. `this.notifyPath('items')`) to update the tree.  Note that all\n * elements that wish to be updated based on deep mutations must apply this\n * mixin or otherwise skip strict dirty checking for objects/arrays.\n * Specifically, any elements in the binding tree between the source of a\n * mutation and the consumption of it must enable this behavior or apply the\n * `Polymer.OptionalMutableDataBehavior`.\n *\n * While this behavior adds the ability to forgo Object/Array dirty checking,\n * the `mutableData` flag defaults to false and must be set on the instance.\n *\n * Note, the performance characteristics of propagating large object graphs\n * will be worse by relying on `mutableData: true` as opposed to using\n * strict dirty checking with immutable patterns or Polymer's path notification\n * API.\n */\ninterface OptionalMutableDataBehavior {\n\n  /**\n   * Instance-level flag for configuring the dirty-checking strategy\n   * for this element.  When true, Objects and Arrays will skip dirty\n   * checking, otherwise strict equality checking will be used.\n   */\n  mutableData: boolean|null|undefined;\n\n  /**\n   * Overrides `Polymer.PropertyEffects` to skip strict equality checking\n   * for Objects and Arrays.\n   *\n   * Pulls the value to dirty check against from the `__dataTemp` cache\n   * (rather than the normal `__data` cache) for Objects.  Since the temp\n   * cache is cleared at the end of a turn, this implementation allows\n   * side-effects of deep object changes to be processed by re-setting the\n   * same object (using the temp cache as an in-turn backstop to prevent\n   * cycles due to 2-way notification).\n   *\n   * @param property Property name\n   * @param value New property value\n   * @param old Previous property value\n   * @returns Whether the property should be considered a change\n   */\n  _shouldPropertyChange(property: string, value: any, old: any): boolean;\n}\n\ndeclare const OptionalMutableDataBehavior: object;\n"
  },
  {
    "path": "lib/legacy/mutable-data-behavior.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport { MutableData } from '../mixins/mutable-data.js';\n\nlet mutablePropertyChange;\n/** @suppress {missingProperties} */\n(() => {\n  mutablePropertyChange = MutableData._mutablePropertyChange;\n})();\n\n/**\n * Legacy element behavior to skip strict dirty-checking for objects and arrays,\n * (always consider them to be \"dirty\") for use on legacy API Polymer elements.\n *\n * By default, `Polymer.PropertyEffects` performs strict dirty checking on\n * objects, which means that any deep modifications to an object or array will\n * not be propagated unless \"immutable\" data patterns are used (i.e. all object\n * references from the root to the mutation were changed).\n *\n * Polymer also provides a proprietary data mutation and path notification API\n * (e.g. `notifyPath`, `set`, and array mutation API's) that allow efficient\n * mutation and notification of deep changes in an object graph to all elements\n * bound to the same object graph.\n *\n * In cases where neither immutable patterns nor the data mutation API can be\n * used, applying this mixin will cause Polymer to skip dirty checking for\n * objects and arrays (always consider them to be \"dirty\").  This allows a\n * user to make a deep modification to a bound object graph, and then either\n * simply re-set the object (e.g. `this.items = this.items`) or call `notifyPath`\n * (e.g. `this.notifyPath('items')`) to update the tree.  Note that all\n * elements that wish to be updated based on deep mutations must apply this\n * mixin or otherwise skip strict dirty checking for objects/arrays.\n * Specifically, any elements in the binding tree between the source of a\n * mutation and the consumption of it must apply this behavior or enable the\n * `Polymer.OptionalMutableDataBehavior`.\n *\n * In order to make the dirty check strategy configurable, see\n * `Polymer.OptionalMutableDataBehavior`.\n *\n * Note, the performance characteristics of propagating large object graphs\n * will be worse as opposed to using strict dirty checking with immutable\n * patterns or Polymer's path notification API.\n *\n * @polymerBehavior\n * @summary Behavior to skip strict dirty-checking for objects and\n *   arrays\n */\nexport const MutableDataBehavior = {\n\n  /**\n   * Overrides `Polymer.PropertyEffects` to provide option for skipping\n   * strict equality checking for Objects and Arrays.\n   *\n   * This method pulls the value to dirty check against from the `__dataTemp`\n   * cache (rather than the normal `__data` cache) for Objects.  Since the temp\n   * cache is cleared at the end of a turn, this implementation allows\n   * side-effects of deep object changes to be processed by re-setting the\n   * same object (using the temp cache as an in-turn backstop to prevent\n   * cycles due to 2-way notification).\n   *\n   * @param {string} property Property name\n   * @param {*} value New property value\n   * @param {*} old Previous property value\n   * @return {boolean} Whether the property should be considered a change\n   * @protected\n   * @override\n   */\n  _shouldPropertyChange(property, value, old) {\n    return mutablePropertyChange(this, property, value, old, true);\n  }\n};\n\n/**\n * Legacy element behavior to add the optional ability to skip strict\n * dirty-checking for objects and arrays (always consider them to be\n * \"dirty\") by setting a `mutable-data` attribute on an element instance.\n *\n * By default, `Polymer.PropertyEffects` performs strict dirty checking on\n * objects, which means that any deep modifications to an object or array will\n * not be propagated unless \"immutable\" data patterns are used (i.e. all object\n * references from the root to the mutation were changed).\n *\n * Polymer also provides a proprietary data mutation and path notification API\n * (e.g. `notifyPath`, `set`, and array mutation API's) that allow efficient\n * mutation and notification of deep changes in an object graph to all elements\n * bound to the same object graph.\n *\n * In cases where neither immutable patterns nor the data mutation API can be\n * used, applying this mixin will allow Polymer to skip dirty checking for\n * objects and arrays (always consider them to be \"dirty\").  This allows a\n * user to make a deep modification to a bound object graph, and then either\n * simply re-set the object (e.g. `this.items = this.items`) or call `notifyPath`\n * (e.g. `this.notifyPath('items')`) to update the tree.  Note that all\n * elements that wish to be updated based on deep mutations must apply this\n * mixin or otherwise skip strict dirty checking for objects/arrays.\n * Specifically, any elements in the binding tree between the source of a\n * mutation and the consumption of it must enable this behavior or apply the\n * `Polymer.OptionalMutableDataBehavior`.\n *\n * While this behavior adds the ability to forgo Object/Array dirty checking,\n * the `mutableData` flag defaults to false and must be set on the instance.\n *\n * Note, the performance characteristics of propagating large object graphs\n * will be worse by relying on `mutableData: true` as opposed to using\n * strict dirty checking with immutable patterns or Polymer's path notification\n * API.\n *\n * @polymerBehavior\n * @summary Behavior to optionally skip strict dirty-checking for objects and\n *   arrays\n */\nexport const OptionalMutableDataBehavior = {\n\n  properties: {\n    /**\n     * Instance-level flag for configuring the dirty-checking strategy\n     * for this element.  When true, Objects and Arrays will skip dirty\n     * checking, otherwise strict equality checking will be used.\n     */\n    mutableData: Boolean\n  },\n\n  /**\n   * Overrides `Polymer.PropertyEffects` to skip strict equality checking\n   * for Objects and Arrays.\n   *\n   * Pulls the value to dirty check against from the `__dataTemp` cache\n   * (rather than the normal `__data` cache) for Objects.  Since the temp\n   * cache is cleared at the end of a turn, this implementation allows\n   * side-effects of deep object changes to be processed by re-setting the\n   * same object (using the temp cache as an in-turn backstop to prevent\n   * cycles due to 2-way notification).\n   *\n   * @param {string} property Property name\n   * @param {*} value New property value\n   * @param {*} old Previous property value\n   * @return {boolean} Whether the property should be considered a change\n   * @protected\n   * @override\n   */\n  _shouldPropertyChange(property, value, old) {\n    return mutablePropertyChange(this, property, value, old, this.mutableData);\n  }\n};\n"
  },
  {
    "path": "lib/legacy/polymer-fn.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n\nimport {Class} from './class.js';\n\n\n/**\n * Legacy class factory and registration helper for defining Polymer\n * elements.\n *\n * This method is equivalent to\n *\n *     import {Class} from '@polymer/polymer/lib/legacy/class.js';\n *     customElements.define(info.is, Class(info));\n *\n * See `Class` for details on valid legacy metadata format for `info`.\n *\n * @returns Generated class\n */\nexport const Polymer: {\n  (info: PolymerInit): {new(): HTMLElement};\n  Class: typeof Class;\n}\n\nimport {PolymerInit} from '../../interfaces';\n"
  },
  {
    "path": "lib/legacy/polymer-fn.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport { Class } from './class.js';\n\nimport '../utils/boot.js';\n\n/**\n * Legacy class factory and registration helper for defining Polymer\n * elements.\n *\n * This method is equivalent to\n *\n *     import {Class} from '@polymer/polymer/lib/legacy/class.js';\n *     customElements.define(info.is, Class(info));\n *\n * See `Class` for details on valid legacy metadata format for `info`.\n *\n * @global\n * @override\n * @function\n * @param {!PolymerInit} info Object containing Polymer metadata and functions\n *   to become class methods.\n * @return {function(new: HTMLElement)} Generated class\n * @suppress {duplicate, invalidCasts, checkTypes}\n */\nconst Polymer = function(info) {\n  // if input is a `class` (aka a function with a prototype), use the prototype\n  // remember that the `constructor` will never be called\n  let klass;\n  if (typeof info === 'function') {\n    klass = info;\n  } else {\n    klass = Polymer.Class(info);\n  }\n  // Copy opt out for `legacyNoObservedAttributes` from info object to class.\n  if (info._legacyForceObservedAttributes) {\n    klass.prototype._legacyForceObservedAttributes = info._legacyForceObservedAttributes;\n  }\n  customElements.define(klass.is, /** @type {!HTMLElement} */(klass));\n  return klass;\n};\n\nPolymer.Class = Class;\n\nexport { Polymer };"
  },
  {
    "path": "lib/legacy/polymer.dom.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n// tslint:disable:no-any describes the API as best we are able today\n\nimport {FlattenedNodesObserver} from '../utils/flattened-nodes-observer.js';\n\nexport {flush, enqueueDebouncer as addDebouncer} from '../utils/flush.js';\n\nimport {Debouncer} from '../utils/debounce.js';\n\nexport {matchesSelector};\n\n\n/**\n * Cross-platform `element.matches` shim.\n *\n * @returns True if node matched selector\n */\ndeclare function matchesSelector(node: Node, selector: string): boolean;\n\n\nexport {DomApiNative as DomApi};\n\n/**\n * Node API wrapper class returned from `Polymer.dom.(target)` when\n * `target` is a `Node`.\n */\ndeclare class DomApiNative {\n\n  /**\n   * For shadow roots, returns the currently focused element within this\n   * shadow root.\n   *\n   * return {Node|undefined} Currently focused element\n   */\n  readonly activeElement: any;\n  parentNode: Node|null;\n  firstChild: Node|null;\n  lastChild: Node|null;\n  nextSibling: Node|null;\n  previousSibling: Node|null;\n  firstElementChild: HTMLElement|null;\n  lastElementChild: HTMLElement|null;\n  nextElementSibling: HTMLElement|null;\n  previousElementSibling: HTMLElement|null;\n  childNodes: Node[];\n  children: HTMLElement[];\n  classList: DOMTokenList|null;\n  textContent: string;\n  innerHTML: string;\n\n  /**\n   * @param node Node for which to create a Polymer.dom helper object.\n   */\n  constructor(node: Node);\n\n  /**\n   * Returns an instance of `FlattenedNodesObserver` that\n   * listens for node changes on this element.\n   *\n   * @param callback Called when direct or distributed children\n   *   of this element changes\n   * @returns Observer instance\n   */\n  observeNodes(callback: (p0: {target: HTMLElement, addedNodes: Element[], removedNodes: Element[]}) => void): FlattenedNodesObserver;\n\n  /**\n   * Disconnects an observer previously created via `observeNodes`\n   *\n   * @param observerHandle Observer instance\n   *   to disconnect.\n   */\n  unobserveNodes(observerHandle: FlattenedNodesObserver): void;\n\n  /**\n   * Provided as a backwards-compatible API only.  This method does nothing.\n   */\n  notifyObserver(): void;\n\n  /**\n   * Returns true if the provided node is contained with this element's\n   * light-DOM children or shadow root, including any nested shadow roots\n   * of children therein.\n   *\n   * @param node Node to test\n   * @returns Returns true if the given `node` is contained within\n   *   this element's light or shadow DOM.\n   */\n  deepContains(node: Node|null): boolean;\n\n  /**\n   * Returns the root node of this node.  Equivalent to `getRootNode()`.\n   *\n   * @returns Top most element in the dom tree in which the node\n   * exists. If the node is connected to a document this is either a\n   * shadowRoot or the document; otherwise, it may be the node\n   * itself or a node or document fragment containing it.\n   */\n  getOwnerRoot(): Node;\n\n  /**\n   * For slot elements, returns the nodes assigned to the slot; otherwise\n   * an empty array. It is equivalent to `<slot>.addignedNodes({flatten:true})`.\n   *\n   * @returns Array of assigned nodes\n   */\n  getDistributedNodes(): Node[];\n\n  /**\n   * Returns an array of all slots this element was distributed to.\n   *\n   * @returns Description\n   */\n  getDestinationInsertionPoints(): HTMLSlotElement[];\n\n  /**\n   * Calls `importNode` on the `ownerDocument` for this node.\n   *\n   * @param node Node to import\n   * @param deep True if the node should be cloned deeply during\n   *   import\n   * @returns Clone of given node imported to this owner document\n   */\n  importNode(node: Node, deep: boolean): Node|null;\n\n  /**\n   * @returns Returns a flattened list of all child nodes and\n   * nodes assigned to child slots.\n   */\n  getEffectiveChildNodes(): Node[];\n\n  /**\n   * Returns a filtered list of flattened child elements for this element based\n   * on the given selector.\n   *\n   * @param selector Selector to filter nodes against\n   * @returns List of flattened child elements\n   */\n  queryDistributedElements(selector: string): HTMLElement[];\n  cloneNode(deep?: boolean): Node;\n  appendChild(node: Node): Node;\n  insertBefore(newChild: Node, refChild: Node|null): Node;\n  removeChild(node: Node): Node;\n  replaceChild(oldChild: Node, newChild: Node): Node;\n  setAttribute(name: string, value: string): void;\n  removeAttribute(name: string): void;\n  querySelector(selector: string): Element|null;\n  querySelectorAll(selector: string): NodeListOf<Element>;\n}\n\nexport {EventApi};\n\n/**\n * Event API wrapper class returned from `dom.(target)` when\n * `target` is an `Event`.\n */\ndeclare class EventApi {\n\n  /**\n   * Returns the first node on the `composedPath` of this event.\n   */\n  readonly rootTarget: EventTarget;\n\n  /**\n   * Returns the local (re-targeted) target for this event.\n   */\n  readonly localTarget: EventTarget;\n\n  /**\n   * Returns the `composedPath` for this event.\n   */\n  readonly path: EventTarget[];\n  constructor(event: any);\n}\n\nexport {dom};\n\n\n/**\n * Legacy DOM and Event manipulation API wrapper factory used to abstract\n * differences between native Shadow DOM and \"Shady DOM\" when polyfilling on\n * older browsers.\n *\n * Note that in Polymer 2.x use of `Polymer.dom` is no longer required and\n * in the majority of cases simply facades directly to the standard native\n * API.\n *\n * @returns Wrapper providing either node API or event API\n */\ndeclare function dom(obj?: Node|Event|DomApiNative|EventApi|null): DomApiNative|EventApi;\n"
  },
  {
    "path": "lib/legacy/polymer.dom.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport '../utils/boot.js';\nimport { wrap } from '../utils/wrap.js';\nimport '../utils/settings.js';\nimport { FlattenedNodesObserver } from '../utils/flattened-nodes-observer.js';\nexport { flush, enqueueDebouncer as addDebouncer } from '../utils/flush.js';\n/* eslint-disable no-unused-vars */\nimport { Debouncer } from '../utils/debounce.js';  // used in type annotations\n/* eslint-enable no-unused-vars */\n\nconst p = Element.prototype;\n/**\n * @const {function(this:Node, string): boolean}\n */\nconst normalizedMatchesSelector = p.matches || p.matchesSelector ||\n  p.mozMatchesSelector || p.msMatchesSelector ||\n  p.oMatchesSelector || p.webkitMatchesSelector;\n\n/**\n * Cross-platform `element.matches` shim.\n *\n * @function matchesSelector\n * @param {!Node} node Node to check selector against\n * @param {string} selector Selector to match\n * @return {boolean} True if node matched selector\n */\nexport const matchesSelector = function(node, selector) {\n  return normalizedMatchesSelector.call(node, selector);\n};\n\n/**\n * Node API wrapper class returned from `Polymer.dom.(target)` when\n * `target` is a `Node`.\n * @implements {PolymerDomApi}\n * @unrestricted\n */\nclass DomApiNative {\n\n  /**\n   * @param {!Node} node Node for which to create a Polymer.dom helper object.\n   */\n  constructor(node) {\n    if (window['ShadyDOM'] && window['ShadyDOM']['inUse']) {\n      window['ShadyDOM']['patch'](node);\n    }\n    this.node = node;\n  }\n\n  /**\n   * Returns an instance of `FlattenedNodesObserver` that\n   * listens for node changes on this element.\n   *\n   * @param {function(this:HTMLElement, { target: !HTMLElement, addedNodes: !Array<!Element>, removedNodes: !Array<!Element> }):void} callback Called when direct or distributed children\n   *   of this element changes\n   * @return {!PolymerDomApi.ObserveHandle} Observer instance\n   * @override\n   */\n  observeNodes(callback) {\n    return new FlattenedNodesObserver(\n        /** @type {!HTMLElement} */(this.node), callback);\n  }\n\n  /**\n   * Disconnects an observer previously created via `observeNodes`\n   *\n   * @param {!PolymerDomApi.ObserveHandle} observerHandle Observer instance\n   *   to disconnect.\n   * @return {void}\n   * @override\n   */\n  unobserveNodes(observerHandle) {\n    observerHandle.disconnect();\n  }\n\n  /**\n   * Provided as a backwards-compatible API only.  This method does nothing.\n   * @return {void}\n   */\n  notifyObserver() {}\n\n  /**\n   * Returns true if the provided node is contained with this element's\n   * light-DOM children or shadow root, including any nested shadow roots\n   * of children therein.\n   *\n   * @param {Node} node Node to test\n   * @return {boolean} Returns true if the given `node` is contained within\n   *   this element's light or shadow DOM.\n   * @override\n   */\n  deepContains(node) {\n    if (wrap(this.node).contains(node)) {\n      return true;\n    }\n    let n = node;\n    let doc = node.ownerDocument;\n    // walk from node to `this` or `document`\n    while (n && n !== doc && n !== this.node) {\n      // use logical parentnode, or native ShadowRoot host\n      n = wrap(n).parentNode || wrap(n).host;\n    }\n    return n === this.node;\n  }\n\n  /**\n   * Returns the root node of this node.  Equivalent to `getRootNode()`.\n   *\n   * @return {!Node} Top most element in the dom tree in which the node\n   * exists. If the node is connected to a document this is either a\n   * shadowRoot or the document; otherwise, it may be the node\n   * itself or a node or document fragment containing it.\n   * @override\n   */\n  getOwnerRoot() {\n    return wrap(this.node).getRootNode();\n  }\n\n  /**\n   * For slot elements, returns the nodes assigned to the slot; otherwise\n   * an empty array. It is equivalent to `<slot>.addignedNodes({flatten:true})`.\n   *\n   * @return {!Array<!Node>} Array of assigned nodes\n   * @override\n   */\n  getDistributedNodes() {\n    return (this.node.localName === 'slot') ?\n      wrap(this.node).assignedNodes({flatten: true}) :\n      [];\n  }\n\n  /**\n   * Returns an array of all slots this element was distributed to.\n   *\n   * @return {!Array<!HTMLSlotElement>} Description\n   * @override\n   */\n  getDestinationInsertionPoints() {\n    let ip$ = [];\n    let n = wrap(this.node).assignedSlot;\n    while (n) {\n      ip$.push(n);\n      n = wrap(n).assignedSlot;\n    }\n    return ip$;\n  }\n\n  /**\n   * Calls `importNode` on the `ownerDocument` for this node.\n   *\n   * @param {!Node} node Node to import\n   * @param {boolean} deep True if the node should be cloned deeply during\n   *   import\n   * @return {Node} Clone of given node imported to this owner document\n   */\n  importNode(node, deep) {\n    let doc = this.node instanceof Document ? this.node :\n      this.node.ownerDocument;\n    return wrap(doc).importNode(node, deep);\n  }\n\n  /**\n   * @return {!Array<!Node>} Returns a flattened list of all child nodes and\n   * nodes assigned to child slots.\n   * @override\n   */\n  getEffectiveChildNodes() {\n    return FlattenedNodesObserver.getFlattenedNodes(\n        /** @type {!HTMLElement} */ (this.node));\n  }\n\n  /**\n   * Returns a filtered list of flattened child elements for this element based\n   * on the given selector.\n   *\n   * @param {string} selector Selector to filter nodes against\n   * @return {!Array<!HTMLElement>} List of flattened child elements\n   * @override\n   */\n  queryDistributedElements(selector) {\n    let c$ = this.getEffectiveChildNodes();\n    let list = [];\n    for (let i=0, l=c$.length, c; (i<l) && (c=c$[i]); i++) {\n      if ((c.nodeType === Node.ELEMENT_NODE) &&\n          matchesSelector(c, selector)) {\n        list.push(c);\n      }\n    }\n    return list;\n  }\n\n  /**\n   * For shadow roots, returns the currently focused element within this\n   * shadow root.\n   *\n   * return {Node|undefined} Currently focused element\n   * @override\n   */\n  get activeElement() {\n    let node = this.node;\n    return node._activeElement !== undefined ? node._activeElement : node.activeElement;\n  }\n}\n\nfunction forwardMethods(proto, methods) {\n  for (let i=0; i < methods.length; i++) {\n    let method = methods[i];\n    /* eslint-disable valid-jsdoc */\n    proto[method] = /** @this {DomApiNative} */ function() {\n      return this.node[method].apply(this.node, arguments);\n    };\n    /* eslint-enable */\n  }\n}\n\nfunction forwardReadOnlyProperties(proto, properties) {\n  for (let i=0; i < properties.length; i++) {\n    let name = properties[i];\n    Object.defineProperty(proto, name, {\n      get: function() {\n        const domApi = /** @type {DomApiNative} */(this);\n        return domApi.node[name];\n      },\n      configurable: true\n    });\n  }\n}\n\nfunction forwardProperties(proto, properties) {\n  for (let i=0; i < properties.length; i++) {\n    let name = properties[i];\n    Object.defineProperty(proto, name, {\n      /**\n       * @this {DomApiNative}\n       * @return {*} .\n       */\n      get: function() {\n        return this.node[name];\n      },\n      /**\n       * @this {DomApiNative}\n       * @param {*} value .\n       */\n      set: function(value) {\n        this.node[name] = value;\n      },\n      configurable: true\n    });\n  }\n}\n\n\n/**\n * Event API wrapper class returned from `dom.(target)` when\n * `target` is an `Event`.\n */\nexport class EventApi {\n  constructor(event) {\n    this.event = event;\n  }\n\n  /**\n   * Returns the first node on the `composedPath` of this event.\n   *\n   * @return {!EventTarget} The node this event was dispatched to\n   */\n  get rootTarget() {\n    return this.path[0];\n  }\n\n  /**\n   * Returns the local (re-targeted) target for this event.\n   *\n   * @return {!EventTarget} The local (re-targeted) target for this event.\n   */\n  get localTarget() {\n    return this.event.target;\n  }\n\n  /**\n   * Returns the `composedPath` for this event.\n   * @return {!Array<!EventTarget>} The nodes this event propagated through\n   */\n  get path() {\n    return this.event.composedPath();\n  }\n}\n\n/**\n * @function\n * @param {boolean=} deep\n * @return {!Node}\n */\nDomApiNative.prototype.cloneNode;\n/**\n * @function\n * @param {!Node} node\n * @return {!Node}\n */\nDomApiNative.prototype.appendChild;\n/**\n * @function\n * @param {!Node} newChild\n * @param {Node} refChild\n * @return {!Node}\n */\nDomApiNative.prototype.insertBefore;\n/**\n * @function\n * @param {!Node} node\n * @return {!Node}\n */\nDomApiNative.prototype.removeChild;\n/**\n * @function\n * @param {!Node} oldChild\n * @param {!Node} newChild\n * @return {!Node}\n */\nDomApiNative.prototype.replaceChild;\n/**\n * @function\n * @param {string} name\n * @param {string} value\n * @return {void}\n */\nDomApiNative.prototype.setAttribute;\n/**\n * @function\n * @param {string} name\n * @return {void}\n */\nDomApiNative.prototype.removeAttribute;\n/**\n * @function\n * @param {string} selector\n * @return {?Element}\n */\nDomApiNative.prototype.querySelector;\n/**\n * @function\n * @param {string} selector\n * @return {!NodeList<!Element>}\n */\nDomApiNative.prototype.querySelectorAll;\n\n/** @type {?Node} */\nDomApiNative.prototype.parentNode;\n/** @type {?Node} */\nDomApiNative.prototype.firstChild;\n/** @type {?Node} */\nDomApiNative.prototype.lastChild;\n/** @type {?Node} */\nDomApiNative.prototype.nextSibling;\n/** @type {?Node} */\nDomApiNative.prototype.previousSibling;\n/** @type {?HTMLElement} */\nDomApiNative.prototype.firstElementChild;\n/** @type {?HTMLElement} */\nDomApiNative.prototype.lastElementChild;\n/** @type {?HTMLElement} */\nDomApiNative.prototype.nextElementSibling;\n/** @type {?HTMLElement} */\nDomApiNative.prototype.previousElementSibling;\n/** @type {!Array<!Node>} */\nDomApiNative.prototype.childNodes;\n/** @type {!Array<!HTMLElement>} */\nDomApiNative.prototype.children;\n/** @type {?DOMTokenList} */\nDomApiNative.prototype.classList;\n\n/** @type {string} */\nDomApiNative.prototype.textContent;\n/** @type {string} */\nDomApiNative.prototype.innerHTML;\n\nlet DomApiImpl = DomApiNative;\n\nif (window['ShadyDOM'] && window['ShadyDOM']['inUse'] && window['ShadyDOM']['noPatch'] && window['ShadyDOM']['Wrapper']) {\n\n  /**\n   * @private\n   * @extends {HTMLElement}\n   */\n  class Wrapper extends window['ShadyDOM']['Wrapper'] {}\n\n  // copy bespoke API onto wrapper\n  Object.getOwnPropertyNames(DomApiNative.prototype).forEach((prop) => {\n    if (prop != 'activeElement') {\n      Wrapper.prototype[prop] = DomApiNative.prototype[prop];\n    }\n  });\n\n  // Note, `classList` is here only for legacy compatibility since it does not\n  // trigger distribution in v1 Shadow DOM.\n  forwardReadOnlyProperties(Wrapper.prototype, [\n    'classList'\n  ]);\n\n  DomApiImpl = Wrapper;\n\n  Object.defineProperties(EventApi.prototype, {\n\n    // Returns the \"lowest\" node in the same root as the event's currentTarget.\n    // When in `noPatch` mode, this must be calculated by walking the event's\n    // path.\n    localTarget: {\n      get() {\n        const current = this.event.currentTarget;\n        const currentRoot = current && dom(current).getOwnerRoot();\n        const p$ = this.path;\n        for (let i = 0; i < p$.length; i++) {\n          const e = p$[i];\n          if (dom(e).getOwnerRoot() === currentRoot) {\n            return e;\n          }\n        }\n      },\n      configurable: true\n    },\n\n    path: {\n      get() {\n        return window['ShadyDOM']['composedPath'](this.event);\n      },\n      configurable: true\n    }\n  });\n\n} else {\n\n  // Methods that can provoke distribution or must return the logical, not\n  // composed tree.\n  forwardMethods(DomApiNative.prototype, [\n    'cloneNode', 'appendChild', 'insertBefore', 'removeChild',\n    'replaceChild', 'setAttribute', 'removeAttribute',\n    'querySelector', 'querySelectorAll', 'attachShadow'\n  ]);\n\n  // Properties that should return the logical, not composed tree. Note, `classList`\n  // is here only for legacy compatibility since it does not trigger distribution\n  // in v1 Shadow DOM.\n  forwardReadOnlyProperties(DomApiNative.prototype, [\n    'parentNode', 'firstChild', 'lastChild',\n    'nextSibling', 'previousSibling', 'firstElementChild',\n    'lastElementChild', 'nextElementSibling', 'previousElementSibling',\n    'childNodes', 'children', 'classList', 'shadowRoot'\n  ]);\n\n  forwardProperties(DomApiNative.prototype, [\n    'textContent', 'innerHTML', 'className'\n  ]);\n}\n\nexport const DomApi = DomApiImpl;\n\n/**\n * Legacy DOM and Event manipulation API wrapper factory used to abstract\n * differences between native Shadow DOM and \"Shady DOM\" when polyfilling on\n * older browsers.\n *\n * Note that in Polymer 2.x use of `Polymer.dom` is no longer required and\n * in the majority of cases simply facades directly to the standard native\n * API.\n *\n * @summary Legacy DOM and Event manipulation API wrapper factory used to\n * abstract differences between native Shadow DOM and \"Shady DOM.\"\n * @param {(Node|Event|DomApiNative|EventApi)=} obj Node or event to operate on\n * @return {!DomApiNative|!EventApi} Wrapper providing either node API or event API\n */\nexport const dom = function(obj) {\n  obj = obj || document;\n  if (obj instanceof DomApiImpl) {\n    return /** @type {!DomApi} */(obj);\n  }\n  if (obj instanceof EventApi) {\n    return /** @type {!EventApi} */(obj);\n  }\n  let helper = obj['__domApi'];\n  if (!helper) {\n    if (obj instanceof Event) {\n      helper = new EventApi(obj);\n    } else {\n      helper = new DomApiImpl(/** @type {Node} */(obj));\n    }\n    obj['__domApi'] = helper;\n  }\n  return helper;\n};\n"
  },
  {
    "path": "lib/legacy/templatizer-behavior.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n\nimport {TemplateInstanceBase, templatize, modelForElement} from '../utils/templatize.js';\n\nexport {Templatizer};\n\n/**\n * The `Templatizer` behavior adds methods to generate instances of\n * templates that are each managed by an anonymous `PropertyEffects`\n * instance where data-bindings in the stamped template content are bound to\n * accessors on itself.\n *\n * This behavior is provided in Polymer 2.x-3.x as a hybrid-element convenience\n * only.  For non-hybrid usage, the `Templatize` library\n * should be used instead.\n *\n * Example:\n *\n *     import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';\n *     // Get a template from somewhere, e.g. light DOM\n *     let template = this.querySelector('template');\n *     // Prepare the template\n *     this.templatize(template);\n *     // Instance the template with an initial data model\n *     let instance = this.stamp({myProp: 'initial'});\n *     // Insert the instance's DOM somewhere, e.g. light DOM\n *     dom(this).appendChild(instance.root);\n *     // Changing a property on the instance will propagate to bindings\n *     // in the template\n *     instance.myProp = 'new value';\n *\n * Users of `Templatizer` may need to implement the following abstract\n * API's to determine how properties and paths from the host should be\n * forwarded into to instances:\n *\n *     _forwardHostPropV2: function(prop, value)\n *\n * Likewise, users may implement these additional abstract API's to determine\n * how instance-specific properties that change on the instance should be\n * forwarded out to the host, if necessary.\n *\n *     _notifyInstancePropV2: function(inst, prop, value)\n *\n * In order to determine which properties are instance-specific and require\n * custom notification via `_notifyInstanceProp`, define an `_instanceProps`\n * object containing keys for each instance prop, for example:\n *\n *     _instanceProps: {\n *       item: true,\n *       index: true\n *     }\n *\n * Any properties used in the template that are not defined in _instanceProp\n * will be forwarded out to the Templatize `owner` automatically.\n *\n * Users may also implement the following abstract function to show or\n * hide any DOM generated using `stamp`:\n *\n *     _showHideChildren: function(shouldHide)\n *\n * Note that some callbacks are suffixed with `V2` in the Polymer 2.x behavior\n * as the implementations will need to differ from the callbacks required\n * by the 1.x Templatizer API due to changes in the `TemplateInstance` API\n * between versions 1.x and 2.x.\n */\ninterface Templatizer {\n\n  /**\n   * Generates an anonymous `TemplateInstance` class (stored as `this.ctor`)\n   * for the provided template.  This method should be called once per\n   * template to prepare an element for stamping the template, followed\n   * by `stamp` to create new instances of the template.\n   *\n   * @param template Template to prepare\n   * @param mutableData When `true`, the generated class will skip\n   *   strict dirty-checking for objects and arrays (always consider them to\n   *   be \"dirty\"). Defaults to false.\n   */\n  templatize(template: HTMLTemplateElement, mutableData?: boolean): void;\n\n  /**\n   * Creates an instance of the template prepared by `templatize`.  The object\n   * returned is an instance of the anonymous class generated by `templatize`\n   * whose `root` property is a document fragment containing newly cloned\n   * template content, and which has property accessors corresponding to\n   * properties referenced in template bindings.\n   *\n   * @param model Object containing initial property values to\n   *   populate into the template bindings.\n   * @returns Returns the created instance of\n   * the template prepared by `templatize`.\n   */\n  stamp(model?: object|null): TemplateInstanceBase|null;\n\n  /**\n   * Returns the template \"model\" (`TemplateInstance`) associated with\n   * a given element, which serves as the binding scope for the template\n   * instance the element is contained in.  A template model should be used\n   * to manipulate data associated with this template instance.\n   *\n   * @param el Element for which to return a template model.\n   * @returns Model representing the binding scope for\n   *   the element.\n   */\n  modelForElement(el: HTMLElement|null): TemplateInstanceBase|null;\n}\n\ndeclare const Templatizer: object;\n"
  },
  {
    "path": "lib/legacy/templatizer-behavior.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport { TemplateInstanceBase, templatize, modelForElement } from '../utils/templatize.js'; // eslint-disable-line no-unused-vars\n\n/**\n * @typedef {{\n *   _templatizerTemplate: HTMLTemplateElement,\n *   _parentModel: boolean,\n *   _instanceProps: Object,\n *   _forwardHostPropV2: Function,\n *   _notifyInstancePropV2: Function,\n *   ctor: function(new:TemplateInstanceBase, Object=)\n * }}\n */\nlet TemplatizerUser; // eslint-disable-line\n\n/**\n * The `Templatizer` behavior adds methods to generate instances of\n * templates that are each managed by an anonymous `PropertyEffects`\n * instance where data-bindings in the stamped template content are bound to\n * accessors on itself.\n *\n * This behavior is provided in Polymer 2.x-3.x as a hybrid-element convenience\n * only.  For non-hybrid usage, the `Templatize` library\n * should be used instead.\n *\n * Example:\n *\n *     import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';\n *     // Get a template from somewhere, e.g. light DOM\n *     let template = this.querySelector('template');\n *     // Prepare the template\n *     this.templatize(template);\n *     // Instance the template with an initial data model\n *     let instance = this.stamp({myProp: 'initial'});\n *     // Insert the instance's DOM somewhere, e.g. light DOM\n *     dom(this).appendChild(instance.root);\n *     // Changing a property on the instance will propagate to bindings\n *     // in the template\n *     instance.myProp = 'new value';\n *\n * Users of `Templatizer` may need to implement the following abstract\n * API's to determine how properties and paths from the host should be\n * forwarded into to instances:\n *\n *     _forwardHostPropV2: function(prop, value)\n *\n * Likewise, users may implement these additional abstract API's to determine\n * how instance-specific properties that change on the instance should be\n * forwarded out to the host, if necessary.\n *\n *     _notifyInstancePropV2: function(inst, prop, value)\n *\n * In order to determine which properties are instance-specific and require\n * custom notification via `_notifyInstanceProp`, define an `_instanceProps`\n * object containing keys for each instance prop, for example:\n *\n *     _instanceProps: {\n *       item: true,\n *       index: true\n *     }\n *\n * Any properties used in the template that are not defined in _instanceProp\n * will be forwarded out to the Templatize `owner` automatically.\n *\n * Users may also implement the following abstract function to show or\n * hide any DOM generated using `stamp`:\n *\n *     _showHideChildren: function(shouldHide)\n *\n * Note that some callbacks are suffixed with `V2` in the Polymer 2.x behavior\n * as the implementations will need to differ from the callbacks required\n * by the 1.x Templatizer API due to changes in the `TemplateInstance` API\n * between versions 1.x and 2.x.\n *\n * @polymerBehavior\n */\nexport const Templatizer = {\n\n  /**\n   * Generates an anonymous `TemplateInstance` class (stored as `this.ctor`)\n   * for the provided template.  This method should be called once per\n   * template to prepare an element for stamping the template, followed\n   * by `stamp` to create new instances of the template.\n   *\n   * @param {!HTMLTemplateElement} template Template to prepare\n   * @param {boolean=} mutableData When `true`, the generated class will skip\n   *   strict dirty-checking for objects and arrays (always consider them to\n   *   be \"dirty\"). Defaults to false.\n   * @return {void}\n   * @this {TemplatizerUser}\n   */\n  templatize(template, mutableData) {\n    this._templatizerTemplate = template;\n    this.ctor =\n        templatize(template, /** @type {!Polymer_PropertyEffects} */ (this), {\n          mutableData: Boolean(mutableData),\n          parentModel: this._parentModel,\n          instanceProps: this._instanceProps,\n          forwardHostProp: this._forwardHostPropV2,\n          notifyInstanceProp: this._notifyInstancePropV2\n        });\n  },\n\n  /**\n   * Creates an instance of the template prepared by `templatize`.  The object\n   * returned is an instance of the anonymous class generated by `templatize`\n   * whose `root` property is a document fragment containing newly cloned\n   * template content, and which has property accessors corresponding to\n   * properties referenced in template bindings.\n   *\n   * @param {Object=} model Object containing initial property values to\n   *   populate into the template bindings.\n   * @return {TemplateInstanceBase} Returns the created instance of\n   * the template prepared by `templatize`.\n   * @this {TemplatizerUser}\n   */\n  stamp(model) {\n    return new this.ctor(model);\n  },\n\n  /**\n   * Returns the template \"model\" (`TemplateInstance`) associated with\n   * a given element, which serves as the binding scope for the template\n   * instance the element is contained in.  A template model should be used\n   * to manipulate data associated with this template instance.\n   *\n   * @param {HTMLElement} el Element for which to return a template model.\n   * @return {TemplateInstanceBase} Model representing the binding scope for\n   *   the element.\n   * @this {TemplatizerUser}\n   */\n  modelForElement(el) {\n    return modelForElement(this._templatizerTemplate, el);\n  }\n};\n"
  },
  {
    "path": "lib/mixins/dir-mixin.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n// tslint:disable:no-any describes the API as best we are able today\n\nimport {PropertyAccessors} from './property-accessors.js';\n\nimport {dedupingMixin} from '../utils/mixin.js';\n\nexport {DirMixin};\n\n\n/**\n * Element class mixin that allows elements to use the `:dir` CSS Selector to\n * have text direction specific styling.\n *\n * With this mixin, any stylesheet provided in the template will transform\n * `:dir` into `:host([dir])` and sync direction with the page via the\n * element's `dir` attribute.\n *\n * Elements can opt out of the global page text direction by setting the `dir`\n * attribute directly in `ready()` or in HTML.\n *\n * Caveats:\n * - Applications must set `<html dir=\"ltr\">` or `<html dir=\"rtl\">` to sync\n *   direction\n * - Automatic left-to-right or right-to-left styling is sync'd with the\n *   `<html>` element only.\n * - Changing `dir` at runtime is supported.\n * - Opting out of the global direction styling is permanent\n */\ndeclare function DirMixin<T extends new (...args: any[]) => {}>(base: T): T & DirMixinConstructor & PropertyAccessorsConstructor & PropertiesChangedConstructor;\n\nimport {PropertyAccessorsConstructor} from './property-accessors.js';\n\nimport {PropertiesChangedConstructor, PropertiesChanged} from './properties-changed.js';\n\ninterface DirMixinConstructor {\n  new(...args: any[]): DirMixin;\n\n  /**\n   * @param cssText .\n   * @param baseURI .\n   * @returns .\n   */\n  _processStyleText(cssText: string, baseURI: string): string;\n\n  /**\n   * Replace `:dir` in the given CSS text\n   *\n   * @param text CSS text to replace DIR\n   * @returns Modified CSS\n   */\n  _replaceDirInCssText(text: string): string;\n}\n\nexport {DirMixinConstructor};\n\ninterface DirMixin extends PropertyAccessors, PropertiesChanged {\n  ready(): void;\n  connectedCallback(): void;\n  disconnectedCallback(): void;\n}\n"
  },
  {
    "path": "lib/mixins/dir-mixin.js",
    "content": "/**\n * @fileoverview\n * @suppress {checkPrototypalTypes}\n * @license Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\n * This code may only be used under the BSD style license found at\n * http://polymer.github.io/LICENSE.txt The complete set of authors may be found\n * at http://polymer.github.io/AUTHORS.txt The complete set of contributors may\n * be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by\n * Google as part of the polymer project is also subject to an additional IP\n * rights grant found at http://polymer.github.io/PATENTS.txt\n */\nimport { PropertyAccessors } from './property-accessors.js';\n\nimport { dedupingMixin } from '../utils/mixin.js';\n\nconst HOST_DIR = /:host\\(:dir\\((ltr|rtl)\\)\\)/g;\nconst HOST_DIR_REPLACMENT = ':host([dir=\"$1\"])';\n\nconst EL_DIR = /([\\s\\w-#\\.\\[\\]\\*]*):dir\\((ltr|rtl)\\)/g;\nconst EL_DIR_REPLACMENT = ':host([dir=\"$2\"]) $1';\n\nconst DIR_CHECK = /:dir\\((?:ltr|rtl)\\)/;\n\nconst SHIM_SHADOW = Boolean(window['ShadyDOM'] && window['ShadyDOM']['inUse']);\n\n/**\n * @type {!Array<!Polymer_DirMixin>}\n */\nconst DIR_INSTANCES = [];\n\n/** @type {?MutationObserver} */\nlet observer = null;\n\nlet documentDir = '';\n\nfunction getRTL() {\n  documentDir = document.documentElement.getAttribute('dir');\n}\n\n/**\n * @param {!Polymer_DirMixin} instance Instance to set RTL status on\n */\nfunction setRTL(instance) {\n  if (!instance.__autoDirOptOut) {\n    const el = /** @type {!HTMLElement} */(instance);\n    el.setAttribute('dir', documentDir);\n  }\n}\n\nfunction updateDirection() {\n  getRTL();\n  documentDir = document.documentElement.getAttribute('dir');\n  for (let i = 0; i < DIR_INSTANCES.length; i++) {\n    setRTL(DIR_INSTANCES[i]);\n  }\n}\n\nfunction takeRecords() {\n  if (observer && observer.takeRecords().length) {\n    updateDirection();\n  }\n}\n\n/**\n * Element class mixin that allows elements to use the `:dir` CSS Selector to\n * have text direction specific styling.\n *\n * With this mixin, any stylesheet provided in the template will transform\n * `:dir` into `:host([dir])` and sync direction with the page via the\n * element's `dir` attribute.\n *\n * Elements can opt out of the global page text direction by setting the `dir`\n * attribute directly in `ready()` or in HTML.\n *\n * Caveats:\n * - Applications must set `<html dir=\"ltr\">` or `<html dir=\"rtl\">` to sync\n *   direction\n * - Automatic left-to-right or right-to-left styling is sync'd with the\n *   `<html>` element only.\n * - Changing `dir` at runtime is supported.\n * - Opting out of the global direction styling is permanent\n *\n * @mixinFunction\n * @polymer\n * @appliesMixin PropertyAccessors\n * @template T\n * @param {function(new:T)} superClass Class to apply mixin to.\n * @return {function(new:T)} superClass with mixin applied.\n */\nexport const DirMixin = dedupingMixin((base) => {\n\n  if (!SHIM_SHADOW) {\n    if (!observer) {\n      getRTL();\n      observer = new MutationObserver(updateDirection);\n      observer.observe(document.documentElement, {attributes: true, attributeFilter: ['dir']});\n    }\n  }\n\n  /**\n   * @constructor\n   * @implements {Polymer_PropertyAccessors}\n   * @private\n   */\n  const elementBase = PropertyAccessors(base);\n\n  /**\n   * @polymer\n   * @mixinClass\n   * @implements {Polymer_DirMixin}\n   */\n  class Dir extends elementBase {\n\n    /**\n     * @param {string} cssText .\n     * @param {string} baseURI .\n     * @return {string} .\n     * @suppress {missingProperties} Interfaces in closure do not inherit statics, but classes do\n     * @nocollapse\n     */\n    static _processStyleText(cssText, baseURI) {\n      // TODO(https://github.com/google/closure-compiler/issues/3240):\n      //     Change back to just super.methodCall()\n      cssText = elementBase._processStyleText.call(this, cssText, baseURI);\n      if (!SHIM_SHADOW && DIR_CHECK.test(cssText)) {\n        cssText = this._replaceDirInCssText(cssText);\n        this.__activateDir = true;\n      }\n      return cssText;\n    }\n\n    /**\n     * Replace `:dir` in the given CSS text\n     *\n     * @param {string} text CSS text to replace DIR\n     * @return {string} Modified CSS\n     * @nocollapse\n     */\n    static _replaceDirInCssText(text) {\n      let replacedText = text;\n      replacedText = replacedText.replace(HOST_DIR, HOST_DIR_REPLACMENT);\n      replacedText = replacedText.replace(EL_DIR, EL_DIR_REPLACMENT);\n      return replacedText;\n    }\n\n    constructor() {\n      super();\n      /** @type {boolean} */\n      this.__autoDirOptOut = false;\n    }\n\n    /**\n     * @override\n     * @suppress {invalidCasts} Closure doesn't understand that `this` is an\n     *     HTMLElement\n     * @return {void}\n     */\n    ready() {\n      super.ready();\n      this.__autoDirOptOut = /** @type {!HTMLElement} */(this).hasAttribute('dir');\n    }\n\n    /**\n     * @override\n     * @suppress {missingProperties} If it exists on elementBase, it can be\n     *   super'd\n     * @return {void}\n     */\n    connectedCallback() {\n      if (elementBase.prototype.connectedCallback) {\n        super.connectedCallback();\n      }\n      if (this.constructor.__activateDir) {\n        takeRecords();\n        DIR_INSTANCES.push(this);\n        setRTL(this);\n      }\n    }\n\n    /**\n     * @override\n     * @suppress {missingProperties} If it exists on elementBase, it can be\n     *   super'd\n     * @return {void}\n     */\n    disconnectedCallback() {\n      if (elementBase.prototype.disconnectedCallback) {\n        super.disconnectedCallback();\n      }\n      if (this.constructor.__activateDir) {\n        const idx = DIR_INSTANCES.indexOf(this);\n        if (idx > -1) {\n          DIR_INSTANCES.splice(idx, 1);\n        }\n      }\n    }\n  }\n\n  Dir.__activateDir = false;\n\n  return Dir;\n});\n"
  },
  {
    "path": "lib/mixins/disable-upgrade-mixin.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n// tslint:disable:no-any describes the API as best we are able today\n\nimport {ElementMixin} from './element-mixin.js';\n\nimport {dedupingMixin} from '../utils/mixin.js';\n\nexport {findObservedAttributesGetter};\n\ndeclare function findObservedAttributesGetter(): any;\n\nexport {DisableUpgradeMixin};\n\n\n/**\n * Element class mixin that allows the element to boot up in a non-enabled\n * state when the `disable-upgrade` attribute is present. This mixin is\n * designed to be used with element classes like PolymerElement that perform\n * initial startup work when they are first connected. When the\n * `disable-upgrade` attribute is removed, if the element is connected, it\n * boots up and \"enables\" as it otherwise would; if it is not connected, the\n * element boots up when it is next connected.\n *\n * Using `disable-upgrade` with PolymerElement prevents any data propagation\n * to the element, any element DOM from stamping, or any work done in\n * connected/disconnctedCallback from occuring, but it does not prevent work\n * done in the element constructor.\n *\n * Note, this mixin must be applied on top of any element class that\n * itself implements a `connectedCallback` so that it can control the work\n * done in `connectedCallback`. For example,\n *\n *     MyClass = DisableUpgradeMixin(class extends BaseClass {...});\n */\ndeclare function DisableUpgradeMixin<T extends new (...args: any[]) => {}>(base: T): T & DisableUpgradeMixinConstructor & ElementMixinConstructor & PropertyEffectsConstructor & TemplateStampConstructor & PropertyAccessorsConstructor & PropertiesChangedConstructor & PropertiesMixinConstructor;\n\nimport {ElementMixinConstructor} from './element-mixin.js';\n\nimport {PropertyEffectsConstructor, PropertyEffects} from './property-effects.js';\n\nimport {TemplateStampConstructor, TemplateStamp} from './template-stamp.js';\n\nimport {PropertyAccessorsConstructor, PropertyAccessors} from './property-accessors.js';\n\nimport {PropertiesChangedConstructor, PropertiesChanged} from './properties-changed.js';\n\nimport {PropertiesMixinConstructor, PropertiesMixin} from './properties-mixin.js';\n\ninterface DisableUpgradeMixinConstructor {\n  new(...args: any[]): DisableUpgradeMixin;\n}\n\nexport {DisableUpgradeMixinConstructor};\n\ninterface DisableUpgradeMixin extends ElementMixin, PropertyEffects, TemplateStamp, PropertyAccessors, PropertiesChanged, PropertiesMixin {\n  _initializeProperties(): void;\n  _enableProperties(): void;\n\n  /**\n   * @param name Attribute name.\n   * @param old The previous value for the attribute.\n   * @param value The new value for the attribute.\n   * @param namespace The XML namespace for the attribute.\n   */\n  attributeChangedCallback(name: string, old: string|null, value: string|null, namespace: string|null): void;\n  connectedCallback(): void;\n  disconnectedCallback(): void;\n  _canApplyPropertyDefault(property: any): any;\n}\n"
  },
  {
    "path": "lib/mixins/disable-upgrade-mixin.js",
    "content": "/**\n * @fileoverview\n * @suppress {checkPrototypalTypes}\n * @license Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\n * This code may only be used under the BSD style license found at\n * http://polymer.github.io/LICENSE.txt The complete set of authors may be found\n * at http://polymer.github.io/AUTHORS.txt The complete set of contributors may\n * be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by\n * Google as part of the polymer project is also subject to an additional IP\n * rights grant found at http://polymer.github.io/PATENTS.txt\n */\nimport { ElementMixin } from './element-mixin.js';\nimport { dedupingMixin } from '../utils/mixin.js';\nimport { wrap } from '../utils/wrap.js';\n\nconst DISABLED_ATTR = 'disable-upgrade';\n\nexport const findObservedAttributesGetter = (ctor) => {\n  while (ctor) {\n    const desc = Object.getOwnPropertyDescriptor(ctor, 'observedAttributes');\n    if (desc) {\n      return desc.get;\n    }\n    ctor = Object.getPrototypeOf(ctor.prototype).constructor;\n  }\n  return () => [];\n};\n\n/**\n * Element class mixin that allows the element to boot up in a non-enabled\n * state when the `disable-upgrade` attribute is present. This mixin is\n * designed to be used with element classes like PolymerElement that perform\n * initial startup work when they are first connected. When the\n * `disable-upgrade` attribute is removed, if the element is connected, it\n * boots up and \"enables\" as it otherwise would; if it is not connected, the\n * element boots up when it is next connected.\n *\n * Using `disable-upgrade` with PolymerElement prevents any data propagation\n * to the element, any element DOM from stamping, or any work done in\n * connected/disconnctedCallback from occuring, but it does not prevent work\n * done in the element constructor.\n *\n * Note, this mixin must be applied on top of any element class that\n * itself implements a `connectedCallback` so that it can control the work\n * done in `connectedCallback`. For example,\n *\n *     MyClass = DisableUpgradeMixin(class extends BaseClass {...});\n *\n * @mixinFunction\n * @polymer\n * @appliesMixin ElementMixin\n * @template T\n * @param {function(new:T)} superClass Class to apply mixin to.\n * @return {function(new:T)} superClass with mixin applied.\n */\nexport const DisableUpgradeMixin = dedupingMixin((base) => {\n  /**\n   * @constructor\n   * @implements {Polymer_ElementMixin}\n   * @extends {HTMLElement}\n   * @private\n   */\n  const superClass = ElementMixin(base);\n\n  // Work around for closure bug #126934458. Using `super` in a property\n  // getter does not work so instead we search the Base prototype for an\n  // implementation of observedAttributes so that we can override and call\n  // the `super` getter. Note, this is done one time ever because we assume\n  // that `Base` is always comes from `Polymer.LegacyElementMixn`.\n  let observedAttributesGetter = findObservedAttributesGetter(superClass);\n\n  /**\n   * @polymer\n   * @mixinClass\n   * @implements {Polymer_DisableUpgradeMixin}\n   */\n  class DisableUpgradeClass extends superClass {\n\n    constructor() {\n      super();\n      /** @type {boolean|undefined} */\n      this.__isUpgradeDisabled;\n    }\n\n    static get observedAttributes() {\n      return observedAttributesGetter.call(this).concat(DISABLED_ATTR);\n    }\n\n    // Prevent element from initializing properties when it's upgrade disabled.\n    /** @override */\n    _initializeProperties() {\n      if (this.hasAttribute(DISABLED_ATTR)) {\n        this.__isUpgradeDisabled = true;\n      } else {\n        super._initializeProperties();\n      }\n    }\n\n    // Prevent element from enabling properties when it's upgrade disabled.\n    // Normally overriding connectedCallback would be enough, but dom-* elements\n    /** @override */\n    _enableProperties() {\n      if (!this.__isUpgradeDisabled) {\n        super._enableProperties();\n      }\n    }\n\n    // If the element starts upgrade-disabled and a property is set for\n    // which an accessor exists, the default should not be applied.\n    // This additional check is needed because defaults are applied via\n    // `_initializeProperties` which is called after initial properties\n    // have been set when the element starts upgrade-disabled.\n    /** @override */\n    _canApplyPropertyDefault(property) {\n      return super._canApplyPropertyDefault(property) &&\n        !(this.__isUpgradeDisabled && this._isPropertyPending(property));\n    }\n\n    /**\n     * @override\n     * @param {string} name Attribute name.\n     * @param {?string} old The previous value for the attribute.\n     * @param {?string} value The new value for the attribute.\n     * @param {?string} namespace The XML namespace for the attribute.\n     * @return {void}\n     */\n    attributeChangedCallback(name, old, value, namespace) {\n      if (name == DISABLED_ATTR) {\n        // When disable-upgrade is removed, initialize properties and\n        // provoke connectedCallback if the element is already connected.\n        if (this.__isUpgradeDisabled && value == null) {\n          super._initializeProperties();\n          this.__isUpgradeDisabled = false;\n          if (wrap(this).isConnected) {\n            super.connectedCallback();\n          }\n        }\n      } else {\n        super.attributeChangedCallback(\n            name, old, value, /** @type {null|string} */ (namespace));\n      }\n    }\n\n    // Prevent element from connecting when it's upgrade disabled.\n    // This prevents user code in `attached` from being called.\n    /** @override */\n    connectedCallback() {\n      if (!this.__isUpgradeDisabled) {\n        super.connectedCallback();\n      }\n    }\n\n    // Prevent element from disconnecting when it's upgrade disabled.\n    // This avoids allowing user code `detached` from being called without a\n    // paired call to `attached`.\n    /** @override */\n    disconnectedCallback() {\n      if (!this.__isUpgradeDisabled) {\n        super.disconnectedCallback();\n      }\n    }\n\n  }\n\n  return DisableUpgradeClass;\n});\n"
  },
  {
    "path": "lib/mixins/element-mixin.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n// tslint:disable:no-any describes the API as best we are able today\n\nimport {dedupingMixin} from '../utils/mixin.js';\n\nimport {stylesFromTemplate, stylesFromModuleImports} from '../utils/style-gather.js';\n\nimport {pathFromUrl, resolveCss, resolveUrl} from '../utils/resolve-url.js';\n\nimport {DomModule} from '../elements/dom-module.js';\n\nimport {PropertyEffects} from './property-effects.js';\n\nimport {PropertiesMixin} from './properties-mixin.js';\n\nexport {ElementMixin};\n\n\n/**\n * Element class mixin that provides the core API for Polymer's meta-programming\n * features including template stamping, data-binding, attribute deserialization,\n * and property change observation.\n *\n * Subclassers may provide the following static getters to return metadata\n * used to configure Polymer's features for the class:\n *\n * - `static get is()`: When the template is provided via a `dom-module`,\n *   users should return the `dom-module` id from a static `is` getter.  If\n *   no template is needed or the template is provided directly via the\n *   `template` getter, there is no need to define `is` for the element.\n *\n * - `static get template()`: Users may provide the template directly (as\n *   opposed to via `dom-module`) by implementing a static `template` getter.\n *   The getter must return an `HTMLTemplateElement`.\n *\n * - `static get properties()`: Should return an object describing\n *   property-related metadata used by Polymer features (key: property name\n *   value: object containing property metadata). Valid keys in per-property\n *   metadata include:\n *   - `type` (String|Number|Object|Array|...): Used by\n *     `attributeChangedCallback` to determine how string-based attributes\n *     are deserialized to JavaScript property values.\n *   - `notify` (boolean): Causes a change in the property to fire a\n *     non-bubbling event called `<property>-changed`. Elements that have\n *     enabled two-way binding to the property use this event to observe changes.\n *   - `readOnly` (boolean): Creates a getter for the property, but no setter.\n *     To set a read-only property, use the private setter method\n *     `_setProperty(property, value)`.\n *   - `observer` (string): Observer method name that will be called when\n *     the property changes. The arguments of the method are\n *     `(value, previousValue)`.\n *   - `computed` (string): String describing method and dependent properties\n *     for computing the value of this property (e.g. `'computeFoo(bar, zot)'`).\n *     Computed properties are read-only by default and can only be changed\n *     via the return value of the computing method.\n *\n * - `static get observers()`: Array of strings describing multi-property\n *   observer methods and their dependent properties (e.g.\n *   `'observeABC(a, b, c)'`).\n *\n * The base class provides default implementations for the following standard\n * custom element lifecycle callbacks; users may override these, but should\n * call the super method to ensure\n * - `constructor`: Run when the element is created or upgraded\n * - `connectedCallback`: Run each time the element is connected to the\n *   document\n * - `disconnectedCallback`: Run each time the element is disconnected from\n *   the document\n * - `attributeChangedCallback`: Run each time an attribute in\n *   `observedAttributes` is set or removed (note: this element's default\n *   `observedAttributes` implementation will automatically return an array\n *   of dash-cased attributes based on `properties`)\n */\ndeclare function ElementMixin<T extends new (...args: any[]) => {}>(base: T): T & ElementMixinConstructor & PropertyEffectsConstructor & TemplateStampConstructor & PropertyAccessorsConstructor & PropertiesChangedConstructor & PropertiesMixinConstructor;\n\nimport {PropertyEffectsConstructor} from './property-effects.js';\n\nimport {TemplateStampConstructor, TemplateStamp} from './template-stamp.js';\n\nimport {PropertyAccessorsConstructor, PropertyAccessors} from './property-accessors.js';\n\nimport {PropertiesChangedConstructor, PropertiesChanged} from './properties-changed.js';\n\nimport {PropertiesMixinConstructor} from './properties-mixin.js';\n\ninterface ElementMixinConstructor {\n  new(...args: any[]): ElementMixin;\n\n  /**\n   * Overrides `PropertyEffects` to add map of dynamic functions on\n   * template info, for consumption by `PropertyEffects` template binding\n   * code. This map determines which method templates should have accessors\n   * created for them.\n   *\n   * @param template Template\n   * @param templateInfo Template metadata for current template\n   * @param nodeInfo Node metadata for current template.\n   * @returns .\n   */\n  _parseTemplateContent(template: HTMLTemplateElement, templateInfo: TemplateInfo, nodeInfo: NodeInfo): boolean;\n\n  /**\n   * Override of PropertiesChanged createProperties to create accessors\n   * and property effects for all of the properties.\n   *\n   * @param props .\n   */\n  createProperties(props: object): void;\n\n  /**\n   * Overrides `PropertyEffects` to warn on use of undeclared properties in\n   * template.\n   *\n   * @param templateInfo Template metadata to add effect to\n   * @param prop Property that should trigger the effect\n   * @param effect Effect metadata object\n   */\n  _addTemplatePropertyEffect(templateInfo: object|null, prop: string, effect?: object|null): void;\n\n  /**\n   * Override of PropertiesMixin _finalizeClass to create observers and\n   * find the template.\n   */\n  _finalizeClass(): void;\n  _prepareTemplate(): void;\n\n  /**\n   * Creates observers for the given `observers` array.\n   * Leverages `PropertyEffects` to create observers.\n   *\n   * @param observers Array of observer descriptors for\n   *   this class\n   * @param dynamicFns Object containing keys for any properties\n   *   that are functions and should trigger the effect when the function\n   *   reference is changed\n   */\n  createObservers(observers: object|null, dynamicFns: object|null): void;\n\n  /**\n   * Gather style text for a style element in the template.\n   *\n   * @param cssText Text containing styling to process\n   * @param baseURI Base URI to rebase CSS paths against\n   * @returns The processed CSS text\n   */\n  _processStyleText(cssText: string, baseURI: string): string;\n\n  /**\n   * Configures an element `proto` to function with a given `template`.\n   * The element name `is` and extends `ext` must be specified for ShadyCSS\n   * style scoping.\n   *\n   * @param is Tag name (or type extension name) for this element\n   */\n  _finalizeTemplate(is: string): void;\n}\n\nexport {ElementMixinConstructor};\n\ninterface ElementMixin extends PropertyEffects, TemplateStamp, PropertyAccessors, PropertiesChanged, PropertiesMixin {\n  _template: HTMLTemplateElement|null;\n  _importPath: string;\n  rootPath: string;\n  importPath: string;\n  root: StampedTemplate|HTMLElement|ShadowRoot|null;\n  $: {[key: string]: Element};\n\n  /**\n   * Stamps the element template.\n   */\n  ready(): void;\n\n  /**\n   * Overrides the default `PropertyAccessors` to ensure class\n   * metaprogramming related to property accessors and effects has\n   * completed (calls `finalize`).\n   *\n   * It also initializes any property defaults provided via `value` in\n   * `properties` metadata.\n   */\n  _initializeProperties(): void;\n\n  /**\n   * Implements `PropertyEffects`'s `_readyClients` call. Attaches\n   * element dom by calling `_attachDom` with the dom stamped from the\n   * element's template via `_stampTemplate`. Note that this allows\n   * client dom to be attached to the element prior to any observers\n   * running.\n   */\n  _readyClients(): void;\n\n  /**\n   * Provides a default implementation of the standard Custom Elements\n   * `connectedCallback`.\n   *\n   * The default implementation enables the property effects system and\n   * flushes any pending properties, and updates shimmed CSS properties\n   * when using the ShadyCSS scoping/custom properties polyfill.\n   */\n  connectedCallback(): void;\n\n  /**\n   * Determines if a property dfeault can be applied. For example, this\n   * prevents a default from being applied when a property that has no\n   * accessor is overridden by its host before upgrade (e.g. via a binding).\n   *\n   * @param property Name of the property\n   * @returns Returns true if the property default can be applied.\n   */\n  _canApplyPropertyDefault(property: string): boolean;\n\n  /**\n   * Attaches an element's stamped dom to itself. By default,\n   * this method creates a `shadowRoot` and adds the dom to it.\n   * However, this method may be overridden to allow an element\n   * to put its dom in another location.\n   *\n   * @param dom to attach to the element.\n   * @returns node to which the dom has been attached.\n   */\n  _attachDom(dom: StampedTemplate|null): ShadowRoot|null;\n\n  /**\n   * When using the ShadyCSS scoping and custom property shim, causes all\n   * shimmed styles in this element (and its subtree) to be updated\n   * based on current custom property values.\n   *\n   * The optional parameter overrides inline custom property styles with an\n   * object of properties where the keys are CSS properties, and the values\n   * are strings.\n   *\n   * Example: `this.updateStyles({'--color': 'blue'})`\n   *\n   * These properties are retained unless a value of `null` is set.\n   *\n   * Note: This function does not support updating CSS mixins.\n   * You can not dynamically change the value of an `@apply`.\n   *\n   * @param properties Bag of custom property key/values to\n   *   apply to this element.\n   */\n  updateStyles(properties?: object|null): void;\n\n  /**\n   * Rewrites a given URL relative to a base URL. The base URL defaults to\n   * the original location of the document containing the `dom-module` for\n   * this element. This method will return the same URL before and after\n   * bundling.\n   *\n   * Note that this function performs no resolution for URLs that start\n   * with `/` (absolute URLs) or `#` (hash identifiers).  For general purpose\n   * URL resolution, use `window.URL`.\n   *\n   * @param url URL to resolve.\n   * @param base Optional base URL to resolve against, defaults\n   * to the element's `importPath`\n   * @returns Rewritten URL relative to base\n   */\n  resolveUrl(url: string, base?: string): string;\n}\n\nexport {updateStyles};\n\n\n/**\n * When using the ShadyCSS scoping and custom property shim, causes all\n * shimmed `styles` (via `custom-style`) in the document (and its subtree)\n * to be updated based on current custom property values.\n *\n * The optional parameter overrides inline custom property styles with an\n * object of properties where the keys are CSS properties, and the values\n * are strings.\n *\n * Example: `updateStyles({'--color': 'blue'})`\n *\n * These properties are retained unless a value of `null` is set.\n */\ndeclare function updateStyles(props?: object|null): void;\n\nimport {TemplateInfo} from '../../interfaces';\n\nimport {NodeInfo} from '../../interfaces';\n\nimport {StampedTemplate} from '../../interfaces';\n"
  },
  {
    "path": "lib/mixins/element-mixin.js",
    "content": "/**\n * @fileoverview\n * @suppress {checkPrototypalTypes}\n * @license Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\n * This code may only be used under the BSD style license found at\n * http://polymer.github.io/LICENSE.txt The complete set of authors may be found\n * at http://polymer.github.io/AUTHORS.txt The complete set of contributors may\n * be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by\n * Google as part of the polymer project is also subject to an additional IP\n * rights grant found at http://polymer.github.io/PATENTS.txt\n */\nimport '../utils/boot.js';\n\nimport { rootPath, strictTemplatePolicy, allowTemplateFromDomModule, legacyOptimizations, legacyWarnings, syncInitialRender, supportsAdoptingStyleSheets, useAdoptedStyleSheetsWithBuiltCSS } from '../utils/settings.js';\nimport { dedupingMixin } from '../utils/mixin.js';\nimport { stylesFromTemplate, stylesFromModuleImports } from '../utils/style-gather.js';\nimport { pathFromUrl, resolveCss, resolveUrl } from '../utils/resolve-url.js';\nimport { DomModule } from '../elements/dom-module.js';\nimport { PropertyEffects } from './property-effects.js';\nimport { PropertiesMixin } from './properties-mixin.js';\nimport { wrap } from '../utils/wrap.js';\n\n/**\n * Current Polymer version in Semver notation.\n * @type {string} Semver notation of the current version of Polymer.\n */\nexport const version = '3.5.2';\n\nexport const builtCSS = window.ShadyCSS && window.ShadyCSS['cssBuild'];\n\n/**\n * Element class mixin that provides the core API for Polymer's meta-programming\n * features including template stamping, data-binding, attribute deserialization,\n * and property change observation.\n *\n * Subclassers may provide the following static getters to return metadata\n * used to configure Polymer's features for the class:\n *\n * - `static get is()`: When the template is provided via a `dom-module`,\n *   users should return the `dom-module` id from a static `is` getter.  If\n *   no template is needed or the template is provided directly via the\n *   `template` getter, there is no need to define `is` for the element.\n *\n * - `static get template()`: Users may provide the template directly (as\n *   opposed to via `dom-module`) by implementing a static `template` getter.\n *   The getter must return an `HTMLTemplateElement`.\n *\n * - `static get properties()`: Should return an object describing\n *   property-related metadata used by Polymer features (key: property name\n *   value: object containing property metadata). Valid keys in per-property\n *   metadata include:\n *   - `type` (String|Number|Object|Array|...): Used by\n *     `attributeChangedCallback` to determine how string-based attributes\n *     are deserialized to JavaScript property values.\n *   - `notify` (boolean): Causes a change in the property to fire a\n *     non-bubbling event called `<property>-changed`. Elements that have\n *     enabled two-way binding to the property use this event to observe changes.\n *   - `readOnly` (boolean): Creates a getter for the property, but no setter.\n *     To set a read-only property, use the private setter method\n *     `_setProperty(property, value)`.\n *   - `observer` (string): Observer method name that will be called when\n *     the property changes. The arguments of the method are\n *     `(value, previousValue)`.\n *   - `computed` (string): String describing method and dependent properties\n *     for computing the value of this property (e.g. `'computeFoo(bar, zot)'`).\n *     Computed properties are read-only by default and can only be changed\n *     via the return value of the computing method.\n *\n * - `static get observers()`: Array of strings describing multi-property\n *   observer methods and their dependent properties (e.g.\n *   `'observeABC(a, b, c)'`).\n *\n * The base class provides default implementations for the following standard\n * custom element lifecycle callbacks; users may override these, but should\n * call the super method to ensure\n * - `constructor`: Run when the element is created or upgraded\n * - `connectedCallback`: Run each time the element is connected to the\n *   document\n * - `disconnectedCallback`: Run each time the element is disconnected from\n *   the document\n * - `attributeChangedCallback`: Run each time an attribute in\n *   `observedAttributes` is set or removed (note: this element's default\n *   `observedAttributes` implementation will automatically return an array\n *   of dash-cased attributes based on `properties`)\n *\n * @mixinFunction\n * @polymer\n * @appliesMixin PropertyEffects\n * @appliesMixin PropertiesMixin\n * @property rootPath {string} Set to the value of `rootPath`,\n *   which defaults to the main document path\n * @property importPath {string} Set to the value of the class's static\n *   `importPath` property, which defaults to the path of this element's\n *   `dom-module` (when `is` is used), but can be overridden for other\n *   import strategies.\n * @summary Element class mixin that provides the core API for Polymer's\n * meta-programming features.\n * @template T\n * @param {function(new:T)} superClass Class to apply mixin to.\n * @return {function(new:T)} superClass with mixin applied.\n */\nexport const ElementMixin = dedupingMixin(base => {\n  /**\n   * @constructor\n   * @implements {Polymer_PropertyEffects}\n   * @implements {Polymer_PropertiesMixin}\n   * @extends {HTMLElement}\n   * @private\n   */\n  const polymerElementBase = PropertiesMixin(PropertyEffects(base));\n\n  /**\n   * Returns a list of properties with default values.\n   * This list is created as an optimization since it is a subset of\n   * the list returned from `_properties`.\n   * This list is used in `_initializeProperties` to set property defaults.\n   *\n   * @param {PolymerElementConstructor} constructor Element class\n   * @return {PolymerElementProperties} Flattened properties for this class\n   *   that have default values\n   * @private\n   */\n  function propertyDefaults(constructor) {\n    if (!constructor.hasOwnProperty(\n      JSCompiler_renameProperty('__propertyDefaults', constructor))) {\n      constructor.__propertyDefaults = null;\n      let props = constructor._properties;\n      for (let p in props) {\n        let info = props[p];\n        if ('value' in info) {\n          constructor.__propertyDefaults = constructor.__propertyDefaults || {};\n          constructor.__propertyDefaults[p] = info;\n        }\n      }\n    }\n    return constructor.__propertyDefaults;\n  }\n\n  /**\n   * Returns a memoized version of the `observers` array.\n   * @param {PolymerElementConstructor} constructor Element class\n   * @return {Array} Array containing own observers for the given class\n   * @protected\n   */\n  function ownObservers(constructor) {\n    if (!constructor.hasOwnProperty(\n      JSCompiler_renameProperty('__ownObservers', constructor))) {\n      constructor.__ownObservers =\n          constructor.hasOwnProperty(\n              JSCompiler_renameProperty('observers', constructor)) ?\n          /** @type {PolymerElementConstructor} */ (constructor).observers :\n          null;\n    }\n    return constructor.__ownObservers;\n  }\n\n  /**\n   * Creates effects for a property.\n   *\n   * Note, once a property has been set to\n   * `readOnly`, `computed`, `reflectToAttribute`, or `notify`\n   * these values may not be changed. For example, a subclass cannot\n   * alter these settings. However, additional `observers` may be added\n   * by subclasses.\n   *\n   * The info object should contain property metadata as follows:\n   *\n   * * `type`: {function} type to which an attribute matching the property\n   * is deserialized. Note the property is camel-cased from a dash-cased\n   * attribute. For example, 'foo-bar' attribute is deserialized to a\n   * property named 'fooBar'.\n   *\n   * * `readOnly`: {boolean} creates a readOnly property and\n   * makes a private setter for the private of the form '_setFoo' for a\n   * property 'foo',\n   *\n   * * `computed`: {string} creates a computed property. A computed property\n   * is also automatically set to `readOnly: true`. The value is calculated\n   * by running a method and arguments parsed from the given string. For\n   * example 'compute(foo)' will compute a given property when the\n   * 'foo' property changes by executing the 'compute' method. This method\n   * must return the computed value.\n   *\n   * * `reflectToAttribute`: {boolean} If true, the property value is reflected\n   * to an attribute of the same name. Note, the attribute is dash-cased\n   * so a property named 'fooBar' is reflected as 'foo-bar'.\n   *\n   * * `notify`: {boolean} sends a non-bubbling notification event when\n   * the property changes. For example, a property named 'foo' sends an\n   * event named 'foo-changed' with `event.detail` set to the value of\n   * the property.\n   *\n   * * observer: {string} name of a method that runs when the property\n   * changes. The arguments of the method are (value, previousValue).\n   *\n   * Note: Users may want control over modifying property\n   * effects via subclassing. For example, a user might want to make a\n   * reflectToAttribute property not do so in a subclass. We've chosen to\n   * disable this because it leads to additional complication.\n   * For example, a readOnly effect generates a special setter. If a subclass\n   * disables the effect, the setter would fail unexpectedly.\n   * Based on feedback, we may want to try to make effects more malleable\n   * and/or provide an advanced api for manipulating them.\n   *\n   * @param {!PolymerElement} proto Element class prototype to add accessors\n   *   and effects to\n   * @param {string} name Name of the property.\n   * @param {Object} info Info object from which to create property effects.\n   * Supported keys:\n   * @param {Object} allProps Flattened map of all properties defined in this\n   *   element (including inherited properties)\n   * @return {void}\n   * @private\n   */\n  function createPropertyFromConfig(proto, name, info, allProps) {\n    // computed forces readOnly...\n    if (info.computed) {\n      info.readOnly = true;\n    }\n    // Note, since all computed properties are readOnly, this prevents\n    // adding additional computed property effects (which leads to a confusing\n    // setup where multiple triggers for setting a property)\n    // While we do have `hasComputedEffect` this is set on the property's\n    // dependencies rather than itself.\n    if (info.computed) {\n      if (proto._hasReadOnlyEffect(name)) {\n        console.warn(`Cannot redefine computed property '${name}'.`);\n      } else {\n        proto._createComputedProperty(name, info.computed, allProps);\n      }\n    }\n    if (info.readOnly && !proto._hasReadOnlyEffect(name)) {\n      proto._createReadOnlyProperty(name, !info.computed);\n    } else if (info.readOnly === false && proto._hasReadOnlyEffect(name)) {\n      console.warn(`Cannot make readOnly property '${name}' non-readOnly.`);\n    }\n    if (info.reflectToAttribute && !proto._hasReflectEffect(name)) {\n      proto._createReflectedProperty(name);\n    } else if (info.reflectToAttribute === false && proto._hasReflectEffect(name)) {\n      console.warn(`Cannot make reflected property '${name}' non-reflected.`);\n    }\n    if (info.notify && !proto._hasNotifyEffect(name)) {\n      proto._createNotifyingProperty(name);\n    } else if (info.notify === false && proto._hasNotifyEffect(name)) {\n      console.warn(`Cannot make notify property '${name}' non-notify.`);\n    }\n    // always add observer\n    if (info.observer) {\n      proto._createPropertyObserver(name, info.observer, allProps[info.observer]);\n    }\n    // always create the mapping from attribute back to property for deserialization.\n    proto._addPropertyToAttributeMap(name);\n  }\n\n  /**\n   * Process all style elements in the element template. Styles with the\n   * `include` attribute are processed such that any styles in\n   * the associated \"style modules\" are included in the element template.\n   * @param {PolymerElementConstructor} klass Element class\n   * @param {!HTMLTemplateElement} template Template to process\n   * @param {string} is Name of element\n   * @param {string} baseURI Base URI for element\n   * @private\n   */\n  function processElementStyles(klass, template, is, baseURI) {\n    if (!builtCSS) {\n      const templateStyles = template.content.querySelectorAll('style');\n      const stylesWithImports = stylesFromTemplate(template);\n      // insert styles from <link rel=\"import\" type=\"css\"> at the top of the template\n      const linkedStyles = stylesFromModuleImports(is);\n      const firstTemplateChild = template.content.firstElementChild;\n      for (let idx = 0; idx < linkedStyles.length; idx++) {\n        let s = linkedStyles[idx];\n        s.textContent = klass._processStyleText(s.textContent, baseURI);\n        template.content.insertBefore(s, firstTemplateChild);\n      }\n      // keep track of the last \"concrete\" style in the template we have encountered\n      let templateStyleIndex = 0;\n      // ensure all gathered styles are actually in this template.\n      for (let i = 0; i < stylesWithImports.length; i++) {\n        let s = stylesWithImports[i];\n        let templateStyle = templateStyles[templateStyleIndex];\n        // if the style is not in this template, it's been \"included\" and\n        // we put a clone of it in the template before the style that included it\n        if (templateStyle !== s) {\n          s = s.cloneNode(true);\n          templateStyle.parentNode.insertBefore(s, templateStyle);\n        } else {\n          templateStyleIndex++;\n        }\n        s.textContent = klass._processStyleText(s.textContent, baseURI);\n      }\n    }\n    if (window.ShadyCSS) {\n      window.ShadyCSS.prepareTemplate(template, is);\n    }\n    // Support for `adoptedStylesheets` relies on using native Shadow DOM\n    // and built CSS. Built CSS is required because runtime transformation of\n    // `@apply` is not supported. This is because ShadyCSS relies on being able\n    // to update a `style` element in the element template and this is\n    // removed when using `adoptedStyleSheets`.\n    // Note, it would be more efficient to allow style includes to become\n    // separate stylesheets; however, because of `@apply` these are\n    // potentially not shareable and sharing the ones that could be shared\n    // would require some coordination. To keep it simple, all the includes\n    // and styles are collapsed into a single shareable stylesheet.\n    if (useAdoptedStyleSheetsWithBuiltCSS && builtCSS &&\n        supportsAdoptingStyleSheets) {\n      // Remove styles in template and make a shareable stylesheet\n      const styles = template.content.querySelectorAll('style');\n      if (styles) {\n        let css = '';\n        Array.from(styles).forEach(s => {\n          css += s.textContent;\n          s.parentNode.removeChild(s);\n        });\n        klass._styleSheet = new CSSStyleSheet();\n        klass._styleSheet.replaceSync(css);\n      }\n    }\n  }\n\n  /**\n   * Look up template from dom-module for element\n   *\n   * @param {string} is Element name to look up\n   * @return {?HTMLTemplateElement|undefined} Template found in dom module, or\n   *   undefined if not found\n   * @protected\n   */\n  function getTemplateFromDomModule(is) {\n    let template = null;\n    // Under strictTemplatePolicy in 3.x+, dom-module lookup is only allowed\n    // when opted-in via allowTemplateFromDomModule\n    if (is && (!strictTemplatePolicy || allowTemplateFromDomModule)) {\n      template = /** @type {?HTMLTemplateElement} */ (\n          DomModule.import(is, 'template'));\n      // Under strictTemplatePolicy, require any element with an `is`\n      // specified to have a dom-module\n      if (strictTemplatePolicy && !template) {\n        throw new Error(`strictTemplatePolicy: expecting dom-module or null template for ${is}`);\n      }\n    }\n    return template;\n  }\n\n  /**\n   * @polymer\n   * @mixinClass\n   * @unrestricted\n   * @implements {Polymer_ElementMixin}\n   * @extends {polymerElementBase}\n   */\n  class PolymerElement extends polymerElementBase {\n\n    /**\n     * Current Polymer version in Semver notation.\n     * @type {string} Semver notation of the current version of Polymer.\n     * @nocollapse\n     */\n    static get polymerElementVersion() {\n      return version;\n    }\n\n    /**\n     * Override of PropertiesMixin _finalizeClass to create observers and\n     * find the template.\n     * @return {void}\n     * @protected\n     * @suppress {missingProperties} Interfaces in closure do not inherit statics, but classes do\n     * @nocollapse\n     */\n    static _finalizeClass() {\n      // TODO(https://github.com/google/closure-compiler/issues/3240):\n      //     Change back to just super.methodCall()\n      polymerElementBase._finalizeClass.call(this);\n      const observers = ownObservers(this);\n      if (observers) {\n        this.createObservers(observers, this._properties);\n      }\n      this._prepareTemplate();\n    }\n\n    /** @nocollapse */\n    static _prepareTemplate() {\n      // note: create \"working\" template that is finalized at instance time\n      let template = /** @type {PolymerElementConstructor} */ (this).template;\n      if (template) {\n        if (typeof template === 'string') {\n          console.error('template getter must return HTMLTemplateElement');\n          template = null;\n        } else if (!legacyOptimizations) {\n          template = template.cloneNode(true);\n        }\n      }\n\n      /** @override */\n      this.prototype._template = template;\n    }\n\n    /**\n     * Override of PropertiesChanged createProperties to create accessors\n     * and property effects for all of the properties.\n     * @param {!Object} props .\n     * @return {void}\n     * @protected\n     * @nocollapse\n     */\n    static createProperties(props) {\n      for (let p in props) {\n        createPropertyFromConfig(\n            /** @type {?} */ (this.prototype), p, props[p], props);\n      }\n    }\n\n    /**\n     * Creates observers for the given `observers` array.\n     * Leverages `PropertyEffects` to create observers.\n     * @param {Object} observers Array of observer descriptors for\n     *   this class\n     * @param {Object} dynamicFns Object containing keys for any properties\n     *   that are functions and should trigger the effect when the function\n     *   reference is changed\n     * @return {void}\n     * @protected\n     * @nocollapse\n     */\n    static createObservers(observers, dynamicFns) {\n      const proto = this.prototype;\n      for (let i=0; i < observers.length; i++) {\n        proto._createMethodObserver(observers[i], dynamicFns);\n      }\n    }\n\n    /**\n     * Returns the template that will be stamped into this element's shadow root.\n     *\n     * If a `static get is()` getter is defined, the default implementation will\n     * return the first `<template>` in a `dom-module` whose `id` matches this\n     * element's `is` (note that a `_template` property on the class prototype\n     * takes precedence over the `dom-module` template, to maintain legacy\n     * element semantics; a subclass will subsequently fall back to its super\n     * class template if neither a `prototype._template` or a `dom-module` for\n     * the class's `is` was found).\n     *\n     * Users may override this getter to return an arbitrary template\n     * (in which case the `is` getter is unnecessary). The template returned\n     * must be an `HTMLTemplateElement`.\n     *\n     * Note that when subclassing, if the super class overrode the default\n     * implementation and the subclass would like to provide an alternate\n     * template via a `dom-module`, it should override this getter and\n     * return `DomModule.import(this.is, 'template')`.\n     *\n     * If a subclass would like to modify the super class template, it should\n     * clone it rather than modify it in place.  If the getter does expensive\n     * work such as cloning/modifying a template, it should memoize the\n     * template for maximum performance:\n     *\n     *   let memoizedTemplate;\n     *   class MySubClass extends MySuperClass {\n     *     static get template() {\n     *       if (!memoizedTemplate) {\n     *         memoizedTemplate = super.template.cloneNode(true);\n     *         let subContent = document.createElement('div');\n     *         subContent.textContent = 'This came from MySubClass';\n     *         memoizedTemplate.content.appendChild(subContent);\n     *       }\n     *       return memoizedTemplate;\n     *     }\n     *   }\n     *\n     * @return {!HTMLTemplateElement|string} Template to be stamped\n     * @nocollapse\n     */\n    static get template() {\n      // Explanation of template-related properties:\n      // - constructor.template (this getter): the template for the class.\n      //     This can come from the prototype (for legacy elements), from a\n      //     dom-module, or from the super class's template (or can be overridden\n      //     altogether by the user)\n      // - constructor._template: memoized version of constructor.template\n      // - prototype._template: working template for the element, which will be\n      //     parsed and modified in place. It is a cloned version of\n      //     constructor.template, saved in _finalizeClass(). Note that before\n      //     this getter is called, for legacy elements this could be from a\n      //     _template field on the info object passed to Polymer(), a behavior,\n      //     or set in registered(); once the static getter runs, a clone of it\n      //     will overwrite it on the prototype as the working template.\n      if (!this.hasOwnProperty(JSCompiler_renameProperty('_template', this))) {\n        let protoTemplate = this.prototype.hasOwnProperty(\n          JSCompiler_renameProperty('_template', this.prototype)) ?\n          this.prototype._template : undefined;\n        // Accept a function for the legacy Polymer({_template:...}) field for\n        // lazy parsing\n        if (typeof protoTemplate === 'function') {\n          protoTemplate = protoTemplate();\n        }\n        this._template =\n          // If user has put template on prototype (e.g. in legacy via registered\n          // callback or info object), prefer that first. Note that `null` is\n          // used as a sentinel to indicate \"no template\" and can be used to\n          // override a super template, whereas `undefined` is used as a\n          // sentinel to mean \"fall-back to default template lookup\" via\n          // dom-module and/or super.template.\n          protoTemplate !== undefined ? protoTemplate :\n          // Look in dom-module associated with this element's is\n          ((this.hasOwnProperty(JSCompiler_renameProperty('is', this)) &&\n          (getTemplateFromDomModule(/** @type {PolymerElementConstructor}*/ (this).is))) ||\n          // Next look for superclass template (call the super impl this\n          // way so that `this` points to the superclass)\n          Object.getPrototypeOf(/** @type {PolymerElementConstructor}*/ (this).prototype).constructor.template);\n      }\n      return this._template;\n    }\n\n    /**\n     * Set the template.\n     *\n     * @param {!HTMLTemplateElement|string} value Template to set.\n     * @nocollapse\n     */\n    static set template(value) {\n      this._template = value;\n    }\n\n    /**\n     * Path matching the url from which the element was imported.\n     *\n     * This path is used to resolve url's in template style cssText.\n     * The `importPath` property is also set on element instances and can be\n     * used to create bindings relative to the import path.\n     *\n     * For elements defined in ES modules, users should implement\n     * `static get importMeta() { return import.meta; }`, and the default\n     * implementation of `importPath` will  return `import.meta.url`'s path.\n     * For elements defined in HTML imports, this getter will return the path\n     * to the document containing a `dom-module` element matching this\n     * element's static `is` property.\n     *\n     * Note, this path should contain a trailing `/`.\n     *\n     * @return {string} The import path for this element class\n     * @suppress {missingProperties}\n     * @nocollapse\n     */\n    static get importPath() {\n      if (!this.hasOwnProperty(JSCompiler_renameProperty('_importPath', this))) {\n        const meta = this.importMeta;\n        if (meta) {\n          this._importPath = pathFromUrl(meta.url);\n        } else {\n          const module = DomModule.import(/** @type {PolymerElementConstructor} */ (this).is);\n          this._importPath = (module && module.assetpath) ||\n            Object.getPrototypeOf(/** @type {PolymerElementConstructor}*/ (this).prototype).constructor.importPath;\n        }\n      }\n      return this._importPath;\n    }\n\n    constructor() {\n      super();\n      /** @type {HTMLTemplateElement} */\n      this._template;\n      /** @type {string} */\n      this._importPath;\n      /** @type {string} */\n      this.rootPath;\n      /** @type {string} */\n      this.importPath;\n      /** @type {StampedTemplate | HTMLElement | ShadowRoot} */\n      this.root;\n      /** @type {!Object<string, !Element>} */\n      this.$;\n    }\n\n    /**\n     * Overrides the default `PropertyAccessors` to ensure class\n     * metaprogramming related to property accessors and effects has\n     * completed (calls `finalize`).\n     *\n     * It also initializes any property defaults provided via `value` in\n     * `properties` metadata.\n     *\n     * @return {void}\n     * @override\n     * @suppress {invalidCasts,missingProperties} go/missingfnprops\n     */\n    _initializeProperties() {\n      this.constructor.finalize();\n      // note: finalize template when we have access to `localName` to\n      // avoid dependence on `is` for polyfilling styling.\n      this.constructor._finalizeTemplate(/** @type {!HTMLElement} */(this).localName);\n      super._initializeProperties();\n      // set path defaults\n      this.rootPath = rootPath;\n      this.importPath = this.constructor.importPath;\n      // apply property defaults...\n      let p$ = propertyDefaults(this.constructor);\n      if (!p$) {\n        return;\n      }\n      for (let p in p$) {\n        let info = p$[p];\n        if (this._canApplyPropertyDefault(p)) {\n          let value = typeof info.value == 'function' ?\n            info.value.call(this) :\n            info.value;\n          // Set via `_setProperty` if there is an accessor, to enable\n          // initializing readOnly property defaults\n          if (this._hasAccessor(p)) {\n            this._setPendingProperty(p, value, true);\n          } else {\n            this[p] = value;\n          }\n        }\n      }\n    }\n\n    /**\n     * Determines if a property dfeault can be applied. For example, this\n     * prevents a default from being applied when a property that has no\n     * accessor is overridden by its host before upgrade (e.g. via a binding).\n     * @override\n     * @param {string} property Name of the property\n     * @return {boolean} Returns true if the property default can be applied.\n     */\n    _canApplyPropertyDefault(property) {\n      return !this.hasOwnProperty(property);\n    }\n\n    /**\n     * Gather style text for a style element in the template.\n     *\n     * @param {string} cssText Text containing styling to process\n     * @param {string} baseURI Base URI to rebase CSS paths against\n     * @return {string} The processed CSS text\n     * @protected\n     * @nocollapse\n     */\n    static _processStyleText(cssText, baseURI) {\n      return resolveCss(cssText, baseURI);\n    }\n\n    /**\n    * Configures an element `proto` to function with a given `template`.\n    * The element name `is` and extends `ext` must be specified for ShadyCSS\n    * style scoping.\n    *\n    * @param {string} is Tag name (or type extension name) for this element\n    * @return {void}\n    * @protected\n    * @nocollapse\n    */\n    static _finalizeTemplate(is) {\n      /** @const {HTMLTemplateElement} */\n      const template = this.prototype._template;\n      if (template && !template.__polymerFinalized) {\n        template.__polymerFinalized = true;\n        const importPath = this.importPath;\n        const baseURI = importPath ? resolveUrl(importPath) : '';\n        // e.g. support `include=\"module-name\"`, and ShadyCSS\n        processElementStyles(this, template, is, baseURI);\n        this.prototype._bindTemplate(template);\n      }\n    }\n\n    /**\n     * Provides a default implementation of the standard Custom Elements\n     * `connectedCallback`.\n     *\n     * The default implementation enables the property effects system and\n     * flushes any pending properties, and updates shimmed CSS properties\n     * when using the ShadyCSS scoping/custom properties polyfill.\n     *\n     * @override\n     * @suppress {missingProperties, invalidCasts} Super may or may not\n     *     implement the callback\n     * @return {void}\n     */\n    connectedCallback() {\n      if (window.ShadyCSS && this._template) {\n        window.ShadyCSS.styleElement(/** @type {!HTMLElement} */(this));\n      }\n      super.connectedCallback();\n    }\n\n    /**\n     * Stamps the element template.\n     *\n     * @return {void}\n     * @override\n     */\n    ready() {\n      if (this._template) {\n        this.root = this._stampTemplate(this._template);\n        this.$ = this.root.$;\n      }\n      super.ready();\n    }\n\n    /**\n     * Implements `PropertyEffects`'s `_readyClients` call. Attaches\n     * element dom by calling `_attachDom` with the dom stamped from the\n     * element's template via `_stampTemplate`. Note that this allows\n     * client dom to be attached to the element prior to any observers\n     * running.\n     *\n     * @return {void}\n     * @override\n     */\n    _readyClients() {\n      if (this._template) {\n        this.root = this._attachDom(/** @type {StampedTemplate} */(this.root));\n      }\n      // The super._readyClients here sets the clients initialized flag.\n      // We must wait to do this until after client dom is created/attached\n      // so that this flag can be checked to prevent notifications fired\n      // during this process from being handled before clients are ready.\n      super._readyClients();\n    }\n\n\n    /**\n     * Attaches an element's stamped dom to itself. By default,\n     * this method creates a `shadowRoot` and adds the dom to it.\n     * However, this method may be overridden to allow an element\n     * to put its dom in another location.\n     *\n     * @override\n     * @throws {Error}\n     * @suppress {missingReturn}\n     * @param {StampedTemplate} dom to attach to the element.\n     * @return {ShadowRoot} node to which the dom has been attached.\n     */\n    _attachDom(dom) {\n      const n = wrap(this);\n      if (n.attachShadow) {\n        if (dom) {\n          if (!n.shadowRoot) {\n            n.attachShadow({mode: 'open', shadyUpgradeFragment: dom});\n            n.shadowRoot.appendChild(dom);\n            // When `adoptedStyleSheets` is supported a stylesheet is made\n            // available on the element constructor.\n            if (this.constructor._styleSheet) {\n              n.shadowRoot.adoptedStyleSheets = [this.constructor._styleSheet];\n            }\n          }\n          if (syncInitialRender && window.ShadyDOM) {\n            window.ShadyDOM.flushInitial(n.shadowRoot);\n          }\n          return n.shadowRoot;\n        }\n        return null;\n      } else {\n        throw new Error('ShadowDOM not available. ' +\n          // TODO(sorvell): move to compile-time conditional when supported\n        'PolymerElement can create dom as children instead of in ' +\n        'ShadowDOM by setting `this.root = this;\\` before \\`ready\\`.');\n      }\n    }\n\n    /**\n     * When using the ShadyCSS scoping and custom property shim, causes all\n     * shimmed styles in this element (and its subtree) to be updated\n     * based on current custom property values.\n     *\n     * The optional parameter overrides inline custom property styles with an\n     * object of properties where the keys are CSS properties, and the values\n     * are strings.\n     *\n     * Example: `this.updateStyles({'--color': 'blue'})`\n     *\n     * These properties are retained unless a value of `null` is set.\n     *\n     * Note: This function does not support updating CSS mixins.\n     * You can not dynamically change the value of an `@apply`.\n     *\n     * @override\n     * @param {Object=} properties Bag of custom property key/values to\n     *   apply to this element.\n     * @return {void}\n     * @suppress {invalidCasts}\n     */\n    updateStyles(properties) {\n      if (window.ShadyCSS) {\n        window.ShadyCSS.styleSubtree(/** @type {!HTMLElement} */(this), properties);\n      }\n    }\n\n    /**\n     * Rewrites a given URL relative to a base URL. The base URL defaults to\n     * the original location of the document containing the `dom-module` for\n     * this element. This method will return the same URL before and after\n     * bundling.\n     *\n     * Note that this function performs no resolution for URLs that start\n     * with `/` (absolute URLs) or `#` (hash identifiers).  For general purpose\n     * URL resolution, use `window.URL`.\n     *\n     * @override\n     * @param {string} url URL to resolve.\n     * @param {string=} base Optional base URL to resolve against, defaults\n     * to the element's `importPath`\n     * @return {string} Rewritten URL relative to base\n     */\n    resolveUrl(url, base) {\n      if (!base && this.importPath) {\n        base = resolveUrl(this.importPath);\n      }\n      return resolveUrl(url, base);\n    }\n\n    /**\n     * Overrides `PropertyEffects` to add map of dynamic functions on\n     * template info, for consumption by `PropertyEffects` template binding\n     * code. This map determines which method templates should have accessors\n     * created for them.\n     *\n     * @param {!HTMLTemplateElement} template Template\n     * @param {!TemplateInfo} templateInfo Template metadata for current template\n     * @param {!NodeInfo} nodeInfo Node metadata for current template.\n     * @return {boolean} .\n     * @suppress {missingProperties} Interfaces in closure do not inherit statics, but classes do\n     * @nocollapse\n     */\n    static _parseTemplateContent(template, templateInfo, nodeInfo) {\n      templateInfo.dynamicFns = templateInfo.dynamicFns || this._properties;\n      // TODO(https://github.com/google/closure-compiler/issues/3240):\n      //     Change back to just super.methodCall()\n      return polymerElementBase._parseTemplateContent.call(\n        this, template, templateInfo, nodeInfo);\n    }\n\n    /**\n     * Overrides `PropertyEffects` to warn on use of undeclared properties in\n     * template.\n     *\n     * @param {Object} templateInfo Template metadata to add effect to\n     * @param {string} prop Property that should trigger the effect\n     * @param {Object=} effect Effect metadata object\n     * @return {void}\n     * @protected\n     * @suppress {missingProperties} Interfaces in closure do not inherit statics, but classes do\n     * @nocollapse\n     */\n    static _addTemplatePropertyEffect(templateInfo, prop, effect) {\n      // Warn if properties are used in template without being declared.\n      // Properties must be listed in `properties` to be included in\n      // `observedAttributes` since CE V1 reads that at registration time, and\n      // since we want to keep template parsing lazy, we can't automatically\n      // add undeclared properties used in templates to `observedAttributes`.\n      // The warning is only enabled in `legacyOptimizations` mode, since\n      // we don't want to spam existing users who might have adopted the\n      // shorthand when attribute deserialization is not important.\n      if (legacyWarnings && !(prop in this._properties) &&\n          // Methods used in templates with no dependencies (or only literal\n          // dependencies) become accessors with template effects; ignore these\n          !(effect.info.part.signature && effect.info.part.signature.static) &&\n          // Warnings for bindings added to nested templates are handled by\n          // templatizer so ignore both the host-to-template bindings\n          // (`hostProp`) and TemplateInstance-to-child bindings\n          // (`nestedTemplate`)\n          !effect.info.part.hostProp && !templateInfo.nestedTemplate) {\n        console.warn(`Property '${prop}' used in template but not declared in 'properties'; ` +\n          `attribute will not be observed.`);\n      }\n      // TODO(https://github.com/google/closure-compiler/issues/3240):\n      //     Change back to just super.methodCall()\n      return polymerElementBase._addTemplatePropertyEffect.call(\n        this, templateInfo, prop, effect);\n    }\n\n  }\n\n  return PolymerElement;\n});\n\n/**\n * When using the ShadyCSS scoping and custom property shim, causes all\n * shimmed `styles` (via `custom-style`) in the document (and its subtree)\n * to be updated based on current custom property values.\n *\n * The optional parameter overrides inline custom property styles with an\n * object of properties where the keys are CSS properties, and the values\n * are strings.\n *\n * Example: `updateStyles({'--color': 'blue'})`\n *\n * These properties are retained unless a value of `null` is set.\n *\n * @param {Object=} props Bag of custom property key/values to\n *   apply to the document.\n * @return {void}\n */\nexport const updateStyles = function(props) {\n  if (window.ShadyCSS) {\n    window.ShadyCSS.styleDocument(props);\n  }\n};\n"
  },
  {
    "path": "lib/mixins/gesture-event-listeners.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n// tslint:disable:no-any describes the API as best we are able today\n\nimport {dedupingMixin} from '../utils/mixin.js';\n\nimport {addListener, removeListener} from '../utils/gestures.js';\n\nexport {GestureEventListeners};\n\n\n/**\n * Element class mixin that provides API for adding Polymer's cross-platform\n * gesture events to nodes.\n *\n * The API is designed to be compatible with override points implemented\n * in `TemplateStamp` such that declarative event listeners in\n * templates will support gesture events when this mixin is applied along with\n * `TemplateStamp`.\n */\ndeclare function GestureEventListeners<T extends new (...args: any[]) => {}>(base: T): T & GestureEventListenersConstructor;\n\ninterface GestureEventListenersConstructor {\n  new(...args: any[]): GestureEventListeners;\n}\n\nexport {GestureEventListenersConstructor};\n\ninterface GestureEventListeners {\n\n  /**\n   * Add the event listener to the node if it is a gestures event.\n   *\n   * @param node Node to add event listener to\n   * @param eventName Name of event\n   * @param handler Listener function to add\n   */\n  _addEventListenerToNode(node: EventTarget, eventName: string, handler: (p0: Event) => void): void;\n\n  /**\n   * Remove the event listener to the node if it is a gestures event.\n   *\n   * @param node Node to remove event listener from\n   * @param eventName Name of event\n   * @param handler Listener function to remove\n   */\n  _removeEventListenerFromNode(node: EventTarget, eventName: string, handler: (p0: Event) => void): void;\n}\n"
  },
  {
    "path": "lib/mixins/gesture-event-listeners.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport '../utils/boot.js';\n\nimport { dedupingMixin } from '../utils/mixin.js';\nimport { addListener, removeListener } from '../utils/gestures.js';\n\n/**\n * Element class mixin that provides API for adding Polymer's cross-platform\n * gesture events to nodes.\n *\n * The API is designed to be compatible with override points implemented\n * in `TemplateStamp` such that declarative event listeners in\n * templates will support gesture events when this mixin is applied along with\n * `TemplateStamp`.\n *\n * @mixinFunction\n * @polymer\n * @summary Element class mixin that provides API for adding Polymer's\n *   cross-platform gesture events to nodes\n * @template T\n * @param {function(new:T)} superClass Class to apply mixin to.\n * @return {function(new:T)} superClass with mixin applied.\n */\nexport const GestureEventListeners = dedupingMixin((superClass) => {\n  /**\n   * @polymer\n   * @mixinClass\n   * @implements {Polymer_GestureEventListeners}\n   */\n  class GestureEventListeners extends superClass {\n    /**\n     * Add the event listener to the node if it is a gestures event.\n     *\n     * @param {!EventTarget} node Node to add event listener to\n     * @param {string} eventName Name of event\n     * @param {function(!Event):void} handler Listener function to add\n     * @return {void}\n     * @override\n     */\n    _addEventListenerToNode(node, eventName, handler) {\n      if (!addListener(node, eventName, handler)) {\n        super._addEventListenerToNode(node, eventName, handler);\n      }\n    }\n\n    /**\n     * Remove the event listener to the node if it is a gestures event.\n     *\n     * @param {!EventTarget} node Node to remove event listener from\n     * @param {string} eventName Name of event\n     * @param {function(!Event):void} handler Listener function to remove\n     * @return {void}\n     * @override\n     */\n    _removeEventListenerFromNode(node, eventName, handler) {\n      if (!removeListener(node, eventName, handler)) {\n        super._removeEventListenerFromNode(node, eventName, handler);\n      }\n    }\n  }\n\n  return GestureEventListeners;\n});\n"
  },
  {
    "path": "lib/mixins/mutable-data.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n// tslint:disable:no-any describes the API as best we are able today\n\nimport {dedupingMixin} from '../utils/mixin.js';\n\nexport {MutableData};\n\n\n/**\n * Element class mixin to skip strict dirty-checking for objects and arrays\n * (always consider them to be \"dirty\"), for use on elements utilizing\n * `PropertyEffects`\n *\n * By default, `PropertyEffects` performs strict dirty checking on\n * objects, which means that any deep modifications to an object or array will\n * not be propagated unless \"immutable\" data patterns are used (i.e. all object\n * references from the root to the mutation were changed).\n *\n * Polymer also provides a proprietary data mutation and path notification API\n * (e.g. `notifyPath`, `set`, and array mutation API's) that allow efficient\n * mutation and notification of deep changes in an object graph to all elements\n * bound to the same object graph.\n *\n * In cases where neither immutable patterns nor the data mutation API can be\n * used, applying this mixin will cause Polymer to skip dirty checking for\n * objects and arrays (always consider them to be \"dirty\").  This allows a\n * user to make a deep modification to a bound object graph, and then either\n * simply re-set the object (e.g. `this.items = this.items`) or call `notifyPath`\n * (e.g. `this.notifyPath('items')`) to update the tree.  Note that all\n * elements that wish to be updated based on deep mutations must apply this\n * mixin or otherwise skip strict dirty checking for objects/arrays.\n * Specifically, any elements in the binding tree between the source of a\n * mutation and the consumption of it must apply this mixin or enable the\n * `OptionalMutableData` mixin.\n *\n * In order to make the dirty check strategy configurable, see\n * `OptionalMutableData`.\n *\n * Note, the performance characteristics of propagating large object graphs\n * will be worse as opposed to using strict dirty checking with immutable\n * patterns or Polymer's path notification API.\n */\ndeclare function MutableData<T extends new (...args: any[]) => {}>(base: T): T & MutableDataConstructor;\n\ninterface MutableDataConstructor {\n  new(...args: any[]): MutableData;\n}\n\nexport {MutableDataConstructor};\n\ninterface MutableData {\n\n  /**\n   * Overrides `PropertyEffects` to provide option for skipping\n   * strict equality checking for Objects and Arrays.\n   *\n   * This method pulls the value to dirty check against from the `__dataTemp`\n   * cache (rather than the normal `__data` cache) for Objects.  Since the temp\n   * cache is cleared at the end of a turn, this implementation allows\n   * side-effects of deep object changes to be processed by re-setting the\n   * same object (using the temp cache as an in-turn backstop to prevent\n   * cycles due to 2-way notification).\n   *\n   * @param property Property name\n   * @param value New property value\n   * @param old Previous property value\n   * @returns Whether the property should be considered a change\n   */\n  _shouldPropertyChange(property: string, value: any, old: any): boolean;\n}\n\nexport {OptionalMutableData};\n\n\n/**\n * Element class mixin to add the optional ability to skip strict\n * dirty-checking for objects and arrays (always consider them to be\n * \"dirty\") by setting a `mutable-data` attribute on an element instance.\n *\n * By default, `PropertyEffects` performs strict dirty checking on\n * objects, which means that any deep modifications to an object or array will\n * not be propagated unless \"immutable\" data patterns are used (i.e. all object\n * references from the root to the mutation were changed).\n *\n * Polymer also provides a proprietary data mutation and path notification API\n * (e.g. `notifyPath`, `set`, and array mutation API's) that allow efficient\n * mutation and notification of deep changes in an object graph to all elements\n * bound to the same object graph.\n *\n * In cases where neither immutable patterns nor the data mutation API can be\n * used, applying this mixin will allow Polymer to skip dirty checking for\n * objects and arrays (always consider them to be \"dirty\").  This allows a\n * user to make a deep modification to a bound object graph, and then either\n * simply re-set the object (e.g. `this.items = this.items`) or call `notifyPath`\n * (e.g. `this.notifyPath('items')`) to update the tree.  Note that all\n * elements that wish to be updated based on deep mutations must apply this\n * mixin or otherwise skip strict dirty checking for objects/arrays.\n * Specifically, any elements in the binding tree between the source of a\n * mutation and the consumption of it must enable this mixin or apply the\n * `MutableData` mixin.\n *\n * While this mixin adds the ability to forgo Object/Array dirty checking,\n * the `mutableData` flag defaults to false and must be set on the instance.\n *\n * Note, the performance characteristics of propagating large object graphs\n * will be worse by relying on `mutableData: true` as opposed to using\n * strict dirty checking with immutable patterns or Polymer's path notification\n * API.\n */\ndeclare function OptionalMutableData<T extends new (...args: any[]) => {}>(base: T): T & OptionalMutableDataConstructor;\n\ninterface OptionalMutableDataConstructor {\n  new(...args: any[]): OptionalMutableData;\n}\n\nexport {OptionalMutableDataConstructor};\n\ninterface OptionalMutableData {\n\n  /**\n   * Instance-level flag for configuring the dirty-checking strategy\n   * for this element.  When true, Objects and Arrays will skip dirty\n   * checking, otherwise strict equality checking will be used.\n   */\n  mutableData: boolean|null|undefined;\n\n  /**\n   * Overrides `PropertyEffects` to provide option for skipping\n   * strict equality checking for Objects and Arrays.\n   *\n   * When `this.mutableData` is true on this instance, this method\n   * pulls the value to dirty check against from the `__dataTemp` cache\n   * (rather than the normal `__data` cache) for Objects.  Since the temp\n   * cache is cleared at the end of a turn, this implementation allows\n   * side-effects of deep object changes to be processed by re-setting the\n   * same object (using the temp cache as an in-turn backstop to prevent\n   * cycles due to 2-way notification).\n   *\n   * @param property Property name\n   * @param value New property value\n   * @param old Previous property value\n   * @returns Whether the property should be considered a change\n   */\n  _shouldPropertyChange(property: string, value: any, old: any): boolean;\n}\n"
  },
  {
    "path": "lib/mixins/mutable-data.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport { dedupingMixin } from '../utils/mixin.js';\n\n// Common implementation for mixin & behavior\nfunction mutablePropertyChange(inst, property, value, old, mutableData) {\n  let isObject;\n  if (mutableData) {\n    isObject = (typeof value === 'object' && value !== null);\n    // Pull `old` for Objects from temp cache, but treat `null` as a primitive\n    if (isObject) {\n      old = inst.__dataTemp[property];\n    }\n  }\n  // Strict equality check, but return false for NaN===NaN\n  let shouldChange = (old !== value && (old === old || value === value));\n  // Objects are stored in temporary cache (cleared at end of\n  // turn), which is used for dirty-checking\n  if (isObject && shouldChange) {\n    inst.__dataTemp[property] = value;\n  }\n  return shouldChange;\n}\n\n/**\n * Element class mixin to skip strict dirty-checking for objects and arrays\n * (always consider them to be \"dirty\"), for use on elements utilizing\n * `PropertyEffects`\n *\n * By default, `PropertyEffects` performs strict dirty checking on\n * objects, which means that any deep modifications to an object or array will\n * not be propagated unless \"immutable\" data patterns are used (i.e. all object\n * references from the root to the mutation were changed).\n *\n * Polymer also provides a proprietary data mutation and path notification API\n * (e.g. `notifyPath`, `set`, and array mutation API's) that allow efficient\n * mutation and notification of deep changes in an object graph to all elements\n * bound to the same object graph.\n *\n * In cases where neither immutable patterns nor the data mutation API can be\n * used, applying this mixin will cause Polymer to skip dirty checking for\n * objects and arrays (always consider them to be \"dirty\").  This allows a\n * user to make a deep modification to a bound object graph, and then either\n * simply re-set the object (e.g. `this.items = this.items`) or call `notifyPath`\n * (e.g. `this.notifyPath('items')`) to update the tree.  Note that all\n * elements that wish to be updated based on deep mutations must apply this\n * mixin or otherwise skip strict dirty checking for objects/arrays.\n * Specifically, any elements in the binding tree between the source of a\n * mutation and the consumption of it must apply this mixin or enable the\n * `OptionalMutableData` mixin.\n *\n * In order to make the dirty check strategy configurable, see\n * `OptionalMutableData`.\n *\n * Note, the performance characteristics of propagating large object graphs\n * will be worse as opposed to using strict dirty checking with immutable\n * patterns or Polymer's path notification API.\n *\n * @mixinFunction\n * @polymer\n * @summary Element class mixin to skip strict dirty-checking for objects\n *   and arrays\n * @template T\n * @param {function(new:T)} superClass Class to apply mixin to.\n * @return {function(new:T)} superClass with mixin applied.\n */\nexport const MutableData = dedupingMixin(superClass => {\n\n  /**\n   * @polymer\n   * @mixinClass\n   * @implements {Polymer_MutableData}\n   */\n  class MutableData extends superClass {\n    /**\n     * Overrides `PropertyEffects` to provide option for skipping\n     * strict equality checking for Objects and Arrays.\n     *\n     * This method pulls the value to dirty check against from the `__dataTemp`\n     * cache (rather than the normal `__data` cache) for Objects.  Since the temp\n     * cache is cleared at the end of a turn, this implementation allows\n     * side-effects of deep object changes to be processed by re-setting the\n     * same object (using the temp cache as an in-turn backstop to prevent\n     * cycles due to 2-way notification).\n     *\n     * @param {string} property Property name\n     * @param {*} value New property value\n     * @param {*} old Previous property value\n     * @return {boolean} Whether the property should be considered a change\n     * @protected\n     */\n    _shouldPropertyChange(property, value, old) {\n      return mutablePropertyChange(this, property, value, old, true);\n    }\n\n  }\n\n  return MutableData;\n\n});\n\n/**\n * Element class mixin to add the optional ability to skip strict\n * dirty-checking for objects and arrays (always consider them to be\n * \"dirty\") by setting a `mutable-data` attribute on an element instance.\n *\n * By default, `PropertyEffects` performs strict dirty checking on\n * objects, which means that any deep modifications to an object or array will\n * not be propagated unless \"immutable\" data patterns are used (i.e. all object\n * references from the root to the mutation were changed).\n *\n * Polymer also provides a proprietary data mutation and path notification API\n * (e.g. `notifyPath`, `set`, and array mutation API's) that allow efficient\n * mutation and notification of deep changes in an object graph to all elements\n * bound to the same object graph.\n *\n * In cases where neither immutable patterns nor the data mutation API can be\n * used, applying this mixin will allow Polymer to skip dirty checking for\n * objects and arrays (always consider them to be \"dirty\").  This allows a\n * user to make a deep modification to a bound object graph, and then either\n * simply re-set the object (e.g. `this.items = this.items`) or call `notifyPath`\n * (e.g. `this.notifyPath('items')`) to update the tree.  Note that all\n * elements that wish to be updated based on deep mutations must apply this\n * mixin or otherwise skip strict dirty checking for objects/arrays.\n * Specifically, any elements in the binding tree between the source of a\n * mutation and the consumption of it must enable this mixin or apply the\n * `MutableData` mixin.\n *\n * While this mixin adds the ability to forgo Object/Array dirty checking,\n * the `mutableData` flag defaults to false and must be set on the instance.\n *\n * Note, the performance characteristics of propagating large object graphs\n * will be worse by relying on `mutableData: true` as opposed to using\n * strict dirty checking with immutable patterns or Polymer's path notification\n * API.\n *\n * @mixinFunction\n * @polymer\n * @summary Element class mixin to optionally skip strict dirty-checking\n *   for objects and arrays\n */\nexport const OptionalMutableData = dedupingMixin(superClass => {\n\n  /**\n   * @mixinClass\n   * @polymer\n   * @implements {Polymer_OptionalMutableData}\n   */\n  class OptionalMutableData extends superClass {\n\n    /** @nocollapse */\n    static get properties() {\n      return {\n        /**\n         * Instance-level flag for configuring the dirty-checking strategy\n         * for this element.  When true, Objects and Arrays will skip dirty\n         * checking, otherwise strict equality checking will be used.\n         */\n        mutableData: Boolean\n      };\n    }\n\n    /**\n     * Overrides `PropertyEffects` to provide option for skipping\n     * strict equality checking for Objects and Arrays.\n     *\n     * When `this.mutableData` is true on this instance, this method\n     * pulls the value to dirty check against from the `__dataTemp` cache\n     * (rather than the normal `__data` cache) for Objects.  Since the temp\n     * cache is cleared at the end of a turn, this implementation allows\n     * side-effects of deep object changes to be processed by re-setting the\n     * same object (using the temp cache as an in-turn backstop to prevent\n     * cycles due to 2-way notification).\n     *\n     * @param {string} property Property name\n     * @param {*} value New property value\n     * @param {*} old Previous property value\n     * @return {boolean} Whether the property should be considered a change\n     * @protected\n     */\n    _shouldPropertyChange(property, value, old) {\n      return mutablePropertyChange(this, property, value, old, this.mutableData);\n    }\n  }\n\n  return OptionalMutableData;\n\n});\n\n// Export for use by legacy behavior\nMutableData._mutablePropertyChange = mutablePropertyChange;\n"
  },
  {
    "path": "lib/mixins/properties-changed.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n// tslint:disable:no-any describes the API as best we are able today\n\nimport {dedupingMixin} from '../utils/mixin.js';\n\nimport {microTask} from '../utils/async.js';\n\nexport {PropertiesChanged};\n\n\n/**\n * Element class mixin that provides basic meta-programming for creating one\n * or more property accessors (getter/setter pair) that enqueue an async\n * (batched) `_propertiesChanged` callback.\n *\n * For basic usage of this mixin, call `MyClass.createProperties(props)`\n * once at class definition time to create property accessors for properties\n * named in props, implement `_propertiesChanged` to react as desired to\n * property changes, and implement `static get observedAttributes()` and\n * include lowercase versions of any property names that should be set from\n * attributes. Last, call `this._enableProperties()` in the element's\n * `connectedCallback` to enable the accessors.\n */\ndeclare function PropertiesChanged<T extends new (...args: any[]) => {}>(base: T): T & PropertiesChangedConstructor;\n\ninterface PropertiesChangedConstructor {\n  new(...args: any[]): PropertiesChanged;\n\n  /**\n   * Creates property accessors for the given property names.\n   *\n   * @param props Object whose keys are names of accessors.\n   */\n  createProperties(props: object): void;\n\n  /**\n   * Returns an attribute name that corresponds to the given property.\n   * The attribute name is the lowercased property name. Override to\n   * customize this mapping.\n   *\n   * @param property Property to convert\n   * @returns Attribute name corresponding to the given property.\n   */\n  attributeNameForProperty(property: string): string;\n\n  /**\n   * Override point to provide a type to which to deserialize a value to\n   * a given property.\n   *\n   * @param name Name of property\n   */\n  typeForProperty(name: string): void;\n}\n\nexport {PropertiesChangedConstructor};\n\ninterface PropertiesChanged {\n\n  /**\n   * Creates a setter/getter pair for the named property with its own\n   * local storage.  The getter returns the value in the local storage,\n   * and the setter calls `_setProperty`, which updates the local storage\n   * for the property and enqueues a `_propertiesChanged` callback.\n   *\n   * This method may be called on a prototype or an instance.  Calling\n   * this method may overwrite a property value that already exists on\n   * the prototype/instance by creating the accessor.\n   *\n   * @param property Name of the property\n   * @param readOnly When true, no setter is created; the\n   *   protected `_setProperty` function must be used to set the property\n   */\n  _createPropertyAccessor(property: string, readOnly?: boolean): void;\n\n  /**\n   * Adds the given `property` to a map matching attribute names\n   * to property names, using `attributeNameForProperty`. This map is\n   * used when deserializing attribute values to properties.\n   *\n   * @param property Name of the property\n   */\n  _addPropertyToAttributeMap(property: string): any;\n\n  /**\n   * Defines a property accessor for the given property.\n   *\n   * @param property Name of the property\n   * @param readOnly When true, no setter is created\n   */\n  _definePropertyAccessor(property: string, readOnly?: boolean): void;\n\n  /**\n   * Lifecycle callback called when properties are enabled via\n   * `_enableProperties`.\n   *\n   * Users may override this function to implement behavior that is\n   * dependent on the element having its property data initialized, e.g.\n   * from defaults (initialized from `constructor`, `_initializeProperties`),\n   * `attributeChangedCallback`, or values propagated from host e.g. via\n   * bindings.  `super.ready()` must be called to ensure the data system\n   * becomes enabled.\n   */\n  ready(): void;\n\n  /**\n   * Initializes the local storage for property accessors.\n   *\n   * Provided as an override point for performing any setup work prior\n   * to initializing the property accessor system.\n   */\n  _initializeProperties(): void;\n\n  /**\n   * Called at ready time with bag of instance properties that overwrote\n   * accessors when the element upgraded.\n   *\n   * The default implementation sets these properties back into the\n   * setter at ready time.  This method is provided as an override\n   * point for customizing or providing more efficient initialization.\n   *\n   * @param props Bag of property values that were overwritten\n   *   when creating property accessors.\n   */\n  _initializeInstanceProperties(props: object|null): void;\n\n  /**\n   * Updates the local storage for a property (via `_setPendingProperty`)\n   * and enqueues a `_proeprtiesChanged` callback.\n   *\n   * @param property Name of the property\n   * @param value Value to set\n   */\n  _setProperty(property: string, value: any): void;\n\n  /**\n   * Returns the value for the given property.\n   *\n   * @param property Name of property\n   * @returns Value for the given property\n   */\n  _getProperty(property: string): any;\n\n  /**\n   * Updates the local storage for a property, records the previous value,\n   * and adds it to the set of \"pending changes\" that will be passed to the\n   * `_propertiesChanged` callback.  This method does not enqueue the\n   * `_propertiesChanged` callback.\n   *\n   * @param property Name of the property\n   * @param value Value to set\n   * @param ext Not used here; affordance for closure\n   * @returns Returns true if the property changed\n   */\n  _setPendingProperty(property: string, value: any, ext?: boolean): boolean;\n\n  /**\n   * @param property Name of the property\n   * @returns Returns true if the property is pending.\n   */\n  _isPropertyPending(property: string): boolean;\n\n  /**\n   * Marks the properties as invalid, and enqueues an async\n   * `_propertiesChanged` callback.\n   */\n  _invalidateProperties(): void;\n\n  /**\n   * Call to enable property accessor processing. Before this method is\n   * called accessor values will be set but side effects are\n   * queued. When called, any pending side effects occur immediately.\n   * For elements, generally `connectedCallback` is a normal spot to do so.\n   * It is safe to call this method multiple times as it only turns on\n   * property accessors once.\n   */\n  _enableProperties(): void;\n\n  /**\n   * Calls the `_propertiesChanged` callback with the current set of\n   * pending changes (and old values recorded when pending changes were\n   * set), and resets the pending set of changes. Generally, this method\n   * should not be called in user code.\n   */\n  _flushProperties(): void;\n\n  /**\n   * Called in `_flushProperties` to determine if `_propertiesChanged`\n   * should be called. The default implementation returns true if\n   * properties are pending. Override to customize when\n   * `_propertiesChanged` is called.\n   *\n   * @param currentProps Bag of all current accessor values\n   * @param changedProps Bag of properties changed since the last\n   *   call to `_propertiesChanged`\n   * @param oldProps Bag of previous values for each property\n   *   in `changedProps`\n   * @returns true if changedProps is truthy\n   */\n  _shouldPropertiesChange(currentProps: object, changedProps: object|null, oldProps: object|null): boolean;\n\n  /**\n   * Callback called when any properties with accessors created via\n   * `_createPropertyAccessor` have been set.\n   *\n   * @param currentProps Bag of all current accessor values\n   * @param changedProps Bag of properties changed since the last\n   *   call to `_propertiesChanged`\n   * @param oldProps Bag of previous values for each property\n   *   in `changedProps`\n   */\n  _propertiesChanged(currentProps: object, changedProps: object|null, oldProps: object|null): void;\n\n  /**\n   * Method called to determine whether a property value should be\n   * considered as a change and cause the `_propertiesChanged` callback\n   * to be enqueued.\n   *\n   * The default implementation returns `true` if a strict equality\n   * check fails. The method always returns false for `NaN`.\n   *\n   * Override this method to e.g. provide stricter checking for\n   * Objects/Arrays when using immutable patterns.\n   *\n   * @param property Property name\n   * @param value New property value\n   * @param old Previous property value\n   * @returns Whether the property should be considered a change\n   *   and enqueue a `_proeprtiesChanged` callback\n   */\n  _shouldPropertyChange(property: string, value: any, old: any): boolean;\n\n  /**\n   * Implements native Custom Elements `attributeChangedCallback` to\n   * set an attribute value to a property via `_attributeToProperty`.\n   *\n   * @param name Name of attribute that changed\n   * @param old Old attribute value\n   * @param value New attribute value\n   * @param namespace Attribute namespace.\n   */\n  attributeChangedCallback(name: string, old: string|null, value: string|null, namespace: string|null): void;\n\n  /**\n   * Deserializes an attribute to its associated property.\n   *\n   * This method calls the `_deserializeValue` method to convert the string to\n   * a typed value.\n   *\n   * @param attribute Name of attribute to deserialize.\n   * @param value of the attribute.\n   * @param type type to deserialize to, defaults to the value\n   * returned from `typeForProperty`\n   */\n  _attributeToProperty(attribute: string, value: string|null, type?: any): void;\n\n  /**\n   * Serializes a property to its associated attribute.\n   *\n   * @param property Property name to reflect.\n   * @param attribute Attribute name to reflect to.\n   * @param value Property value to refect.\n   */\n  _propertyToAttribute(property: string, attribute?: string, value?: any): void;\n\n  /**\n   * Sets a typed value to an HTML attribute on a node.\n   *\n   * This method calls the `_serializeValue` method to convert the typed\n   * value to a string.  If the `_serializeValue` method returns `undefined`,\n   * the attribute will be removed (this is the default for boolean\n   * type `false`).\n   *\n   * @param node Element to set attribute to.\n   * @param value Value to serialize.\n   * @param attribute Attribute name to serialize to.\n   */\n  _valueToNodeAttribute(node: Element|null, value: any, attribute: string): void;\n\n  /**\n   * Converts a typed JavaScript value to a string.\n   *\n   * This method is called when setting JS property values to\n   * HTML attributes.  Users may override this method to provide\n   * serialization for custom types.\n   *\n   * @param value Property value to serialize.\n   * @returns String serialized from the provided\n   * property  value.\n   */\n  _serializeValue(value: any): string|undefined;\n\n  /**\n   * Converts a string to a typed JavaScript value.\n   *\n   * This method is called when reading HTML attribute values to\n   * JS properties.  Users may override this method to provide\n   * deserialization for custom `type`s. Types for `Boolean`, `String`,\n   * and `Number` convert attributes to the expected types.\n   *\n   * @param value Value to deserialize.\n   * @param type Type to deserialize the string to.\n   * @returns Typed value deserialized from the provided string.\n   */\n  _deserializeValue(value: string|null, type?: any): any;\n}\n"
  },
  {
    "path": "lib/mixins/properties-changed.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport '../utils/boot.js';\n\nimport { dedupingMixin } from '../utils/mixin.js';\nimport { microTask } from '../utils/async.js';\nimport { wrap } from '../utils/wrap.js';\n\n/** @const {!AsyncInterface} */\nconst microtask = microTask;\n\n/**\n * Element class mixin that provides basic meta-programming for creating one\n * or more property accessors (getter/setter pair) that enqueue an async\n * (batched) `_propertiesChanged` callback.\n *\n * For basic usage of this mixin, call `MyClass.createProperties(props)`\n * once at class definition time to create property accessors for properties\n * named in props, implement `_propertiesChanged` to react as desired to\n * property changes, and implement `static get observedAttributes()` and\n * include lowercase versions of any property names that should be set from\n * attributes. Last, call `this._enableProperties()` in the element's\n * `connectedCallback` to enable the accessors.\n *\n * @mixinFunction\n * @polymer\n * @summary Element class mixin for reacting to property changes from\n *   generated property accessors.\n * @template T\n * @param {function(new:T)} superClass Class to apply mixin to.\n * @return {function(new:T)} superClass with mixin applied.\n */\nexport const PropertiesChanged = dedupingMixin(\n    /**\n     * @template T\n     * @param {function(new:T)} superClass Class to apply mixin to.\n     * @return {function(new:T)} superClass with mixin applied.\n     */\n    (superClass) => {\n\n  /**\n   * @polymer\n   * @mixinClass\n   * @implements {Polymer_PropertiesChanged}\n   * @unrestricted\n   */\n  class PropertiesChanged extends superClass {\n\n    /**\n     * Creates property accessors for the given property names.\n     * @param {!Object} props Object whose keys are names of accessors.\n     * @return {void}\n     * @protected\n     * @nocollapse\n     */\n    static createProperties(props) {\n      const proto = this.prototype;\n      for (let prop in props) {\n        // don't stomp an existing accessor\n        if (!(prop in proto)) {\n          proto._createPropertyAccessor(prop);\n        }\n      }\n    }\n\n    /**\n     * Returns an attribute name that corresponds to the given property.\n     * The attribute name is the lowercased property name. Override to\n     * customize this mapping.\n     * @param {string} property Property to convert\n     * @return {string} Attribute name corresponding to the given property.\n     *\n     * @protected\n     * @nocollapse\n     */\n    static attributeNameForProperty(property) {\n      return property.toLowerCase();\n    }\n\n    /**\n     * Override point to provide a type to which to deserialize a value to\n     * a given property.\n     * @param {string} name Name of property\n     *\n     * @protected\n     * @nocollapse\n     */\n    static typeForProperty(name) { } //eslint-disable-line no-unused-vars\n\n    /**\n     * Creates a setter/getter pair for the named property with its own\n     * local storage.  The getter returns the value in the local storage,\n     * and the setter calls `_setProperty`, which updates the local storage\n     * for the property and enqueues a `_propertiesChanged` callback.\n     *\n     * This method may be called on a prototype or an instance.  Calling\n     * this method may overwrite a property value that already exists on\n     * the prototype/instance by creating the accessor.\n     *\n     * @param {string} property Name of the property\n     * @param {boolean=} readOnly When true, no setter is created; the\n     *   protected `_setProperty` function must be used to set the property\n     * @return {void}\n     * @protected\n     * @override\n     */\n    _createPropertyAccessor(property, readOnly) {\n      this._addPropertyToAttributeMap(property);\n      if (!this.hasOwnProperty(JSCompiler_renameProperty('__dataHasAccessor', this))) {\n        this.__dataHasAccessor = Object.assign({}, this.__dataHasAccessor);\n      }\n      if (!this.__dataHasAccessor[property]) {\n        this.__dataHasAccessor[property] = true;\n        this._definePropertyAccessor(property, readOnly);\n      }\n    }\n\n    /**\n     * Adds the given `property` to a map matching attribute names\n     * to property names, using `attributeNameForProperty`. This map is\n     * used when deserializing attribute values to properties.\n     *\n     * @param {string} property Name of the property\n     * @override\n     */\n    _addPropertyToAttributeMap(property) {\n      if (!this.hasOwnProperty(JSCompiler_renameProperty('__dataAttributes', this))) {\n        this.__dataAttributes = Object.assign({}, this.__dataAttributes);\n      }\n      // This check is technically not correct; it's an optimization that\n      // assumes that if a _property_ name is already in the map (note this is\n      // an attr->property map), the property mapped directly to the attribute\n      // and it has already been mapped.  This would fail if\n      // `attributeNameForProperty` were overridden such that this was not the\n      // case.\n      let attr = this.__dataAttributes[property];\n      if (!attr) {\n        attr = this.constructor.attributeNameForProperty(property);\n        this.__dataAttributes[attr] = property;\n      }\n      return attr;\n    }\n\n    /**\n     * Defines a property accessor for the given property.\n     * @param {string} property Name of the property\n     * @param {boolean=} readOnly When true, no setter is created\n     * @return {void}\n     * @override\n     */\n     _definePropertyAccessor(property, readOnly) {\n      Object.defineProperty(this, property, {\n        /* eslint-disable valid-jsdoc */\n        /** @this {PropertiesChanged} */\n        get() {\n          // Inline for perf instead of using `_getProperty`\n          return this.__data[property];\n        },\n        /** @this {PropertiesChanged} */\n        set: readOnly ? function () {} : function (value) {\n          // Inline for perf instead of using `_setProperty`\n          if (this._setPendingProperty(property, value, true)) {\n            this._invalidateProperties();\n          }\n        }\n        /* eslint-enable */\n      });\n    }\n\n    constructor() {\n      super();\n      /** @type {boolean} */\n      this.__dataEnabled = false;\n      this.__dataReady = false;\n      this.__dataInvalid = false;\n      this.__data = {};\n      this.__dataPending = null;\n      this.__dataOld = null;\n      this.__dataInstanceProps = null;\n      /** @type {number} */\n      // NOTE: used to track re-entrant calls to `_flushProperties`\n      this.__dataCounter = 0;\n      this.__serializing = false;\n      this._initializeProperties();\n    }\n\n    /**\n     * Lifecycle callback called when properties are enabled via\n     * `_enableProperties`.\n     *\n     * Users may override this function to implement behavior that is\n     * dependent on the element having its property data initialized, e.g.\n     * from defaults (initialized from `constructor`, `_initializeProperties`),\n     * `attributeChangedCallback`, or values propagated from host e.g. via\n     * bindings.  `super.ready()` must be called to ensure the data system\n     * becomes enabled.\n     *\n     * @return {void}\n     * @public\n     * @override\n     */\n    ready() {\n      this.__dataReady = true;\n      this._flushProperties();\n    }\n\n    /**\n     * Initializes the local storage for property accessors.\n     *\n     * Provided as an override point for performing any setup work prior\n     * to initializing the property accessor system.\n     *\n     * @return {void}\n     * @protected\n     * @override\n     */\n    _initializeProperties() {\n      // Capture instance properties; these will be set into accessors\n      // during first flush. Don't set them here, since we want\n      // these to overwrite defaults/constructor assignments\n      for (let p in this.__dataHasAccessor) {\n        if (this.hasOwnProperty(p)) {\n          this.__dataInstanceProps = this.__dataInstanceProps || {};\n          this.__dataInstanceProps[p] = this[p];\n          delete this[p];\n        }\n      }\n    }\n\n    /**\n     * Called at ready time with bag of instance properties that overwrote\n     * accessors when the element upgraded.\n     *\n     * The default implementation sets these properties back into the\n     * setter at ready time.  This method is provided as an override\n     * point for customizing or providing more efficient initialization.\n     *\n     * @param {Object} props Bag of property values that were overwritten\n     *   when creating property accessors.\n     * @return {void}\n     * @protected\n     * @override\n     */\n    _initializeInstanceProperties(props) {\n      Object.assign(this, props);\n    }\n\n    /**\n     * Updates the local storage for a property (via `_setPendingProperty`)\n     * and enqueues a `_proeprtiesChanged` callback.\n     *\n     * @param {string} property Name of the property\n     * @param {*} value Value to set\n     * @return {void}\n     * @protected\n     * @override\n     */\n    _setProperty(property, value) {\n      if (this._setPendingProperty(property, value)) {\n        this._invalidateProperties();\n      }\n    }\n\n    /**\n     * Returns the value for the given property.\n     * @param {string} property Name of property\n     * @return {*} Value for the given property\n     * @protected\n     * @override\n     */\n    _getProperty(property) {\n      return this.__data[property];\n    }\n\n    /* eslint-disable no-unused-vars */\n    /**\n     * Updates the local storage for a property, records the previous value,\n     * and adds it to the set of \"pending changes\" that will be passed to the\n     * `_propertiesChanged` callback.  This method does not enqueue the\n     * `_propertiesChanged` callback.\n     *\n     * @param {string} property Name of the property\n     * @param {*} value Value to set\n     * @param {boolean=} ext Not used here; affordance for closure\n     * @return {boolean} Returns true if the property changed\n     * @protected\n     * @override\n     */\n    _setPendingProperty(property, value, ext) {\n      let old = this.__data[property];\n      let changed = this._shouldPropertyChange(property, value, old);\n      if (changed) {\n        if (!this.__dataPending) {\n          this.__dataPending = {};\n          this.__dataOld = {};\n        }\n        // Ensure old is captured from the last turn\n        if (this.__dataOld && !(property in this.__dataOld)) {\n          this.__dataOld[property] = old;\n        }\n        this.__data[property] = value;\n        this.__dataPending[property] = value;\n      }\n      return changed;\n    }\n    /* eslint-enable */\n\n    /**\n     * @param {string} property Name of the property\n     * @return {boolean} Returns true if the property is pending.\n     */\n    _isPropertyPending(property) {\n      return !!(this.__dataPending && this.__dataPending.hasOwnProperty(property));\n    }\n\n    /**\n     * Marks the properties as invalid, and enqueues an async\n     * `_propertiesChanged` callback.\n     *\n     * @return {void}\n     * @protected\n     * @override\n     */\n    _invalidateProperties() {\n      if (!this.__dataInvalid && this.__dataReady) {\n        this.__dataInvalid = true;\n        microtask.run(() => {\n          if (this.__dataInvalid) {\n            this.__dataInvalid = false;\n            this._flushProperties();\n          }\n        });\n      }\n    }\n\n    /**\n     * Call to enable property accessor processing. Before this method is\n     * called accessor values will be set but side effects are\n     * queued. When called, any pending side effects occur immediately.\n     * For elements, generally `connectedCallback` is a normal spot to do so.\n     * It is safe to call this method multiple times as it only turns on\n     * property accessors once.\n     *\n     * @return {void}\n     * @protected\n     * @override\n     */\n    _enableProperties() {\n      if (!this.__dataEnabled) {\n        this.__dataEnabled = true;\n        if (this.__dataInstanceProps) {\n          this._initializeInstanceProperties(this.__dataInstanceProps);\n          this.__dataInstanceProps = null;\n        }\n        this.ready();\n      }\n    }\n\n    /**\n     * Calls the `_propertiesChanged` callback with the current set of\n     * pending changes (and old values recorded when pending changes were\n     * set), and resets the pending set of changes. Generally, this method\n     * should not be called in user code.\n     *\n     * @return {void}\n     * @protected\n     * @override\n     */\n    _flushProperties() {\n      this.__dataCounter++;\n      const props = this.__data;\n      const changedProps = this.__dataPending;\n      const old = this.__dataOld;\n      if (this._shouldPropertiesChange(props, changedProps, old)) {\n        this.__dataPending = null;\n        this.__dataOld = null;\n        this._propertiesChanged(props, changedProps, old);\n      }\n      this.__dataCounter--;\n    }\n\n    /**\n     * Called in `_flushProperties` to determine if `_propertiesChanged`\n     * should be called. The default implementation returns true if\n     * properties are pending. Override to customize when\n     * `_propertiesChanged` is called.\n     * @param {!Object} currentProps Bag of all current accessor values\n     * @param {?Object} changedProps Bag of properties changed since the last\n     *   call to `_propertiesChanged`\n     * @param {?Object} oldProps Bag of previous values for each property\n     *   in `changedProps`\n     * @return {boolean} true if changedProps is truthy\n     * @override\n     */\n    _shouldPropertiesChange(currentProps, changedProps, oldProps) { // eslint-disable-line no-unused-vars\n      return Boolean(changedProps);\n    }\n\n    /**\n     * Callback called when any properties with accessors created via\n     * `_createPropertyAccessor` have been set.\n     *\n     * @param {!Object} currentProps Bag of all current accessor values\n     * @param {?Object} changedProps Bag of properties changed since the last\n     *   call to `_propertiesChanged`\n     * @param {?Object} oldProps Bag of previous values for each property\n     *   in `changedProps`\n     * @return {void}\n     * @protected\n     * @override\n     */\n    _propertiesChanged(currentProps, changedProps, oldProps) { // eslint-disable-line no-unused-vars\n    }\n\n    /**\n     * Method called to determine whether a property value should be\n     * considered as a change and cause the `_propertiesChanged` callback\n     * to be enqueued.\n     *\n     * The default implementation returns `true` if a strict equality\n     * check fails. The method always returns false for `NaN`.\n     *\n     * Override this method to e.g. provide stricter checking for\n     * Objects/Arrays when using immutable patterns.\n     *\n     * @param {string} property Property name\n     * @param {*} value New property value\n     * @param {*} old Previous property value\n     * @return {boolean} Whether the property should be considered a change\n     *   and enqueue a `_proeprtiesChanged` callback\n     * @protected\n     * @override\n     */\n    _shouldPropertyChange(property, value, old) {\n      return (\n        // Strict equality check\n        (old !== value &&\n          // This ensures (old==NaN, value==NaN) always returns false\n          (old === old || value === value))\n      );\n    }\n\n    /**\n     * Implements native Custom Elements `attributeChangedCallback` to\n     * set an attribute value to a property via `_attributeToProperty`.\n     *\n     * @param {string} name Name of attribute that changed\n     * @param {?string} old Old attribute value\n     * @param {?string} value New attribute value\n     * @param {?string} namespace Attribute namespace.\n     * @return {void}\n     * @suppress {missingProperties} Super may or may not implement the callback\n     * @override\n     */\n    attributeChangedCallback(name, old, value, namespace) {\n      if (old !== value) {\n        this._attributeToProperty(name, value);\n      }\n      if (super.attributeChangedCallback) {\n        super.attributeChangedCallback(name, old, value, namespace);\n      }\n    }\n\n    /**\n     * Deserializes an attribute to its associated property.\n     *\n     * This method calls the `_deserializeValue` method to convert the string to\n     * a typed value.\n     *\n     * @param {string} attribute Name of attribute to deserialize.\n     * @param {?string} value of the attribute.\n     * @param {*=} type type to deserialize to, defaults to the value\n     * returned from `typeForProperty`\n     * @return {void}\n     * @override\n     */\n    _attributeToProperty(attribute, value, type) {\n      if (!this.__serializing) {\n        const map = this.__dataAttributes;\n        const property = map && map[attribute] || attribute;\n        this[property] = this._deserializeValue(value, type ||\n          this.constructor.typeForProperty(property));\n      }\n    }\n\n    /**\n     * Serializes a property to its associated attribute.\n     *\n     * @suppress {invalidCasts} Closure can't figure out `this` is an element.\n     *\n     * @param {string} property Property name to reflect.\n     * @param {string=} attribute Attribute name to reflect to.\n     * @param {*=} value Property value to refect.\n     * @return {void}\n     * @override\n     */\n    _propertyToAttribute(property, attribute, value) {\n      this.__serializing = true;\n      value = (arguments.length < 3) ? this[property] : value;\n      this._valueToNodeAttribute(/** @type {!HTMLElement} */(this), value,\n        attribute || this.constructor.attributeNameForProperty(property));\n      this.__serializing = false;\n    }\n\n    /**\n     * Sets a typed value to an HTML attribute on a node.\n     *\n     * This method calls the `_serializeValue` method to convert the typed\n     * value to a string.  If the `_serializeValue` method returns `undefined`,\n     * the attribute will be removed (this is the default for boolean\n     * type `false`).\n     *\n     * @param {Element} node Element to set attribute to.\n     * @param {*} value Value to serialize.\n     * @param {string} attribute Attribute name to serialize to.\n     * @return {void}\n     * @override\n     */\n    _valueToNodeAttribute(node, value, attribute) {\n      const str = this._serializeValue(value);\n      if (attribute === 'class' || attribute === 'name' || attribute === 'slot') {\n        node = /** @type {?Element} */(wrap(node));\n      }\n      if (str === undefined) {\n        node.removeAttribute(attribute);\n      } else {\n        node.setAttribute(\n            attribute,\n            // Closure's type for `setAttribute`'s second parameter incorrectly\n            // excludes `TrustedScript`.\n            (str === '' && window.trustedTypes) ?\n                /** @type {?} */ (window.trustedTypes.emptyScript) :\n                str);\n      }\n    }\n\n    /**\n     * Converts a typed JavaScript value to a string.\n     *\n     * This method is called when setting JS property values to\n     * HTML attributes.  Users may override this method to provide\n     * serialization for custom types.\n     *\n     * @param {*} value Property value to serialize.\n     * @return {string | undefined} String serialized from the provided\n     * property  value.\n     * @override\n     */\n    _serializeValue(value) {\n      switch (typeof value) {\n        case 'boolean':\n          return value ? '' : undefined;\n        default:\n          return value != null ? value.toString() : undefined;\n      }\n    }\n\n    /**\n     * Converts a string to a typed JavaScript value.\n     *\n     * This method is called when reading HTML attribute values to\n     * JS properties.  Users may override this method to provide\n     * deserialization for custom `type`s. Types for `Boolean`, `String`,\n     * and `Number` convert attributes to the expected types.\n     *\n     * @param {?string} value Value to deserialize.\n     * @param {*=} type Type to deserialize the string to.\n     * @return {*} Typed value deserialized from the provided string.\n     * @override\n     */\n    _deserializeValue(value, type) {\n      switch (type) {\n        case Boolean:\n          return (value !== null);\n        case Number:\n          return Number(value);\n        default:\n          return value;\n      }\n    }\n\n  }\n\n  return PropertiesChanged;\n});\n"
  },
  {
    "path": "lib/mixins/properties-mixin.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n// tslint:disable:no-any describes the API as best we are able today\n\nimport {dedupingMixin} from '../utils/mixin.js';\n\nimport {register, incrementInstanceCount} from '../utils/telemetry.js';\n\nimport {PropertiesChanged} from './properties-changed.js';\n\nexport {PropertiesMixin};\n\n\n/**\n * Mixin that provides a minimal starting point to using the PropertiesChanged\n * mixin by providing a mechanism to declare properties in a static\n * getter (e.g. static get properties() { return { foo: String } }). Changes\n * are reported via the `_propertiesChanged` method.\n *\n * This mixin provides no specific support for rendering. Users are expected\n * to create a ShadowRoot and put content into it and update it in whatever\n * way makes sense. This can be done in reaction to properties changing by\n * implementing `_propertiesChanged`.\n */\ndeclare function PropertiesMixin<T extends new (...args: any[]) => {}>(base: T): T & PropertiesMixinConstructor & PropertiesChangedConstructor;\n\nimport {PropertiesChangedConstructor} from './properties-changed.js';\n\ninterface PropertiesMixinConstructor {\n  new(...args: any[]): PropertiesMixin;\n\n  /**\n   * Overrides `PropertiesChanged` method to return type specified in the\n   * static `properties` object for the given property.\n   *\n   * @param name Name of property\n   * @returns Type to which to deserialize attribute\n   */\n  typeForProperty(name: string): any;\n\n  /**\n   * Finalizes an element definition, including ensuring any super classes\n   * are also finalized. This includes ensuring property\n   * accessors exist on the element prototype. This method calls\n   * `_finalizeClass` to finalize each constructor in the prototype chain.\n   */\n  finalize(): void;\n\n  /**\n   * Finalize an element class. This includes ensuring property\n   * accessors exist on the element prototype. This method is called by\n   * `finalize` and finalizes the class constructor.\n   */\n  _finalizeClass(): void;\n}\n\nexport {PropertiesMixinConstructor};\n\ninterface PropertiesMixin extends PropertiesChanged {\n\n  /**\n   * Overrides `PropertiesChanged` method and adds a call to\n   * `finalize` which lazily configures the element's property accessors.\n   */\n  _initializeProperties(): void;\n\n  /**\n   * Called when the element is added to a document.\n   * Calls `_enableProperties` to turn on property system from\n   * `PropertiesChanged`.\n   */\n  connectedCallback(): void;\n\n  /**\n   * Called when the element is removed from a document\n   */\n  disconnectedCallback(): void;\n}\n"
  },
  {
    "path": "lib/mixins/properties-mixin.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport '../utils/boot.js';\n\nimport { dedupingMixin } from '../utils/mixin.js';\nimport { register, incrementInstanceCount } from '../utils/telemetry.js';\nimport { PropertiesChanged } from './properties-changed.js';\n\n/**\n * Creates a copy of `props` with each property normalized such that\n * upgraded it is an object with at least a type property { type: Type}.\n *\n * @param {!Object} props Properties to normalize\n * @return {!Object} Copy of input `props` with normalized properties that\n * are in the form {type: Type}\n * @private\n */\nfunction normalizeProperties(props) {\n  const output = {};\n  for (let p in props) {\n    const o = props[p];\n    output[p] = (typeof o === 'function') ? {type: o} : o;\n  }\n  return output;\n}\n\n/**\n * Mixin that provides a minimal starting point to using the PropertiesChanged\n * mixin by providing a mechanism to declare properties in a static\n * getter (e.g. static get properties() { return { foo: String } }). Changes\n * are reported via the `_propertiesChanged` method.\n *\n * This mixin provides no specific support for rendering. Users are expected\n * to create a ShadowRoot and put content into it and update it in whatever\n * way makes sense. This can be done in reaction to properties changing by\n * implementing `_propertiesChanged`.\n *\n * @mixinFunction\n * @polymer\n * @appliesMixin PropertiesChanged\n * @summary Mixin that provides a minimal starting point for using\n * the PropertiesChanged mixin by providing a declarative `properties` object.\n * @template T\n * @param {function(new:T)} superClass Class to apply mixin to.\n * @return {function(new:T)} superClass with mixin applied.\n */\nexport const PropertiesMixin = dedupingMixin(superClass => {\n\n /**\n  * @constructor\n  * @implements {Polymer_PropertiesChanged}\n  * @private\n  */\n const base = PropertiesChanged(superClass);\n\n /**\n  * Returns the super class constructor for the given class, if it is an\n  * instance of the PropertiesMixin.\n  *\n  * @param {!PropertiesMixinConstructor} constructor PropertiesMixin constructor\n  * @return {?PropertiesMixinConstructor} Super class constructor\n  */\n function superPropertiesClass(constructor) {\n   const superCtor = Object.getPrototypeOf(constructor);\n\n   // Note, the `PropertiesMixin` class below only refers to the class\n   // generated by this call to the mixin; the instanceof test only works\n   // because the mixin is deduped and guaranteed only to apply once, hence\n   // all constructors in a proto chain will see the same `PropertiesMixin`\n   return (superCtor.prototype instanceof PropertiesMixin) ?\n     /** @type {!PropertiesMixinConstructor} */ (superCtor) : null;\n }\n\n /**\n  * Returns a memoized version of the `properties` object for the\n  * given class. Properties not in object format are converted to at\n  * least {type}.\n  *\n  * @param {PropertiesMixinConstructor} constructor PropertiesMixin constructor\n  * @return {Object} Memoized properties object\n  */\n function ownProperties(constructor) {\n   if (!constructor.hasOwnProperty(JSCompiler_renameProperty('__ownProperties', constructor))) {\n     let props = null;\n\n     if (constructor.hasOwnProperty(JSCompiler_renameProperty('properties', constructor))) {\n       const properties = constructor.properties;\n\n       if (properties) {\n        props = normalizeProperties(properties);\n       }\n     }\n\n     constructor.__ownProperties = props;\n   }\n   return constructor.__ownProperties;\n }\n\n /**\n  * @polymer\n  * @mixinClass\n  * @extends {base}\n  * @implements {Polymer_PropertiesMixin}\n  * @unrestricted\n  */\n class PropertiesMixin extends base {\n\n   /**\n    * Implements standard custom elements getter to observes the attributes\n    * listed in `properties`.\n    * @suppress {missingProperties} Interfaces in closure do not inherit statics, but classes do\n    * @nocollapse\n    */\n   static get observedAttributes() {\n     if (!this.hasOwnProperty(JSCompiler_renameProperty('__observedAttributes', this))) {\n       register(this.prototype);\n       const props = this._properties;\n       this.__observedAttributes = props ? Object.keys(props).map(p => this.prototype._addPropertyToAttributeMap(p)) : [];\n     }\n     return this.__observedAttributes;\n   }\n\n   /**\n    * Finalizes an element definition, including ensuring any super classes\n    * are also finalized. This includes ensuring property\n    * accessors exist on the element prototype. This method calls\n    * `_finalizeClass` to finalize each constructor in the prototype chain.\n    * @return {void}\n    * @nocollapse\n    */\n   static finalize() {\n     if (!this.hasOwnProperty(JSCompiler_renameProperty('__finalized', this))) {\n       const superCtor = superPropertiesClass(/** @type {!PropertiesMixinConstructor} */(this));\n       if (superCtor) {\n         superCtor.finalize();\n       }\n       this.__finalized = true;\n       this._finalizeClass();\n     }\n   }\n\n   /**\n    * Finalize an element class. This includes ensuring property\n    * accessors exist on the element prototype. This method is called by\n    * `finalize` and finalizes the class constructor.\n    *\n    * @protected\n    * @nocollapse\n    */\n   static _finalizeClass() {\n     const props = ownProperties(/** @type {!PropertiesMixinConstructor} */(this));\n     if (props) {\n       /** @type {?} */ (this).createProperties(props);\n     }\n   }\n\n   /**\n    * Returns a memoized version of all properties, including those inherited\n    * from super classes. Properties not in object format are converted to\n    * at least {type}.\n    *\n    * @return {Object} Object containing properties for this class\n    * @protected\n    * @nocollapse\n    */\n   static get _properties() {\n     if (!this.hasOwnProperty(\n       JSCompiler_renameProperty('__properties', this))) {\n       const superCtor = superPropertiesClass(/** @type {!PropertiesMixinConstructor} */(this));\n       this.__properties = Object.assign({},\n         superCtor && superCtor._properties,\n         ownProperties(/** @type {PropertiesMixinConstructor} */(this)));\n     }\n     return this.__properties;\n   }\n\n   /**\n    * Overrides `PropertiesChanged` method to return type specified in the\n    * static `properties` object for the given property.\n    * @param {string} name Name of property\n    * @return {*} Type to which to deserialize attribute\n    *\n    * @protected\n    * @nocollapse\n    */\n   static typeForProperty(name) {\n     const info = this._properties[name];\n     return info && info.type;\n   }\n\n   /**\n    * Overrides `PropertiesChanged` method and adds a call to\n    * `finalize` which lazily configures the element's property accessors.\n    * @override\n    * @return {void}\n    */\n   _initializeProperties() {\n     incrementInstanceCount();\n     this.constructor.finalize();\n     super._initializeProperties();\n   }\n\n   /**\n    * Called when the element is added to a document.\n    * Calls `_enableProperties` to turn on property system from\n    * `PropertiesChanged`.\n    * @suppress {missingProperties} Super may or may not implement the callback\n    * @return {void}\n    * @override\n    */\n   connectedCallback() {\n     if (super.connectedCallback) {\n       super.connectedCallback();\n     }\n     this._enableProperties();\n   }\n\n   /**\n    * Called when the element is removed from a document\n    * @suppress {missingProperties} Super may or may not implement the callback\n    * @return {void}\n    * @override\n    */\n   disconnectedCallback() {\n     if (super.disconnectedCallback) {\n       super.disconnectedCallback();\n     }\n   }\n\n }\n\n return PropertiesMixin;\n\n});\n"
  },
  {
    "path": "lib/mixins/property-accessors.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n// tslint:disable:no-any describes the API as best we are able today\n\nimport {dedupingMixin} from '../utils/mixin.js';\n\nimport {camelToDashCase, dashToCamelCase} from '../utils/case-map.js';\n\nimport {PropertiesChanged} from './properties-changed.js';\n\nexport {PropertyAccessors};\n\n\n/**\n * Element class mixin that provides basic meta-programming for creating one\n * or more property accessors (getter/setter pair) that enqueue an async\n * (batched) `_propertiesChanged` callback.\n *\n * For basic usage of this mixin:\n *\n * -   Declare attributes to observe via the standard `static get\n *     observedAttributes()`. Use `dash-case` attribute names to represent\n *     `camelCase` property names.\n * -   Implement the `_propertiesChanged` callback on the class.\n * -   Call `MyClass.createPropertiesForAttributes()` **once** on the class to\n *     generate property accessors for each observed attribute. This must be\n *     called before the first instance is created, for example, by calling it\n *     before calling `customElements.define`. It can also be called lazily from\n *     the element's `constructor`, as long as it's guarded so that the call is\n *     only made once, when the first instance is created.\n * -   Call `this._enableProperties()` in the element's `connectedCallback` to\n *     enable the accessors.\n *\n * Any `observedAttributes` will automatically be\n * deserialized via `attributeChangedCallback` and set to the associated\n * property using `dash-case`-to-`camelCase` convention.\n */\ndeclare function PropertyAccessors<T extends new (...args: any[]) => {}>(base: T): T & PropertyAccessorsConstructor & PropertiesChangedConstructor;\n\nimport {PropertiesChangedConstructor} from './properties-changed.js';\n\ninterface PropertyAccessorsConstructor {\n  new(...args: any[]): PropertyAccessors;\n\n  /**\n   * Returns an attribute name that corresponds to the given property.\n   * By default, converts camel to dash case, e.g. `fooBar` to `foo-bar`.\n   *\n   * @param property Property to convert\n   * @returns Attribute name corresponding to the given property.\n   */\n  attributeNameForProperty(property: string): string;\n\n  /**\n   * Generates property accessors for all attributes in the standard\n   * static `observedAttributes` array.\n   *\n   * Attribute names are mapped to property names using the `dash-case` to\n   * `camelCase` convention\n   */\n  createPropertiesForAttributes(): void;\n}\n\nexport {PropertyAccessorsConstructor};\n\ninterface PropertyAccessors extends PropertiesChanged {\n\n  /**\n   * Overrides PropertiesChanged implementation to save existing prototype\n   * property value so that it can be reset.\n   *\n   * @param property Name of the property\n   * @param readOnly When true, no setter is created\n   *\n   * When calling on a prototype, any overwritten values are saved in\n   * `__dataProto`, and it is up to the subclasser to decide how/when\n   * to set those properties back into the accessor.  When calling on an\n   * instance, the overwritten value is set via `_setPendingProperty`,\n   * and the user should call `_invalidateProperties` or `_flushProperties`\n   * for the values to take effect.\n   */\n  _definePropertyAccessor(property: string, readOnly?: boolean): void;\n\n  /**\n   * Overrides PropertiesChanged implementation to initialize values for\n   * accessors created for values that already existed on the element\n   * prototype.\n   */\n  _initializeProperties(): void;\n\n  /**\n   * Returns true if the specified property has a pending change.\n   *\n   * @param prop Property name\n   * @returns True if property has a pending change\n   */\n  _isPropertyPending(prop: string): boolean;\n\n  /**\n   * Overrides PropertiesChanged implemention to serialize objects as JSON.\n   *\n   * @param value Property value to serialize.\n   * @returns String serialized from the provided property\n   *     value.\n   */\n  _serializeValue(value: any): string|undefined;\n\n  /**\n   * Converts a string to a typed JavaScript value.\n   *\n   * This method is called by Polymer when reading HTML attribute values to\n   * JS properties.  Users may override this method on Polymer element\n   * prototypes to provide deserialization for custom `type`s.  Note,\n   * the `type` argument is the value of the `type` field provided in the\n   * `properties` configuration object for a given property, and is\n   * by convention the constructor for the type to deserialize.\n   *\n   * @param value Attribute value to deserialize.\n   * @param type Type to deserialize the string to.\n   * @returns Typed value deserialized from the provided string.\n   */\n  _deserializeValue(value: string|null, type?: any): any;\n\n  /**\n   * Called at instance time with bag of properties that were overwritten\n   * by accessors on the prototype when accessors were created.\n   *\n   * The default implementation sets these properties back into the\n   * setter at instance time.  This method is provided as an override\n   * point for customizing or providing more efficient initialization.\n   *\n   * @param props Bag of property values that were overwritten\n   *   when creating property accessors.\n   */\n  _initializeProtoProperties(props: object|null): void;\n\n  /**\n   * Ensures the element has the given attribute. If it does not,\n   * assigns the given value to the attribute.\n   *\n   * @param attribute Name of attribute to ensure is set.\n   * @param value of the attribute.\n   */\n  _ensureAttribute(attribute: string, value: string): void;\n\n  /**\n   * Returns true if this library created an accessor for the given property.\n   *\n   * @param property Property name\n   * @returns True if an accessor was created\n   */\n  _hasAccessor(property: string): boolean;\n}\n"
  },
  {
    "path": "lib/mixins/property-accessors.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport '../utils/boot.js';\n\nimport { dedupingMixin } from '../utils/mixin.js';\nimport { camelToDashCase, dashToCamelCase } from '../utils/case-map.js';\nimport { PropertiesChanged } from './properties-changed.js';\n\n// Save map of native properties; this forms a blacklist or properties\n// that won't have their values \"saved\" by `saveAccessorValue`, since\n// reading from an HTMLElement accessor from the context of a prototype throws\nconst nativeProperties = {};\nlet proto = HTMLElement.prototype;\nwhile (proto) {\n  let props = Object.getOwnPropertyNames(proto);\n  for (let i=0; i<props.length; i++) {\n    nativeProperties[props[i]] = true;\n  }\n  proto = Object.getPrototypeOf(proto);\n}\n\nconst isTrustedType = (() => {\n  if (!window.trustedTypes) {\n    return () => false;\n  }\n  return (val) => trustedTypes.isHTML(val) ||\n        trustedTypes.isScript(val) || trustedTypes.isScriptURL(val);\n})();\n\n/**\n * Used to save the value of a property that will be overridden with\n * an accessor. If the `model` is a prototype, the values will be saved\n * in `__dataProto`, and it's up to the user (or downstream mixin) to\n * decide how/when to set these values back into the accessors.\n * If `model` is already an instance (it has a `__data` property), then\n * the value will be set as a pending property, meaning the user should\n * call `_invalidateProperties` or `_flushProperties` to take effect\n *\n * @param {Object} model Prototype or instance\n * @param {string} property Name of property\n * @return {void}\n * @private\n */\nfunction saveAccessorValue(model, property) {\n  // Don't read/store value for any native properties since they could throw\n  if (!nativeProperties[property]) {\n    let value = model[property];\n    if (value !== undefined) {\n      if (model.__data) {\n        // Adding accessor to instance; update the property\n        // It is the user's responsibility to call _flushProperties\n        model._setPendingProperty(property, value);\n      } else {\n        // Adding accessor to proto; save proto's value for instance-time use\n        if (!model.__dataProto) {\n          model.__dataProto = {};\n        } else if (!model.hasOwnProperty(JSCompiler_renameProperty('__dataProto', model))) {\n          model.__dataProto = Object.create(model.__dataProto);\n        }\n        model.__dataProto[property] = value;\n      }\n    }\n  }\n}\n\n/**\n * Element class mixin that provides basic meta-programming for creating one\n * or more property accessors (getter/setter pair) that enqueue an async\n * (batched) `_propertiesChanged` callback.\n *\n * For basic usage of this mixin:\n *\n * -   Declare attributes to observe via the standard `static get\n *     observedAttributes()`. Use `dash-case` attribute names to represent\n *     `camelCase` property names.\n * -   Implement the `_propertiesChanged` callback on the class.\n * -   Call `MyClass.createPropertiesForAttributes()` **once** on the class to\n *     generate property accessors for each observed attribute. This must be\n *     called before the first instance is created, for example, by calling it\n *     before calling `customElements.define`. It can also be called lazily from\n *     the element's `constructor`, as long as it's guarded so that the call is\n *     only made once, when the first instance is created.\n * -   Call `this._enableProperties()` in the element's `connectedCallback` to\n *     enable the accessors.\n *\n * Any `observedAttributes` will automatically be\n * deserialized via `attributeChangedCallback` and set to the associated\n * property using `dash-case`-to-`camelCase` convention.\n *\n * @mixinFunction\n * @polymer\n * @appliesMixin PropertiesChanged\n * @summary Element class mixin for reacting to property changes from\n *   generated property accessors.\n * @template T\n * @param {function(new:T)} superClass Class to apply mixin to.\n * @return {function(new:T)} superClass with mixin applied.\n */\nexport const PropertyAccessors = dedupingMixin(superClass => {\n\n  /**\n   * @constructor\n   * @implements {Polymer_PropertiesChanged}\n   * @unrestricted\n   * @private\n   */\n   const base = PropertiesChanged(superClass);\n\n  /**\n   * @polymer\n   * @mixinClass\n   * @implements {Polymer_PropertyAccessors}\n   * @extends {base}\n   * @unrestricted\n   */\n  class PropertyAccessors extends base {\n\n    /**\n     * Generates property accessors for all attributes in the standard\n     * static `observedAttributes` array.\n     *\n     * Attribute names are mapped to property names using the `dash-case` to\n     * `camelCase` convention\n     *\n     * @return {void}\n     * @nocollapse\n     */\n    static createPropertiesForAttributes() {\n      let a$ =  /** @type {?} */ (this).observedAttributes;\n      for (let i=0; i < a$.length; i++) {\n        this.prototype._createPropertyAccessor(dashToCamelCase(a$[i]));\n      }\n    }\n\n    /**\n     * Returns an attribute name that corresponds to the given property.\n     * By default, converts camel to dash case, e.g. `fooBar` to `foo-bar`.\n     * @param {string} property Property to convert\n     * @return {string} Attribute name corresponding to the given property.\n     *\n     * @protected\n     * @nocollapse\n     */\n    static attributeNameForProperty(property) {\n      return camelToDashCase(property);\n    }\n\n    /**\n     * Overrides PropertiesChanged implementation to initialize values for\n     * accessors created for values that already existed on the element\n     * prototype.\n     *\n     * @return {void}\n     * @protected\n     * @override\n     */\n    _initializeProperties() {\n      if (this.__dataProto) {\n        this._initializeProtoProperties(this.__dataProto);\n        this.__dataProto = null;\n      }\n      super._initializeProperties();\n    }\n\n    /**\n     * Called at instance time with bag of properties that were overwritten\n     * by accessors on the prototype when accessors were created.\n     *\n     * The default implementation sets these properties back into the\n     * setter at instance time.  This method is provided as an override\n     * point for customizing or providing more efficient initialization.\n     *\n     * @param {Object} props Bag of property values that were overwritten\n     *   when creating property accessors.\n     * @return {void}\n     * @protected\n     * @override\n     */\n    _initializeProtoProperties(props) {\n      for (let p in props) {\n        this._setProperty(p, props[p]);\n      }\n    }\n\n    /**\n     * Ensures the element has the given attribute. If it does not,\n     * assigns the given value to the attribute.\n     *\n     * @suppress {invalidCasts} Closure can't figure out `this` is infact an\n     *     element\n     *\n     * @param {string} attribute Name of attribute to ensure is set.\n     * @param {string} value of the attribute.\n     * @return {void}\n     * @override\n     */\n    _ensureAttribute(attribute, value) {\n      const el = /** @type {!HTMLElement} */(this);\n      if (!el.hasAttribute(attribute)) {\n        this._valueToNodeAttribute(el, value, attribute);\n      }\n    }\n\n    /**\n     * Overrides PropertiesChanged implemention to serialize objects as JSON.\n     *\n     * @param {*} value Property value to serialize.\n     * @return {string | undefined} String serialized from the provided property\n     *     value.\n     * @override\n     */\n    _serializeValue(value) {\n      /* eslint-disable no-fallthrough */\n      switch (typeof value) {\n        case 'object':\n          if (value instanceof Date) {\n            return value.toString();\n          } else if (value) {\n            if (isTrustedType(value)) {\n              /**\n               * Here `value` isn't actually a string, but it should be\n               * passed into APIs that normally expect a string, like\n               * elem.setAttribute.\n               */\n              return /** @type {?} */ (value);\n            }\n            try {\n              return JSON.stringify(value);\n            } catch(x) {\n              return '';\n            }\n          }\n\n        default:\n          return super._serializeValue(value);\n      }\n    }\n\n    /**\n     * Converts a string to a typed JavaScript value.\n     *\n     * This method is called by Polymer when reading HTML attribute values to\n     * JS properties.  Users may override this method on Polymer element\n     * prototypes to provide deserialization for custom `type`s.  Note,\n     * the `type` argument is the value of the `type` field provided in the\n     * `properties` configuration object for a given property, and is\n     * by convention the constructor for the type to deserialize.\n     *\n     *\n     * @param {?string} value Attribute value to deserialize.\n     * @param {*=} type Type to deserialize the string to.\n     * @return {*} Typed value deserialized from the provided string.\n     * @override\n     */\n    _deserializeValue(value, type) {\n      /**\n       * @type {*}\n       */\n      let outValue;\n      switch (type) {\n        case Object:\n          try {\n            outValue = JSON.parse(/** @type {string} */(value));\n          } catch(x) {\n            // allow non-JSON literals like Strings and Numbers\n            outValue = value;\n          }\n          break;\n        case Array:\n          try {\n            outValue = JSON.parse(/** @type {string} */(value));\n          } catch(x) {\n            outValue = null;\n            console.warn(`Polymer::Attributes: couldn't decode Array as JSON: ${value}`);\n          }\n          break;\n        case Date:\n          outValue = isNaN(value) ? String(value) : Number(value);\n          outValue = new Date(outValue);\n          break;\n        default:\n          outValue = super._deserializeValue(value, type);\n          break;\n      }\n      return outValue;\n    }\n    /* eslint-enable no-fallthrough */\n\n    /**\n     * Overrides PropertiesChanged implementation to save existing prototype\n     * property value so that it can be reset.\n     * @param {string} property Name of the property\n     * @param {boolean=} readOnly When true, no setter is created\n     *\n     * When calling on a prototype, any overwritten values are saved in\n     * `__dataProto`, and it is up to the subclasser to decide how/when\n     * to set those properties back into the accessor.  When calling on an\n     * instance, the overwritten value is set via `_setPendingProperty`,\n     * and the user should call `_invalidateProperties` or `_flushProperties`\n     * for the values to take effect.\n     * @protected\n     * @return {void}\n     * @override\n     */\n    _definePropertyAccessor(property, readOnly) {\n      saveAccessorValue(this, property);\n      super._definePropertyAccessor(property, readOnly);\n    }\n\n    /**\n     * Returns true if this library created an accessor for the given property.\n     *\n     * @param {string} property Property name\n     * @return {boolean} True if an accessor was created\n     * @override\n     */\n    _hasAccessor(property) {\n      return this.__dataHasAccessor && this.__dataHasAccessor[property];\n    }\n\n    /**\n     * Returns true if the specified property has a pending change.\n     *\n     * @param {string} prop Property name\n     * @return {boolean} True if property has a pending change\n     * @protected\n     * @override\n     */\n    _isPropertyPending(prop) {\n      return Boolean(this.__dataPending && (prop in this.__dataPending));\n    }\n\n  }\n\n  return PropertyAccessors;\n\n});\n"
  },
  {
    "path": "lib/mixins/property-effects.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n// tslint:disable:no-any describes the API as best we are able today\n\nimport {dedupingMixin} from '../utils/mixin.js';\n\nimport {root, isAncestor, isDescendant, get, translate, isPath, set, normalize} from '../utils/path.js';\n\nimport {camelToDashCase, dashToCamelCase} from '../utils/case-map.js';\n\nimport {PropertyAccessors} from './property-accessors.js';\n\nimport {TemplateStamp} from './template-stamp.js';\n\nexport {PropertyEffects};\n\n\n/**\n * Element class mixin that provides meta-programming for Polymer's template\n * binding and data observation (collectively, \"property effects\") system.\n *\n * This mixin uses provides the following key static methods for adding\n * property effects to an element class:\n * - `addPropertyEffect`\n * - `createPropertyObserver`\n * - `createMethodObserver`\n * - `createNotifyingProperty`\n * - `createReadOnlyProperty`\n * - `createReflectedProperty`\n * - `createComputedProperty`\n * - `bindTemplate`\n *\n * Each method creates one or more property accessors, along with metadata\n * used by this mixin's implementation of `_propertiesChanged` to perform\n * the property effects.\n *\n * Underscored versions of the above methods also exist on the element\n * prototype for adding property effects on instances at runtime.\n *\n * Note that this mixin overrides several `PropertyAccessors` methods, in\n * many cases to maintain guarantees provided by the Polymer 1.x features;\n * notably it changes property accessors to be synchronous by default\n * whereas the default when using `PropertyAccessors` standalone is to be\n * async by default.\n */\ndeclare function PropertyEffects<T extends new (...args: any[]) => {}>(base: T): T & PropertyEffectsConstructor & TemplateStampConstructor & PropertyAccessorsConstructor & PropertiesChangedConstructor;\n\nimport {TemplateStampConstructor} from './template-stamp.js';\n\nimport {PropertyAccessorsConstructor} from './property-accessors.js';\n\nimport {PropertiesChangedConstructor, PropertiesChanged} from './properties-changed.js';\n\ninterface PropertyEffectsConstructor {\n  new(...args: any[]): PropertyEffects;\n\n  /**\n   * Overrides default `TemplateStamp` implementation to add support for\n   * parsing bindings from `TextNode`'s' `textContent`.  A `bindings`\n   * array is added to `nodeInfo` and populated with binding metadata\n   * with information capturing the binding target, and a `parts` array\n   * with one or more metadata objects capturing the source(s) of the\n   * binding.\n   *\n   * @param node Node to parse\n   * @param templateInfo Template metadata for current template\n   * @param nodeInfo Node metadata for current template node\n   * @returns `true` if the visited node added node-specific\n   *   metadata to `nodeInfo`\n   */\n  _parseTemplateNode(node: Node|null, templateInfo: TemplateInfo|null, nodeInfo: NodeInfo|null): boolean;\n\n  /**\n   * Overrides default `TemplateStamp` implementation to add support for\n   * binding the properties that a nested template depends on to the template\n   * as `_host_<property>`.\n   *\n   * @param node Node to parse\n   * @param templateInfo Template metadata for current template\n   * @param nodeInfo Node metadata for current template node\n   * @returns `true` if the visited node added node-specific\n   *   metadata to `nodeInfo`\n   */\n  _parseTemplateNestedTemplate(node: Node|null, templateInfo: TemplateInfo|null, nodeInfo: NodeInfo|null): boolean;\n\n  /**\n   * Overrides default `TemplateStamp` implementation to add support for\n   * parsing bindings from attributes.  A `bindings`\n   * array is added to `nodeInfo` and populated with binding metadata\n   * with information capturing the binding target, and a `parts` array\n   * with one or more metadata objects capturing the source(s) of the\n   * binding.\n   *\n   * @param node Node to parse\n   * @param templateInfo Template metadata for current template\n   * @param nodeInfo Node metadata for current template node\n   * @param name Attribute name\n   * @param value Attribute value\n   * @returns `true` if the visited node added node-specific\n   *   metadata to `nodeInfo`\n   */\n  _parseTemplateNodeAttribute(node: Element|null, templateInfo: TemplateInfo|null, nodeInfo: NodeInfo|null, name: string, value: string): boolean;\n\n  /**\n   * Ensures an accessor exists for the specified property, and adds\n   * to a list of \"property effects\" that will run when the accessor for\n   * the specified property is set.  Effects are grouped by \"type\", which\n   * roughly corresponds to a phase in effect processing.  The effect\n   * metadata should be in the following form:\n   *\n   *     {\n   *       fn: effectFunction, // Reference to function to call to perform effect\n   *       info: { ... }       // Effect metadata passed to function\n   *       trigger: {          // Optional triggering metadata; if not provided\n   *         name: string      // the property is treated as a wildcard\n   *         structured: boolean\n   *         wildcard: boolean\n   *       }\n   *     }\n   *\n   * Effects are called from `_propertiesChanged` in the following order by\n   * type:\n   *\n   * 1. COMPUTE\n   * 2. PROPAGATE\n   * 3. REFLECT\n   * 4. OBSERVE\n   * 5. NOTIFY\n   *\n   * Effect functions are called with the following signature:\n   *\n   *     effectFunction(inst, path, props, oldProps, info, hasPaths)\n   *\n   * @param property Property that should trigger the effect\n   * @param type Effect type, from this.PROPERTY_EFFECT_TYPES\n   * @param effect Effect metadata object\n   */\n  addPropertyEffect(property: string, type: string, effect?: object|null): void;\n\n  /**\n   * Creates a single-property observer for the given property.\n   *\n   * @param property Property name\n   * @param method Function or name of observer method to call\n   * @param dynamicFn Whether the method name should be included as\n   *   a dependency to the effect.\n   */\n  createPropertyObserver(property: string, method: string|((p0: any, p1: any) => any), dynamicFn?: boolean): void;\n\n  /**\n   * Creates a multi-property \"method observer\" based on the provided\n   * expression, which should be a string in the form of a normal JavaScript\n   * function signature: `'methodName(arg1, [..., argn])'`.  Each argument\n   * should correspond to a property or path in the context of this\n   * prototype (or instance), or may be a literal string or number.\n   *\n   * @param expression Method expression\n   * @param dynamicFn Boolean or object map indicating\n   * @returns whether method names should be included as a dependency to the effect.\n   */\n  createMethodObserver(expression: string, dynamicFn?: boolean|object|null): void;\n\n  /**\n   * Causes the setter for the given property to dispatch `<property>-changed`\n   * events to notify of changes to the property.\n   *\n   * @param property Property name\n   */\n  createNotifyingProperty(property: string): void;\n\n  /**\n   * Creates a read-only accessor for the given property.\n   *\n   * To set the property, use the protected `_setProperty` API.\n   * To create a custom protected setter (e.g. `_setMyProp()` for\n   * property `myProp`), pass `true` for `protectedSetter`.\n   *\n   * Note, if the property will have other property effects, this method\n   * should be called first, before adding other effects.\n   *\n   * @param property Property name\n   * @param protectedSetter Creates a custom protected setter\n   *   when `true`.\n   */\n  createReadOnlyProperty(property: string, protectedSetter?: boolean): void;\n\n  /**\n   * Causes the setter for the given property to reflect the property value\n   * to a (dash-cased) attribute of the same name.\n   *\n   * @param property Property name\n   */\n  createReflectedProperty(property: string): void;\n\n  /**\n   * Creates a computed property whose value is set to the result of the\n   * method described by the given `expression` each time one or more\n   * arguments to the method changes.  The expression should be a string\n   * in the form of a normal JavaScript function signature:\n   * `'methodName(arg1, [..., argn])'`\n   *\n   * @param property Name of computed property to set\n   * @param expression Method expression\n   * @param dynamicFn Boolean or object map indicating whether\n   *   method names should be included as a dependency to the effect.\n   */\n  createComputedProperty(property: string, expression: string, dynamicFn?: boolean|object|null): void;\n\n  /**\n   * Parses the provided template to ensure binding effects are created\n   * for them, and then ensures property accessors are created for any\n   * dependent properties in the template.  Binding effects for bound\n   * templates are stored in a linked list on the instance so that\n   * templates can be efficiently stamped and unstamped.\n   *\n   * @param template Template containing binding\n   *   bindings\n   * @returns Template metadata object\n   */\n  bindTemplate(template: HTMLTemplateElement): TemplateInfo;\n\n  /**\n   * Adds a property effect to the given template metadata, which is run\n   * at the \"propagate\" stage of `_propertiesChanged` when the template\n   * has been bound to the element via `_bindTemplate`.\n   *\n   * The `effect` object should match the format in `_addPropertyEffect`.\n   *\n   * @param templateInfo Template metadata to add effect to\n   * @param prop Property that should trigger the effect\n   * @param effect Effect metadata object\n   */\n  _addTemplatePropertyEffect(templateInfo: object|null, prop: string, effect?: object|null): void;\n\n  /**\n   * Called to parse text in a template (either attribute values or\n   * textContent) into binding metadata.\n   *\n   * Any overrides of this method should return an array of binding part\n   * metadata  representing one or more bindings found in the provided text\n   * and any \"literal\" text in between.  Any non-literal parts will be passed\n   * to `_evaluateBinding` when any dependencies change.  The only required\n   * fields of each \"part\" in the returned array are as follows:\n   *\n   * - `dependencies` - Array containing trigger metadata for each property\n   *   that should trigger the binding to update\n   * - `literal` - String containing text if the part represents a literal;\n   *   in this case no `dependencies` are needed\n   *\n   * Additional metadata for use by `_evaluateBinding` may be provided in\n   * each part object as needed.\n   *\n   * The default implementation handles the following types of bindings\n   * (one or more may be intermixed with literal strings):\n   * - Property binding: `[[prop]]`\n   * - Path binding: `[[object.prop]]`\n   * - Negated property or path bindings: `[[!prop]]` or `[[!object.prop]]`\n   * - Two-way property or path bindings (supports negation):\n   *   `{{prop}}`, `{{object.prop}}`, `{{!prop}}` or `{{!object.prop}}`\n   * - Inline computed method (supports negation):\n   *   `[[compute(a, 'literal', b)]]`, `[[!compute(a, 'literal', b)]]`\n   *\n   * The default implementation uses a regular expression for best\n   * performance. However, the regular expression uses a white-list of\n   * allowed characters in a data-binding, which causes problems for\n   * data-bindings that do use characters not in this white-list.\n   *\n   * Instead of updating the white-list with all allowed characters,\n   * there is a StrictBindingParser (see lib/mixins/strict-binding-parser)\n   * that uses a state machine instead. This state machine is able to handle\n   * all characters. However, it is slightly less performant, therefore we\n   * extracted it into a separate optional mixin.\n   *\n   * @param text Text to parse from attribute or textContent\n   * @param templateInfo Current template metadata\n   * @returns Array of binding part metadata\n   */\n  _parseBindings(text: string, templateInfo: object|null): BindingPart[]|null;\n\n  /**\n   * Called to evaluate a previously parsed binding part based on a set of\n   * one or more changed dependencies.\n   *\n   * @param inst Element that should be used as\n   *     scope for binding dependencies\n   * @param part Binding part metadata\n   * @param path Property/path that triggered this effect\n   * @param props Bag of current property changes\n   * @param oldProps Bag of previous values for changed properties\n   * @param hasPaths True with `props` contains one or more paths\n   * @returns Value the binding part evaluated to\n   */\n  _evaluateBinding(inst: PropertyEffects, part: BindingPart|null, path: string, props: object|null, oldProps: object|null, hasPaths: boolean): any;\n}\n\nexport {PropertyEffectsConstructor};\n\ninterface PropertyEffects extends TemplateStamp, PropertyAccessors, PropertiesChanged {\n  _overrideLegacyUndefined: boolean;\n  readonly PROPERTY_EFFECT_TYPES: any;\n\n  /**\n   * Stamps the provided template and performs instance-time setup for\n   * Polymer template features, including data bindings, declarative event\n   * listeners, and the `this.$` map of `id`'s to nodes.  A document fragment\n   * is returned containing the stamped DOM, ready for insertion into the\n   * DOM.\n   *\n   * This method may be called more than once; however note that due to\n   * `shadycss` polyfill limitations, only styles from templates prepared\n   * using `ShadyCSS.prepareTemplate` will be correctly polyfilled (scoped\n   * to the shadow root and support CSS custom properties), and note that\n   * `ShadyCSS.prepareTemplate` may only be called once per element. As such,\n   * any styles required by in runtime-stamped templates must be included\n   * in the main element template.\n   *\n   * @param template Template to stamp\n   * @param templateInfo Optional bound template info associated\n   *   with the template to be stamped; if omitted the template will be\n   *   automatically bound.\n   * @returns Cloned template content\n   */\n  _stampTemplate(template: HTMLTemplateElement, templateInfo?: TemplateInfo|null): StampedTemplate;\n\n  /**\n   * Overrides `PropertyAccessors` so that property accessor\n   * side effects are not enabled until after client dom is fully ready.\n   * Also calls `_flushClients` callback to ensure client dom is enabled\n   * that was not enabled as a result of flushing properties.\n   */\n  ready(): void;\n  _initializeProperties(): void;\n\n  /**\n   * Overrides `PropertyAccessors` implementation to avoid setting\n   * `_setProperty`'s `shouldNotify: true`.\n   *\n   * @param props Properties to initialize on the instance\n   */\n  _initializeInstanceProperties(props: object|null): void;\n\n  /**\n   * Overrides base implementation to ensure all accessors set `shouldNotify`\n   * to true, for per-property notification tracking.\n   *\n   * @param property Name of the property\n   * @param value Value to set\n   */\n  _setProperty(property: string, value: any): void;\n\n  /**\n   * Overrides the `PropertiesChanged` implementation to introduce special\n   * dirty check logic depending on the property & value being set:\n   *\n   * 1. Any value set to a path (e.g. 'obj.prop': 42 or 'obj.prop': {...})\n   *    Stored in `__dataTemp`, dirty checked against `__dataTemp`\n   * 2. Object set to simple property (e.g. 'prop': {...})\n   *    Stored in `__dataTemp` and `__data`, dirty checked against\n   *    `__dataTemp` by default implementation of `_shouldPropertyChange`\n   * 3. Primitive value set to simple property (e.g. 'prop': 42)\n   *    Stored in `__data`, dirty checked against `__data`\n   *\n   * The dirty-check is important to prevent cycles due to two-way\n   * notification, but paths and objects are only dirty checked against any\n   * previous value set during this turn via a \"temporary cache\" that is\n   * cleared when the last `_propertiesChanged` exits. This is so:\n   * a. any cached array paths (e.g. 'array.3.prop') may be invalidated\n   *    due to array mutations like shift/unshift/splice; this is fine\n   *    since path changes are dirty-checked at user entry points like `set`\n   * b. dirty-checking for objects only lasts one turn to allow the user\n   *    to mutate the object in-place and re-set it with the same identity\n   *    and have all sub-properties re-propagated in a subsequent turn.\n   *\n   * The temp cache is not necessarily sufficient to prevent invalid array\n   * paths, since a splice can happen during the same turn (with pathological\n   * user code); we could introduce a \"fixup\" for temporarily cached array\n   * paths if needed: https://github.com/Polymer/polymer/issues/4227\n   *\n   * @param property Name of the property\n   * @param value Value to set\n   * @param shouldNotify True if property should fire notification\n   *   event (applies only for `notify: true` properties)\n   * @returns Returns true if the property changed\n   */\n  _setPendingProperty(property: string, value: any, shouldNotify?: boolean): boolean;\n\n  /**\n   * Overrides `PropertyAccessor`'s default async queuing of\n   * `_propertiesChanged`: if `__dataReady` is false (has not yet been\n   * manually flushed), the function no-ops; otherwise flushes\n   * `_propertiesChanged` synchronously.\n   */\n  _invalidateProperties(): void;\n\n  /**\n   * Implements `PropertyAccessors`'s properties changed callback.\n   *\n   * Runs each class of effects for the batch of changed properties in\n   * a specific order (compute, propagate, reflect, observe, notify).\n   *\n   * @param currentProps Bag of all current accessor values\n   * @param changedProps Bag of properties changed since the last\n   *   call to `_propertiesChanged`\n   * @param oldProps Bag of previous values for each property\n   *   in `changedProps`\n   */\n  _propertiesChanged(currentProps: object, changedProps: object|null, oldProps: object|null): void;\n\n  /**\n   * Overrides `PropertyAccessors` implementation to provide a\n   * more efficient implementation of initializing properties from\n   * the prototype on the instance.\n   *\n   * @param props Properties to initialize on the prototype\n   */\n  _initializeProtoProperties(props: object|null): void;\n  _registerHost(): void;\n\n  /**\n   * Equivalent to static `addPropertyEffect` API but can be called on\n   * an instance to add effects at runtime.  See that method for\n   * full API docs.\n   *\n   * @param property Property that should trigger the effect\n   * @param type Effect type, from this.PROPERTY_EFFECT_TYPES\n   * @param effect Effect metadata object\n   */\n  _addPropertyEffect(property: string, type: string, effect?: object|null): void;\n\n  /**\n   * Removes the given property effect.\n   *\n   * @param property Property the effect was associated with\n   * @param type Effect type, from this.PROPERTY_EFFECT_TYPES\n   * @param effect Effect metadata object to remove\n   */\n  _removePropertyEffect(property: string, type: string, effect?: object|null): void;\n\n  /**\n   * Returns whether the current prototype/instance has a property effect\n   * of a certain type.\n   *\n   * @param property Property name\n   * @param type Effect type, from this.PROPERTY_EFFECT_TYPES\n   * @returns True if the prototype/instance has an effect of this\n   *     type\n   */\n  _hasPropertyEffect(property: string, type?: string): boolean;\n\n  /**\n   * Returns whether the current prototype/instance has a \"read only\"\n   * accessor for the given property.\n   *\n   * @param property Property name\n   * @returns True if the prototype/instance has an effect of this\n   *     type\n   */\n  _hasReadOnlyEffect(property: string): boolean;\n\n  /**\n   * Returns whether the current prototype/instance has a \"notify\"\n   * property effect for the given property.\n   *\n   * @param property Property name\n   * @returns True if the prototype/instance has an effect of this\n   *     type\n   */\n  _hasNotifyEffect(property: string): boolean;\n\n  /**\n   * Returns whether the current prototype/instance has a \"reflect to\n   * attribute\" property effect for the given property.\n   *\n   * @param property Property name\n   * @returns True if the prototype/instance has an effect of this\n   *     type\n   */\n  _hasReflectEffect(property: string): boolean;\n\n  /**\n   * Returns whether the current prototype/instance has a \"computed\"\n   * property effect for the given property.\n   *\n   * @param property Property name\n   * @returns True if the prototype/instance has an effect of this\n   *     type\n   */\n  _hasComputedEffect(property: string): boolean;\n\n  /**\n   * Sets a pending property or path.  If the root property of the path in\n   * question had no accessor, the path is set, otherwise it is enqueued\n   * via `_setPendingProperty`.\n   *\n   * This function isolates relatively expensive functionality necessary\n   * for the public API (`set`, `setProperties`, `notifyPath`, and property\n   * change listeners via {{...}} bindings), such that it is only done\n   * when paths enter the system, and not at every propagation step.  It\n   * also sets a `__dataHasPaths` flag on the instance which is used to\n   * fast-path slower path-matching code in the property effects host paths.\n   *\n   * `path` can be a path string or array of path parts as accepted by the\n   * public API.\n   *\n   * @param path Path to set\n   * @param value Value to set\n   * @param shouldNotify Set to true if this change should\n   *  cause a property notification event dispatch\n   * @param isPathNotification If the path being set is a path\n   *   notification of an already changed value, as opposed to a request\n   *   to set and notify the change.  In the latter `false` case, a dirty\n   *   check is performed and then the value is set to the path before\n   *   enqueuing the pending property change.\n   * @returns Returns true if the property/path was enqueued in\n   *   the pending changes bag.\n   */\n  _setPendingPropertyOrPath(path: string|Array<number|string>, value: any, shouldNotify?: boolean, isPathNotification?: boolean): boolean;\n\n  /**\n   * Applies a value to a non-Polymer element/node's property.\n   *\n   * The implementation makes a best-effort at binding interop:\n   * Some native element properties have side-effects when\n   * re-setting the same value (e.g. setting `<input>.value` resets the\n   * cursor position), so we do a dirty-check before setting the value.\n   * However, for better interop with non-Polymer custom elements that\n   * accept objects, we explicitly re-set object changes coming from the\n   * Polymer world (which may include deep object changes without the\n   * top reference changing), erring on the side of providing more\n   * information.\n   *\n   * Users may override this method to provide alternate approaches.\n   *\n   * @param node The node to set a property on\n   * @param prop The property to set\n   * @param value The value to set\n   */\n  _setUnmanagedPropertyToNode(node: Node, prop: string, value: any): void;\n\n  /**\n   * Enqueues the given client on a list of pending clients, whose\n   * pending property changes can later be flushed via a call to\n   * `_flushClients`.\n   *\n   * @param client PropertyEffects client to enqueue\n   */\n  _enqueueClient(client: object|null): void;\n\n  /**\n   * Flushes any clients previously enqueued via `_enqueueClient`, causing\n   * their `_flushProperties` method to run.\n   */\n  _flushClients(): void;\n\n  /**\n   * Perform any initial setup on client dom. Called before the first\n   * `_flushProperties` call on client dom and before any element\n   * observers are called.\n   */\n  _readyClients(): void;\n\n  /**\n   * Sets a bag of property changes to this instance, and\n   * synchronously processes all effects of the properties as a batch.\n   *\n   * Property names must be simple properties, not paths.  Batched\n   * path propagation is not supported.\n   *\n   * @param props Bag of one or more key-value pairs whose key is\n   *   a property and value is the new value to set for that property.\n   * @param setReadOnly When true, any private values set in\n   *   `props` will be set. By default, `setProperties` will not set\n   *   `readOnly: true` root properties.\n   */\n  setProperties(props: object|null, setReadOnly?: boolean): void;\n\n  /**\n   * Called to propagate any property changes to stamped template nodes\n   * managed by this element.\n   *\n   * @param changedProps Bag of changed properties\n   * @param oldProps Bag of previous values for changed properties\n   * @param hasPaths True with `props` contains one or more paths\n   */\n  _propagatePropertyChanges(changedProps: object|null, oldProps: object|null, hasPaths: boolean): void;\n  _runEffectsForTemplate(templateInfo: any, changedProps: any, oldProps: any, hasPaths: any): void;\n\n  /**\n   * Aliases one data path as another, such that path notifications from one\n   * are routed to the other.\n   *\n   * @param to Target path to link.\n   * @param from Source path to link.\n   */\n  linkPaths(to: string|Array<string|number>, from: string|Array<string|number>): void;\n\n  /**\n   * Removes a data path alias previously established with `_linkPaths`.\n   *\n   * Note, the path to unlink should be the target (`to`) used when\n   * linking the paths.\n   *\n   * @param path Target path to unlink.\n   */\n  unlinkPaths(path: string|Array<string|number>): void;\n\n  /**\n   * Notify that an array has changed.\n   *\n   * Example:\n   *\n   *     this.items = [ {name: 'Jim'}, {name: 'Todd'}, {name: 'Bill'} ];\n   *     ...\n   *     this.items.splice(1, 1, {name: 'Sam'});\n   *     this.items.push({name: 'Bob'});\n   *     this.notifySplices('items', [\n   *       { index: 1, removed: [{name: 'Todd'}], addedCount: 1,\n   *         object: this.items, type: 'splice' },\n   *       { index: 3, removed: [], addedCount: 1,\n   *         object: this.items, type: 'splice'}\n   *     ]);\n   *\n   * @param path Path that should be notified.\n   * @param splices Array of splice records indicating ordered\n   *   changes that occurred to the array. Each record should have the\n   *   following fields:\n   *    * index: index at which the change occurred\n   *    * removed: array of items that were removed from this index\n   *    * addedCount: number of new items added at this index\n   *    * object: a reference to the array in question\n   *    * type: the string literal 'splice'\n   *\n   *   Note that splice records _must_ be normalized such that they are\n   *   reported in index order (raw results from `Object.observe` are not\n   *   ordered and must be normalized/merged before notifying).\n   */\n  notifySplices(path: string, splices: any[]|null): void;\n\n  /**\n   * Convenience method for reading a value from a path.\n   *\n   * Note, if any part in the path is undefined, this method returns\n   * `undefined` (this method does not throw when dereferencing undefined\n   * paths).\n   *\n   * @param path Path to the value\n   *   to read.  The path may be specified as a string (e.g. `foo.bar.baz`)\n   *   or an array of path parts (e.g. `['foo.bar', 'baz']`).  Note that\n   *   bracketed expressions are not supported; string-based path parts\n   *   *must* be separated by dots.  Note that when dereferencing array\n   *   indices, the index may be used as a dotted part directly\n   *   (e.g. `users.12.name` or `['users', 12, 'name']`).\n   * @param root Root object from which the path is evaluated.\n   * @returns Value at the path, or `undefined` if any part of the path\n   *   is undefined.\n   */\n  get(path: string|Array<string|number>, root?: object|null): any;\n\n  /**\n   * Convenience method for setting a value to a path and notifying any\n   * elements bound to the same path.\n   *\n   * Note, if any part in the path except for the last is undefined,\n   * this method does nothing (this method does not throw when\n   * dereferencing undefined paths).\n   *\n   * @param path Path to the value\n   *   to write.  The path may be specified as a string (e.g. `'foo.bar.baz'`)\n   *   or an array of path parts (e.g. `['foo.bar', 'baz']`).  Note that\n   *   bracketed expressions are not supported; string-based path parts\n   *   *must* be separated by dots.  Note that when dereferencing array\n   *   indices, the index may be used as a dotted part directly\n   *   (e.g. `'users.12.name'` or `['users', 12, 'name']`).\n   * @param value Value to set at the specified path.\n   * @param root Root object from which the path is evaluated.\n   *   When specified, no notification will occur.\n   */\n  set(path: string|Array<string|number>, value: any, root?: object|null): void;\n\n  /**\n   * Adds items onto the end of the array at the path specified.\n   *\n   * The arguments after `path` and return value match that of\n   * `Array.prototype.push`.\n   *\n   * This method notifies other paths to the same array that a\n   * splice occurred to the array.\n   *\n   * @param path Path to array.\n   * @param items Items to push onto array\n   * @returns New length of the array.\n   */\n  push(path: string|Array<string|number>, ...items: any[]): number;\n\n  /**\n   * Removes an item from the end of array at the path specified.\n   *\n   * The arguments after `path` and return value match that of\n   * `Array.prototype.pop`.\n   *\n   * This method notifies other paths to the same array that a\n   * splice occurred to the array.\n   *\n   * @param path Path to array.\n   * @returns Item that was removed.\n   */\n  pop(path: string|Array<string|number>): any;\n\n  /**\n   * Starting from the start index specified, removes 0 or more items\n   * from the array and inserts 0 or more new items in their place.\n   *\n   * The arguments after `path` and return value match that of\n   * `Array.prototype.splice`.\n   *\n   * This method notifies other paths to the same array that a\n   * splice occurred to the array.\n   *\n   * @param path Path to array.\n   * @param start Index from which to start removing/inserting.\n   * @param deleteCount Number of items to remove.\n   * @param items Items to insert into array.\n   * @returns Array of removed items.\n   */\n  splice(path: string|Array<string|number>, start: number, deleteCount?: number, ...items: any[]): any[];\n\n  /**\n   * Removes an item from the beginning of array at the path specified.\n   *\n   * The arguments after `path` and return value match that of\n   * `Array.prototype.pop`.\n   *\n   * This method notifies other paths to the same array that a\n   * splice occurred to the array.\n   *\n   * @param path Path to array.\n   * @returns Item that was removed.\n   */\n  shift(path: string|Array<string|number>): any;\n\n  /**\n   * Adds items onto the beginning of the array at the path specified.\n   *\n   * The arguments after `path` and return value match that of\n   * `Array.prototype.push`.\n   *\n   * This method notifies other paths to the same array that a\n   * splice occurred to the array.\n   *\n   * @param path Path to array.\n   * @param items Items to insert info array\n   * @returns New length of the array.\n   */\n  unshift(path: string|Array<string|number>, ...items: any[]): number;\n\n  /**\n   * Notify that a path has changed.\n   *\n   * Example:\n   *\n   *     this.item.user.name = 'Bob';\n   *     this.notifyPath('item.user.name');\n   *\n   * @param path Path that should be notified.\n   * @param value Value at the path (optional).\n   */\n  notifyPath(path: string, value?: any): void;\n\n  /**\n   * Equivalent to static `createReadOnlyProperty` API but can be called on\n   * an instance to add effects at runtime.  See that method for\n   * full API docs.\n   *\n   * @param property Property name\n   * @param protectedSetter Creates a custom protected setter\n   *   when `true`.\n   */\n  _createReadOnlyProperty(property: string, protectedSetter?: boolean): void;\n\n  /**\n   * Equivalent to static `createPropertyObserver` API but can be called on\n   * an instance to add effects at runtime.  See that method for\n   * full API docs.\n   *\n   * @param property Property name\n   * @param method Function or name of observer method\n   *     to call\n   * @param dynamicFn Whether the method name should be included as\n   *   a dependency to the effect.\n   */\n  _createPropertyObserver(property: string, method: string|((p0: any, p1: any) => any), dynamicFn?: boolean): void;\n\n  /**\n   * Equivalent to static `createMethodObserver` API but can be called on\n   * an instance to add effects at runtime.  See that method for\n   * full API docs.\n   *\n   * @param expression Method expression\n   * @param dynamicFn Boolean or object map indicating\n   *   whether method names should be included as a dependency to the effect.\n   */\n  _createMethodObserver(expression: string, dynamicFn?: boolean|object|null): void;\n\n  /**\n   * Equivalent to static `createNotifyingProperty` API but can be called on\n   * an instance to add effects at runtime.  See that method for\n   * full API docs.\n   *\n   * @param property Property name\n   */\n  _createNotifyingProperty(property: string): void;\n\n  /**\n   * Equivalent to static `createReflectedProperty` API but can be called on\n   * an instance to add effects at runtime.  See that method for\n   * full API docs.\n   *\n   * @param property Property name\n   */\n  _createReflectedProperty(property: string): void;\n\n  /**\n   * Equivalent to static `createComputedProperty` API but can be called on\n   * an instance to add effects at runtime.  See that method for\n   * full API docs.\n   *\n   * @param property Name of computed property to set\n   * @param expression Method expression\n   * @param dynamicFn Boolean or object map indicating\n   *   whether method names should be included as a dependency to the effect.\n   */\n  _createComputedProperty(property: string, expression: string, dynamicFn?: boolean|object|null): void;\n\n  /**\n   * Equivalent to static `bindTemplate` API but can be called on an instance\n   * to add effects at runtime.  See that method for full API docs.\n   *\n   * This method may be called on the prototype (for prototypical template\n   * binding, to avoid creating accessors every instance) once per prototype,\n   * and will be called with `runtimeBinding: true` by `_stampTemplate` to\n   * create and link an instance of the template metadata associated with a\n   * particular stamping.\n   *\n   * @param template Template containing binding\n   * bindings\n   * @param instanceBinding When false (default), performs\n   * \"prototypical\" binding of the template and overwrites any previously\n   * bound template for the class. When true (as passed from\n   * `_stampTemplate`), the template info is instanced and linked into the\n   * list of bound templates.\n   * @returns Template metadata object; for `runtimeBinding`,\n   * this is an instance of the prototypical template info\n   */\n  _bindTemplate(template: HTMLTemplateElement, instanceBinding?: boolean): TemplateInfo;\n\n  /**\n   * Removes and unbinds the nodes previously contained in the provided\n   * DocumentFragment returned from `_stampTemplate`.\n   *\n   * @param dom DocumentFragment previously returned\n   *   from `_stampTemplate` associated with the nodes to be removed\n   */\n  _removeBoundDom(dom: StampedTemplate): void;\n}\n\nimport {TemplateInfo} from '../../interfaces';\n\nimport {NodeInfo} from '../../interfaces';\n\nimport {BindingPart} from '../../interfaces';\n\nimport {StampedTemplate} from '../../interfaces';\n"
  },
  {
    "path": "lib/mixins/property-effects.js",
    "content": "/**\n * @fileoverview\n * @suppress {checkPrototypalTypes}\n * @license Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\n * This code may only be used under the BSD style license found at\n * http://polymer.github.io/LICENSE.txt The complete set of authors may be found\n * at http://polymer.github.io/AUTHORS.txt The complete set of contributors may\n * be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by\n * Google as part of the polymer project is also subject to an additional IP\n * rights grant found at http://polymer.github.io/PATENTS.txt\n */\n\nimport '../utils/boot.js';\nimport { wrap } from '../utils/wrap.js';\nimport { dedupingMixin } from '../utils/mixin.js';\nimport { root, isAncestor, isDescendant, get, translate, isPath, set, normalize } from '../utils/path.js';\n/* for notify, reflect */\nimport { camelToDashCase, dashToCamelCase } from '../utils/case-map.js';\nimport { PropertyAccessors } from './property-accessors.js';\n/* for annotated effects */\nimport { TemplateStamp } from './template-stamp.js';\nimport { sanitizeDOMValue, legacyUndefined, orderedComputed, removeNestedTemplates, fastDomIf } from '../utils/settings.js';\n\n// Monotonically increasing unique ID used for de-duping effects triggered\n// from multiple properties in the same turn\nlet dedupeId = 0;\n\nconst NOOP = [];\n\n/**\n * Property effect types; effects are stored on the prototype using these keys\n * @enum {string}\n */\nconst TYPES = {\n  COMPUTE: '__computeEffects',\n  REFLECT: '__reflectEffects',\n  NOTIFY: '__notifyEffects',\n  PROPAGATE: '__propagateEffects',\n  OBSERVE: '__observeEffects',\n  READ_ONLY: '__readOnly'\n};\n\nconst COMPUTE_INFO = '__computeInfo';\n\n/** @const {!RegExp} */\nconst capitalAttributeRegex = /[A-Z]/;\n\n/**\n * @typedef {{\n * name: (string | undefined),\n * structured: (boolean | undefined),\n * wildcard: (boolean | undefined)\n * }}\n */\nlet DataTrigger; //eslint-disable-line no-unused-vars\n\n/**\n * @typedef {{\n * info: ?,\n * trigger: (!DataTrigger | undefined),\n * fn: (!Function | undefined)\n * }}\n */\nlet DataEffect; //eslint-disable-line no-unused-vars\n\n/**\n * Ensures that the model has an own-property map of effects for the given type.\n * The model may be a prototype or an instance.\n *\n * Property effects are stored as arrays of effects by property in a map,\n * by named type on the model. e.g.\n *\n *   __computeEffects: {\n *     foo: [ ... ],\n *     bar: [ ... ]\n *   }\n *\n * If the model does not yet have an effect map for the type, one is created\n * and returned.  If it does, but it is not an own property (i.e. the\n * prototype had effects), the the map is deeply cloned and the copy is\n * set on the model and returned, ready for new effects to be added.\n *\n * @param {Object} model Prototype or instance\n * @param {string} type Property effect type\n * @param {boolean=} cloneArrays Clone any arrays assigned to the map when\n *   extending a superclass map onto this subclass\n * @return {Object} The own-property map of effects for the given type\n * @private\n */\nfunction ensureOwnEffectMap(model, type, cloneArrays) {\n  let effects = model[type];\n  if (!effects) {\n    effects = model[type] = {};\n  } else if (!model.hasOwnProperty(type)) {\n    effects = model[type] = Object.create(model[type]);\n    if (cloneArrays) {\n      for (let p in effects) {\n        let protoFx = effects[p];\n        // Perf optimization over Array.slice\n        let instFx = effects[p] = Array(protoFx.length);\n        for (let i=0; i<protoFx.length; i++) {\n          instFx[i] = protoFx[i];\n        }\n      }\n    }\n  }\n  return effects;\n}\n\n// -- effects ----------------------------------------------\n\n/**\n * Runs all effects of a given type for the given set of property changes\n * on an instance.\n *\n * @param {!Polymer_PropertyEffects} inst The instance with effects to run\n * @param {?Object} effects Object map of property-to-Array of effects\n * @param {?Object} props Bag of current property changes\n * @param {?Object=} oldProps Bag of previous values for changed properties\n * @param {boolean=} hasPaths True with `props` contains one or more paths\n * @param {*=} extraArgs Additional metadata to pass to effect function\n * @return {boolean} True if an effect ran for this property\n * @private\n */\nfunction runEffects(inst, effects, props, oldProps, hasPaths, extraArgs) {\n  if (effects) {\n    let ran = false;\n    const id = dedupeId++;\n    for (let prop in props) {\n      // Inline `runEffectsForProperty` for perf.\n      let rootProperty = hasPaths ? root(prop) : prop;\n      let fxs = effects[rootProperty];\n      if (fxs) {\n        for (let i=0, l=fxs.length, fx; (i<l) && (fx=fxs[i]); i++) {\n          if ((!fx.info || fx.info.lastRun !== id) &&\n              (!hasPaths || pathMatchesTrigger(prop, fx.trigger))) {\n            if (fx.info) {\n              fx.info.lastRun = id;\n            }\n            fx.fn(inst, prop, props, oldProps, fx.info, hasPaths, extraArgs);\n            ran = true;\n          }\n        }\n      }\n    }\n    return ran;\n  }\n  return false;\n}\n\n/**\n * Runs a list of effects for a given property.\n *\n * @param {!Polymer_PropertyEffects} inst The instance with effects to run\n * @param {!Object} effects Object map of property-to-Array of effects\n * @param {number} dedupeId Counter used for de-duping effects\n * @param {string} prop Name of changed property\n * @param {*} props Changed properties\n * @param {*} oldProps Old properties\n * @param {boolean=} hasPaths True with `props` contains one or more paths\n * @param {*=} extraArgs Additional metadata to pass to effect function\n * @return {boolean} True if an effect ran for this property\n * @private\n */\nfunction runEffectsForProperty(inst, effects, dedupeId, prop, props, oldProps, hasPaths, extraArgs) {\n  let ran = false;\n  let rootProperty = hasPaths ? root(prop) : prop;\n  let fxs = effects[rootProperty];\n  if (fxs) {\n    for (let i=0, l=fxs.length, fx; (i<l) && (fx=fxs[i]); i++) {\n      if ((!fx.info || fx.info.lastRun !== dedupeId) &&\n          (!hasPaths || pathMatchesTrigger(prop, fx.trigger))) {\n        if (fx.info) {\n          fx.info.lastRun = dedupeId;\n        }\n        fx.fn(inst, prop, props, oldProps, fx.info, hasPaths, extraArgs);\n        ran = true;\n      }\n    }\n  }\n  return ran;\n}\n\n/**\n * Determines whether a property/path that has changed matches the trigger\n * criteria for an effect.  A trigger is a descriptor with the following\n * structure, which matches the descriptors returned from `parseArg`.\n * e.g. for `foo.bar.*`:\n * ```\n * trigger: {\n *   name: 'a.b',\n *   structured: true,\n *   wildcard: true\n * }\n * ```\n * If no trigger is given, the path is deemed to match.\n *\n * @param {string} path Path or property that changed\n * @param {?DataTrigger} trigger Descriptor\n * @return {boolean} Whether the path matched the trigger\n */\nfunction pathMatchesTrigger(path, trigger) {\n  if (trigger) {\n    let triggerPath = /** @type {string} */ (trigger.name);\n    return (triggerPath == path) ||\n        !!(trigger.structured && isAncestor(triggerPath, path)) ||\n        !!(trigger.wildcard && isDescendant(triggerPath, path));\n  } else {\n    return true;\n  }\n}\n\n/**\n * Implements the \"observer\" effect.\n *\n * Calls the method with `info.methodName` on the instance, passing the\n * new and old values.\n *\n * @param {!Polymer_PropertyEffects} inst The instance the effect will be run on\n * @param {string} property Name of property\n * @param {Object} props Bag of current property changes\n * @param {Object} oldProps Bag of previous values for changed properties\n * @param {?} info Effect metadata\n * @return {void}\n * @private\n */\nfunction runObserverEffect(inst, property, props, oldProps, info) {\n  let fn = typeof info.method === \"string\" ? inst[info.method] : info.method;\n  let changedProp = info.property;\n  if (fn) {\n    fn.call(inst, inst.__data[changedProp], oldProps[changedProp]);\n  } else if (!info.dynamicFn) {\n    console.warn('observer method `' + info.method + '` not defined');\n  }\n}\n\n/**\n * Runs \"notify\" effects for a set of changed properties.\n *\n * This method differs from the generic `runEffects` method in that it\n * will dispatch path notification events in the case that the property\n * changed was a path and the root property for that path didn't have a\n * \"notify\" effect.  This is to maintain 1.0 behavior that did not require\n * `notify: true` to ensure object sub-property notifications were\n * sent.\n *\n * @param {!Polymer_PropertyEffects} inst The instance with effects to run\n * @param {Object} notifyProps Bag of properties to notify\n * @param {Object} props Bag of current property changes\n * @param {Object} oldProps Bag of previous values for changed properties\n * @param {boolean} hasPaths True with `props` contains one or more paths\n * @return {void}\n * @private\n */\nfunction runNotifyEffects(inst, notifyProps, props, oldProps, hasPaths) {\n  // Notify\n  let fxs = inst[TYPES.NOTIFY];\n  let notified;\n  let id = dedupeId++;\n  // Try normal notify effects; if none, fall back to try path notification\n  for (let prop in notifyProps) {\n    if (notifyProps[prop]) {\n      if (fxs && runEffectsForProperty(inst, fxs, id, prop, props, oldProps, hasPaths)) {\n        notified = true;\n      } else if (hasPaths && notifyPath(inst, prop, props)) {\n        notified = true;\n      }\n    }\n  }\n  // Flush host if we actually notified and host was batching\n  // And the host has already initialized clients; this prevents\n  // an issue with a host observing data changes before clients are ready.\n  let host;\n  if (notified && (host = inst.__dataHost) && host._invalidateProperties) {\n    host._invalidateProperties();\n  }\n}\n\n/**\n * Dispatches {property}-changed events with path information in the detail\n * object to indicate a sub-path of the property was changed.\n *\n * @param {!Polymer_PropertyEffects} inst The element from which to fire the\n *     event\n * @param {string} path The path that was changed\n * @param {Object} props Bag of current property changes\n * @return {boolean} Returns true if the path was notified\n * @private\n */\nfunction notifyPath(inst, path, props) {\n  let rootProperty = root(path);\n  if (rootProperty !== path) {\n    let eventName = camelToDashCase(rootProperty) + '-changed';\n    dispatchNotifyEvent(inst, eventName, props[path], path);\n    return true;\n  }\n  return false;\n}\n\n/**\n * Dispatches {property}-changed events to indicate a property (or path)\n * changed.\n *\n * @param {!Polymer_PropertyEffects} inst The element from which to fire the\n *     event\n * @param {string} eventName The name of the event to send\n *     ('{property}-changed')\n * @param {*} value The value of the changed property\n * @param {string | null | undefined} path If a sub-path of this property\n *     changed, the path that changed (optional).\n * @return {void}\n * @private\n * @suppress {invalidCasts}\n */\nfunction dispatchNotifyEvent(inst, eventName, value, path) {\n  let detail = {\n    value: value,\n    queueProperty: true\n  };\n  if (path) {\n    detail.path = path;\n  }\n  // As a performance optimization, we could elide the wrap here since notifying\n  // events are non-bubbling and shouldn't need retargeting. However, a very\n  // small number of internal tests failed in obscure ways, which may indicate\n  // user code relied on timing differences resulting from ShadyDOM flushing\n  // as a result of the wrapped `dispatchEvent`.\n  wrap(/** @type {!HTMLElement} */(inst)).dispatchEvent(new CustomEvent(eventName, { detail }));\n}\n\n/**\n * Implements the \"notify\" effect.\n *\n * Dispatches a non-bubbling event named `info.eventName` on the instance\n * with a detail object containing the new `value`.\n *\n * @param {!Polymer_PropertyEffects} inst The instance the effect will be run on\n * @param {string} property Name of property\n * @param {Object} props Bag of current property changes\n * @param {Object} oldProps Bag of previous values for changed properties\n * @param {?} info Effect metadata\n * @param {boolean} hasPaths True with `props` contains one or more paths\n * @return {void}\n * @private\n */\nfunction runNotifyEffect(inst, property, props, oldProps, info, hasPaths) {\n  let rootProperty = hasPaths ? root(property) : property;\n  let path = rootProperty != property ? property : null;\n  let value = path ? get(inst, path) : inst.__data[property];\n  if (path && value === undefined) {\n    value = props[property];  // specifically for .splices\n  }\n  dispatchNotifyEvent(inst, info.eventName, value, path);\n}\n\n/**\n * Handler function for 2-way notification events. Receives context\n * information captured in the `addNotifyListener` closure from the\n * `__notifyListeners` metadata.\n *\n * Sets the value of the notified property to the host property or path.  If\n * the event contained path information, translate that path to the host\n * scope's name for that path first.\n *\n * @param {CustomEvent} event Notification event (e.g. '<property>-changed')\n * @param {!Polymer_PropertyEffects} inst Host element instance handling the\n *     notification event\n * @param {string} fromProp Child element property that was bound\n * @param {string} toPath Host property/path that was bound\n * @param {boolean} negate Whether the binding was negated\n * @return {void}\n * @private\n */\nfunction handleNotification(event, inst, fromProp, toPath, negate) {\n  let value;\n  let detail = /** @type {Object} */(event.detail);\n  let fromPath = detail && detail.path;\n  if (fromPath) {\n    toPath = translate(fromProp, toPath, fromPath);\n    value = detail && detail.value;\n  } else {\n    value = event.currentTarget[fromProp];\n  }\n  value = negate ? !value : value;\n  if (!inst[TYPES.READ_ONLY] || !inst[TYPES.READ_ONLY][toPath]) {\n    if (inst._setPendingPropertyOrPath(toPath, value, true, Boolean(fromPath))\n      && (!detail || !detail.queueProperty)) {\n      inst._invalidateProperties();\n    }\n  }\n}\n\n/**\n * Implements the \"reflect\" effect.\n *\n * Sets the attribute named `info.attrName` to the given property value.\n *\n * @param {!Polymer_PropertyEffects} inst The instance the effect will be run on\n * @param {string} property Name of property\n * @param {Object} props Bag of current property changes\n * @param {Object} oldProps Bag of previous values for changed properties\n * @param {?} info Effect metadata\n * @return {void}\n * @private\n */\nfunction runReflectEffect(inst, property, props, oldProps, info) {\n  let value = inst.__data[property];\n  if (sanitizeDOMValue) {\n    value = sanitizeDOMValue(value, info.attrName, 'attribute', /** @type {Node} */(inst));\n  }\n  inst._propertyToAttribute(property, info.attrName, value);\n}\n\n/**\n * Runs \"computed\" effects for a set of changed properties.\n *\n * This method differs from the generic `runEffects` method in that it\n * continues to run computed effects based on the output of each pass until\n * there are no more newly computed properties.  This ensures that all\n * properties that will be computed by the initial set of changes are\n * computed before other effects (binding propagation, observers, and notify)\n * run.\n *\n * @param {!Polymer_PropertyEffects} inst The instance the effect will be run on\n * @param {?Object} changedProps Bag of changed properties\n * @param {?Object} oldProps Bag of previous values for changed properties\n * @param {boolean} hasPaths True with `props` contains one or more paths\n * @return {void}\n * @private\n */\nfunction runComputedEffects(inst, changedProps, oldProps, hasPaths) {\n  let computeEffects = inst[TYPES.COMPUTE];\n  if (computeEffects) {\n    if (orderedComputed) {\n      // Runs computed effects in efficient order by keeping a topologically-\n      // sorted queue of compute effects to run, and inserting subsequently\n      // invalidated effects as they are run\n      dedupeId++;\n      const order = getComputedOrder(inst);\n      const queue = [];\n      for (let p in changedProps) {\n        enqueueEffectsFor(p, computeEffects, queue, order, hasPaths);\n      }\n      let info;\n      while ((info = queue.shift())) {\n        if (runComputedEffect(inst, '', changedProps, oldProps, info)) {\n          enqueueEffectsFor(info.methodInfo, computeEffects, queue, order, hasPaths);\n        }\n      }\n      Object.assign(/** @type {!Object} */ (oldProps), inst.__dataOld);\n      Object.assign(/** @type {!Object} */ (changedProps), inst.__dataPending);\n      inst.__dataPending = null;\n    } else {\n      // Original Polymer 2.x computed effects order, which continues running\n      // effects until no further computed properties have been invalidated\n      let inputProps = changedProps;\n      while (runEffects(inst, computeEffects, inputProps, oldProps, hasPaths)) {\n        Object.assign(/** @type {!Object} */ (oldProps), inst.__dataOld);\n        Object.assign(/** @type {!Object} */ (changedProps), inst.__dataPending);\n        inputProps = inst.__dataPending;\n        inst.__dataPending = null;\n      }\n    }\n  }\n}\n\n/**\n * Inserts a computed effect into a queue, given the specified order. Performs\n * the insert using a binary search.\n *\n * Used by `orderedComputed: true` computed property algorithm.\n *\n * @param {Object} info Property effects metadata\n * @param {Array<Object>} queue Ordered queue of effects\n * @param {Map<string,number>} order Map of computed property name->topological\n *   sort order\n */\nconst insertEffect = (info, queue, order) => {\n  let start = 0;\n  let end = queue.length - 1;\n  let idx = -1;\n  while (start <= end) {\n    const mid = (start + end) >> 1;\n    // Note `methodInfo` is where the computed property name is stored in\n    // the effect metadata\n    const cmp = order.get(queue[mid].methodInfo) - order.get(info.methodInfo);\n    if (cmp < 0) {\n      start = mid + 1;\n    } else if (cmp > 0) {\n      end = mid - 1;\n    } else {\n      idx = mid;\n      break;\n    }\n  }\n  if (idx < 0) {\n    idx = end + 1;\n  }\n  queue.splice(idx, 0, info);\n};\n\n/**\n * Inserts all downstream computed effects invalidated by the specified property\n * into the topologically-sorted queue of effects to be run.\n *\n * Used by `orderedComputed: true` computed property algorithm.\n *\n * @param {string} prop Property name\n * @param {Object} computeEffects Computed effects for this element\n * @param {Array<Object>} queue Topologically-sorted queue of computed effects\n *   to be run\n * @param {Map<string,number>} order Map of computed property name->topological\n *   sort order\n * @param {boolean} hasPaths True with `changedProps` contains one or more paths\n */\nconst enqueueEffectsFor = (prop, computeEffects, queue, order, hasPaths) => {\n  const rootProperty = hasPaths ? root(prop) : prop;\n  const fxs = computeEffects[rootProperty];\n  if (fxs) {\n    for (let i=0; i<fxs.length; i++) {\n      const fx = fxs[i];\n      if ((fx.info.lastRun !== dedupeId) &&\n          (!hasPaths || pathMatchesTrigger(prop, fx.trigger))) {\n        fx.info.lastRun = dedupeId;\n        insertEffect(fx.info, queue, order);\n      }\n    }\n  }\n};\n\n/**\n * Generates and retrieves a memoized map of computed property name to its\n * topologically-sorted order.\n *\n * The map is generated by first assigning a \"dependency count\" to each property\n * (defined as number properties it depends on, including its method for\n * \"dynamic functions\"). Any properties that have no dependencies are added to\n * the `ready` queue, which are properties whose order can be added to the final\n * order map. Properties are popped off the `ready` queue one by one and a.) added as\n * the next property in the order map, and b.) each property that it is a\n * dependency for has its dep count decremented (and if that property's dep\n * count goes to zero, it is added to the `ready` queue), until all properties\n * have been visited and ordered.\n *\n * Used by `orderedComputed: true` computed property algorithm.\n *\n * @param {!Polymer_PropertyEffects} inst The instance to retrieve the computed\n *   effect order for.\n * @return {Map<string,number>} Map of computed property name->topological sort\n *   order\n */\nfunction getComputedOrder(inst) {\n  let ordered = inst.constructor.__orderedComputedDeps;\n  if (!ordered) {\n    ordered = new Map();\n    const effects = inst[TYPES.COMPUTE];\n    let {counts, ready, total} = dependencyCounts(inst);\n    let curr;\n    while ((curr = ready.shift())) {\n      ordered.set(curr, ordered.size);\n      const computedByCurr = effects[curr];\n      if (computedByCurr) {\n        computedByCurr.forEach(fx => {\n          // Note `methodInfo` is where the computed property name is stored\n          const computedProp = fx.info.methodInfo;\n          --total;\n          if (--counts[computedProp] === 0) {\n            ready.push(computedProp);\n          }\n        });\n      }\n    }\n    if (total !== 0) {\n      const el = /** @type {HTMLElement} */ (inst);\n      console.warn(`Computed graph for ${el.localName} incomplete; circular?`);\n    }\n    inst.constructor.__orderedComputedDeps = ordered;\n  }\n  return ordered;\n}\n\n/**\n * Generates a map of property-to-dependency count (`counts`, where \"dependency\n * count\" is the number of dependencies a given property has assuming it is a\n * computed property, otherwise 0).  It also returns a pre-populated list of\n * `ready` properties that have no dependencies and a `total` count, which is\n * used for error-checking the graph.\n *\n * Used by `orderedComputed: true` computed property algorithm.\n *\n * @param {!Polymer_PropertyEffects} inst The instance to generate dependency\n *   counts for.\n * @return {!Object} Object containing `counts` map (property-to-dependency\n *   count) and pre-populated `ready` array of properties that had zero\n *   dependencies.\n */\nfunction dependencyCounts(inst) {\n  const infoForComputed = inst[COMPUTE_INFO];\n  const counts = {};\n  const computedDeps = inst[TYPES.COMPUTE];\n  const ready = [];\n  let total = 0;\n  // Count dependencies for each computed property\n  for (let p in infoForComputed) {\n    const info = infoForComputed[p];\n    // Be sure to add the method name itself in case of \"dynamic functions\"\n    total += counts[p] =\n      info.args.filter(a => !a.literal).length + (info.dynamicFn ? 1 : 0);\n  }\n  // Build list of ready properties (that aren't themselves computed)\n  for (let p in computedDeps) {\n    if (!infoForComputed[p]) {\n      ready.push(p);\n    }\n  }\n  return {counts, ready, total};\n}\n\n/**\n * Implements the \"computed property\" effect by running the method with the\n * values of the arguments specified in the `info` object and setting the\n * return value to the computed property specified.\n *\n * @param {!Polymer_PropertyEffects} inst The instance the effect will be run on\n * @param {string} property Name of property\n * @param {?Object} changedProps Bag of current property changes\n * @param {?Object} oldProps Bag of previous values for changed properties\n * @param {?} info Effect metadata\n * @return {boolean} True when the property being computed changed\n * @private\n */\nfunction runComputedEffect(inst, property, changedProps, oldProps, info) {\n  // Dirty check dependencies and run if any invalid\n  let result = runMethodEffect(inst, property, changedProps, oldProps, info);\n  // Abort if method returns a no-op result\n  if (result === NOOP) {\n    return false;\n  }\n  let computedProp = info.methodInfo;\n  if (inst.__dataHasAccessor && inst.__dataHasAccessor[computedProp]) {\n    return inst._setPendingProperty(computedProp, result, true);\n  } else {\n    inst[computedProp] = result;\n    return false;\n  }\n}\n\n/**\n * Computes path changes based on path links set up using the `linkPaths`\n * API.\n *\n * @param {!Polymer_PropertyEffects} inst The instance whose props are changing\n * @param {string} path Path that has changed\n * @param {*} value Value of changed path\n * @return {void}\n * @private\n */\nfunction computeLinkedPaths(inst, path, value) {\n  let links = inst.__dataLinkedPaths;\n  if (links) {\n    let link;\n    for (let a in links) {\n      let b = links[a];\n      if (isDescendant(a, path)) {\n        link = translate(a, b, path);\n        inst._setPendingPropertyOrPath(link, value, true, true);\n      } else if (isDescendant(b, path)) {\n        link = translate(b, a, path);\n        inst._setPendingPropertyOrPath(link, value, true, true);\n      }\n    }\n  }\n}\n\n// -- bindings ----------------------------------------------\n\n/**\n * Adds binding metadata to the current `nodeInfo`, and binding effects\n * for all part dependencies to `templateInfo`.\n *\n * @param {Function} constructor Class that `_parseTemplate` is currently\n *   running on\n * @param {TemplateInfo} templateInfo Template metadata for current template\n * @param {NodeInfo} nodeInfo Node metadata for current template node\n * @param {string} kind Binding kind, either 'property', 'attribute', or 'text'\n * @param {string} target Target property name\n * @param {!Array<!BindingPart>} parts Array of binding part metadata\n * @param {string=} literal Literal text surrounding binding parts (specified\n *   only for 'property' bindings, since these must be initialized as part\n *   of boot-up)\n * @return {void}\n * @private\n */\nfunction addBinding(constructor, templateInfo, nodeInfo, kind, target, parts, literal) {\n  // Create binding metadata and add to nodeInfo\n  nodeInfo.bindings = nodeInfo.bindings || [];\n  let /** Binding */ binding = { kind, target, parts, literal, isCompound: (parts.length !== 1) };\n  nodeInfo.bindings.push(binding);\n  // Add listener info to binding metadata\n  if (shouldAddListener(binding)) {\n    let {event, negate} = binding.parts[0];\n    binding.listenerEvent = event || (camelToDashCase(target) + '-changed');\n    binding.listenerNegate = negate;\n  }\n  // Add \"propagate\" property effects to templateInfo\n  let index = templateInfo.nodeInfoList.length;\n  for (let i=0; i<binding.parts.length; i++) {\n    let part = binding.parts[i];\n    part.compoundIndex = i;\n    addEffectForBindingPart(constructor, templateInfo, binding, part, index);\n  }\n}\n\n/**\n * Adds property effects to the given `templateInfo` for the given binding\n * part.\n *\n * @param {Function} constructor Class that `_parseTemplate` is currently\n *   running on\n * @param {TemplateInfo} templateInfo Template metadata for current template\n * @param {!Binding} binding Binding metadata\n * @param {!BindingPart} part Binding part metadata\n * @param {number} index Index into `nodeInfoList` for this node\n * @return {void}\n */\nfunction addEffectForBindingPart(constructor, templateInfo, binding, part, index) {\n  if (!part.literal) {\n    if (binding.kind === 'attribute' && binding.target[0] === '-') {\n      console.warn('Cannot set attribute ' + binding.target +\n        ' because \"-\" is not a valid attribute starting character');\n    } else {\n      let dependencies = part.dependencies;\n      let info = { index, binding, part, evaluator: constructor };\n      for (let j=0; j<dependencies.length; j++) {\n        let trigger = dependencies[j];\n        if (typeof trigger == 'string') {\n          trigger = parseArg(trigger);\n          trigger.wildcard = true;\n        }\n        constructor._addTemplatePropertyEffect(templateInfo, trigger.rootProperty, {\n          fn: runBindingEffect,\n          info, trigger\n        });\n      }\n    }\n  }\n}\n\n/**\n * Implements the \"binding\" (property/path binding) effect.\n *\n * Note that binding syntax is overridable via `_parseBindings` and\n * `_evaluateBinding`.  This method will call `_evaluateBinding` for any\n * non-literal parts returned from `_parseBindings`.  However,\n * there is no support for _path_ bindings via custom binding parts,\n * as this is specific to Polymer's path binding syntax.\n *\n * @param {!Polymer_PropertyEffects} inst The instance the effect will be run on\n * @param {string} path Name of property\n * @param {Object} props Bag of current property changes\n * @param {Object} oldProps Bag of previous values for changed properties\n * @param {?} info Effect metadata\n * @param {boolean} hasPaths True with `props` contains one or more paths\n * @param {Array} nodeList List of nodes associated with `nodeInfoList` template\n *   metadata\n * @return {void}\n * @private\n */\nfunction runBindingEffect(inst, path, props, oldProps, info, hasPaths, nodeList) {\n  let node = nodeList[info.index];\n  let binding = info.binding;\n  let part = info.part;\n  // Subpath notification: transform path and set to client\n  // e.g.: foo=\"{{obj.sub}}\", path: 'obj.sub.prop', set 'foo.prop'=obj.sub.prop\n  if (hasPaths && part.source && (path.length > part.source.length) &&\n      (binding.kind == 'property') && !binding.isCompound &&\n      node.__isPropertyEffectsClient &&\n      node.__dataHasAccessor && node.__dataHasAccessor[binding.target]) {\n    let value = props[path];\n    path = translate(part.source, binding.target, path);\n    if (node._setPendingPropertyOrPath(path, value, false, true)) {\n      inst._enqueueClient(node);\n    }\n  } else {\n    let value = info.evaluator._evaluateBinding(inst, part, path, props, oldProps, hasPaths);\n    // Propagate value to child\n    // Abort if value is a no-op result\n    if (value !== NOOP) {\n      applyBindingValue(inst, node, binding, part, value);\n    }\n  }\n}\n\n/**\n * Sets the value for an \"binding\" (binding) effect to a node,\n * either as a property or attribute.\n *\n * @param {!Polymer_PropertyEffects} inst The instance owning the binding effect\n * @param {Node} node Target node for binding\n * @param {!Binding} binding Binding metadata\n * @param {!BindingPart} part Binding part metadata\n * @param {*} value Value to set\n * @return {void}\n * @private\n */\nfunction applyBindingValue(inst, node, binding, part, value) {\n  value = computeBindingValue(node, value, binding, part);\n  if (sanitizeDOMValue) {\n    value = sanitizeDOMValue(value, binding.target, binding.kind, node);\n  }\n  if (binding.kind == 'attribute') {\n    // Attribute binding\n    inst._valueToNodeAttribute(/** @type {Element} */(node), value, binding.target);\n  } else {\n    // Property binding\n    let prop = binding.target;\n    if (node.__isPropertyEffectsClient &&\n        node.__dataHasAccessor && node.__dataHasAccessor[prop]) {\n      if (!node[TYPES.READ_ONLY] || !node[TYPES.READ_ONLY][prop]) {\n        if (node._setPendingProperty(prop, value)) {\n          inst._enqueueClient(node);\n        }\n      }\n    } else {\n      // In legacy no-batching mode, bindings applied before dataReady are\n      // equivalent to the \"apply config\" phase, which only set managed props\n      inst._setUnmanagedPropertyToNode(node, prop, value);\n    }\n  }\n}\n\n/**\n * Transforms an \"binding\" effect value based on compound & negation\n * effect metadata, as well as handling for special-case properties\n *\n * @param {Node} node Node the value will be set to\n * @param {*} value Value to set\n * @param {!Binding} binding Binding metadata\n * @param {!BindingPart} part Binding part metadata\n * @return {*} Transformed value to set\n * @private\n */\nfunction computeBindingValue(node, value, binding, part) {\n  if (binding.isCompound) {\n    let storage = node.__dataCompoundStorage[binding.target];\n    storage[part.compoundIndex] = value;\n    value = storage.join('');\n  }\n  if (binding.kind !== 'attribute') {\n    // Some browsers serialize `undefined` to `\"undefined\"`\n    if (binding.target === 'textContent' ||\n        (binding.target === 'value' &&\n          (node.localName === 'input' || node.localName === 'textarea'))) {\n      value = value == undefined ? '' : value;\n    }\n  }\n  return value;\n}\n\n/**\n * Returns true if a binding's metadata meets all the requirements to allow\n * 2-way binding, and therefore a `<property>-changed` event listener should be\n * added:\n * - used curly braces\n * - is a property (not attribute) binding\n * - is not a textContent binding\n * - is not compound\n *\n * @param {!Binding} binding Binding metadata\n * @return {boolean} True if 2-way listener should be added\n * @private\n */\nfunction shouldAddListener(binding) {\n  return Boolean(binding.target) &&\n         binding.kind != 'attribute' &&\n         binding.kind != 'text' &&\n         !binding.isCompound &&\n         binding.parts[0].mode === '{';\n}\n\n/**\n * Setup compound binding storage structures, notify listeners, and dataHost\n * references onto the bound nodeList.\n *\n * @param {!Polymer_PropertyEffects} inst Instance that bas been previously\n *     bound\n * @param {TemplateInfo} templateInfo Template metadata\n * @return {void}\n * @private\n */\nfunction setupBindings(inst, templateInfo) {\n  // Setup compound storage, dataHost, and notify listeners\n  let {nodeList, nodeInfoList} = templateInfo;\n  if (nodeInfoList.length) {\n    for (let i=0; i < nodeInfoList.length; i++) {\n      let info = nodeInfoList[i];\n      let node = nodeList[i];\n      let bindings = info.bindings;\n      if (bindings) {\n        for (let i=0; i<bindings.length; i++) {\n          let binding = bindings[i];\n          setupCompoundStorage(node, binding);\n          addNotifyListener(node, inst, binding);\n        }\n      }\n      // This ensures all bound elements have a host set, regardless\n      // of whether they upgrade synchronous to creation\n      node.__dataHost = inst;\n    }\n  }\n}\n\n/**\n * Initializes `__dataCompoundStorage` local storage on a bound node with\n * initial literal data for compound bindings, and sets the joined\n * literal parts to the bound property.\n *\n * When changes to compound parts occur, they are first set into the compound\n * storage array for that property, and then the array is joined to result in\n * the final value set to the property/attribute.\n *\n * @param {Node} node Bound node to initialize\n * @param {Binding} binding Binding metadata\n * @return {void}\n * @private\n */\nfunction setupCompoundStorage(node, binding) {\n  if (binding.isCompound) {\n    // Create compound storage map\n    let storage = node.__dataCompoundStorage ||\n      (node.__dataCompoundStorage = {});\n    let parts = binding.parts;\n    // Copy literals from parts into storage for this binding\n    let literals = new Array(parts.length);\n    for (let j=0; j<parts.length; j++) {\n      literals[j] = parts[j].literal;\n    }\n    let target = binding.target;\n    storage[target] = literals;\n    // Configure properties with their literal parts\n    if (binding.literal && binding.kind == 'property') {\n      // Note, className needs style scoping so this needs wrapping.\n      // We may also want to consider doing this for `textContent` and\n      // `innerHTML`.\n      if (target === 'className') {\n        node = wrap(node);\n      }\n      node[target] = binding.literal;\n    }\n  }\n}\n\n/**\n * Adds a 2-way binding notification event listener to the node specified\n *\n * @param {Object} node Child element to add listener to\n * @param {!Polymer_PropertyEffects} inst Host element instance to handle\n *     notification event\n * @param {Binding} binding Binding metadata\n * @return {void}\n * @private\n */\nfunction addNotifyListener(node, inst, binding) {\n  if (binding.listenerEvent) {\n    let part = binding.parts[0];\n    node.addEventListener(binding.listenerEvent, function(e) {\n      handleNotification(e, inst, binding.target, part.source, part.negate);\n    });\n  }\n}\n\n// -- for method-based effects (complexObserver & computed) --------------\n\n/**\n * Adds property effects for each argument in the method signature (and\n * optionally, for the method name if `dynamic` is true) that calls the\n * provided effect function.\n *\n * @param {Element | Object} model Prototype or instance\n * @param {!MethodSignature} sig Method signature metadata\n * @param {string} type Type of property effect to add\n * @param {Function} effectFn Function to run when arguments change\n * @param {*=} methodInfo Effect-specific information to be included in\n *   method effect metadata\n * @param {boolean|Object=} dynamicFn Boolean or object map indicating whether\n *   method names should be included as a dependency to the effect. Note,\n *   defaults to true if the signature is static (sig.static is true).\n * @return {!Object} Effect metadata for this method effect\n * @private\n */\nfunction createMethodEffect(model, sig, type, effectFn, methodInfo, dynamicFn) {\n  dynamicFn = sig.static || (dynamicFn &&\n    (typeof dynamicFn !== 'object' || dynamicFn[sig.methodName]));\n  let info = {\n    methodName: sig.methodName,\n    args: sig.args,\n    methodInfo,\n    dynamicFn\n  };\n  for (let i=0, arg; (i<sig.args.length) && (arg=sig.args[i]); i++) {\n    if (!arg.literal) {\n      model._addPropertyEffect(arg.rootProperty, type, {\n        fn: effectFn, info: info, trigger: arg\n      });\n    }\n  }\n  if (dynamicFn) {\n    model._addPropertyEffect(sig.methodName, type, {\n      fn: effectFn, info: info\n    });\n  }\n  return info;\n}\n\n/**\n * Calls a method with arguments marshaled from properties on the instance\n * based on the method signature contained in the effect metadata.\n *\n * Multi-property observers, computed properties, and inline computing\n * functions call this function to invoke the method, then use the return\n * value accordingly.\n *\n * @param {!Polymer_PropertyEffects} inst The instance the effect will be run on\n * @param {string} property Name of property\n * @param {Object} props Bag of current property changes\n * @param {Object} oldProps Bag of previous values for changed properties\n * @param {?} info Effect metadata\n * @return {*} Returns the return value from the method invocation\n * @private\n */\nfunction runMethodEffect(inst, property, props, oldProps, info) {\n  // Instances can optionally have a _methodHost which allows redirecting where\n  // to find methods. Currently used by `templatize`.\n  let context = inst._methodHost || inst;\n  let fn = context[info.methodName];\n  if (fn) {\n    let args = inst._marshalArgs(info.args, property, props);\n    return args === NOOP ? NOOP : fn.apply(context, args);\n  } else if (!info.dynamicFn) {\n    console.warn('method `' + info.methodName + '` not defined');\n  }\n}\n\nconst emptyArray = [];\n\n// Regular expressions used for binding\nconst IDENT  = '(?:' + '[a-zA-Z_$][\\\\w.:$\\\\-*]*' + ')';\nconst NUMBER = '(?:' + '[-+]?[0-9]*\\\\.?[0-9]+(?:[eE][-+]?[0-9]+)?' + ')';\nconst SQUOTE_STRING = '(?:' + '\\'(?:[^\\'\\\\\\\\]|\\\\\\\\.)*\\'' + ')';\nconst DQUOTE_STRING = '(?:' + '\"(?:[^\"\\\\\\\\]|\\\\\\\\.)*\"' + ')';\nconst STRING = '(?:' + SQUOTE_STRING + '|' + DQUOTE_STRING + ')';\nconst ARGUMENT = '(?:(' + IDENT + '|' + NUMBER + '|' +  STRING + ')\\\\s*' + ')';\nconst ARGUMENTS = '(?:' + ARGUMENT + '(?:,\\\\s*' + ARGUMENT + ')*' + ')';\nconst ARGUMENT_LIST = '(?:' + '\\\\(\\\\s*' +\n                              '(?:' + ARGUMENTS + '?' + ')' +\n                            '\\\\)\\\\s*' + ')';\nconst BINDING = '(' + IDENT + '\\\\s*' + ARGUMENT_LIST + '?' + ')'; // Group 3\nconst OPEN_BRACKET = '(\\\\[\\\\[|{{)' + '\\\\s*';\nconst CLOSE_BRACKET = '(?:]]|}})';\nconst NEGATE = '(?:(!)\\\\s*)?'; // Group 2\nconst EXPRESSION = OPEN_BRACKET + NEGATE + BINDING + CLOSE_BRACKET;\nconst bindingRegex = new RegExp(EXPRESSION, \"g\");\n\n/**\n * Create a string from binding parts of all the literal parts\n *\n * @param {!Array<BindingPart>} parts All parts to stringify\n * @return {string} String made from the literal parts\n */\nfunction literalFromParts(parts) {\n  let s = '';\n  for (let i=0; i<parts.length; i++) {\n    let literal = parts[i].literal;\n    s += literal || '';\n  }\n  return s;\n}\n\n/**\n * Parses an expression string for a method signature, and returns a metadata\n * describing the method in terms of `methodName`, `static` (whether all the\n * arguments are literals), and an array of `args`\n *\n * @param {string} expression The expression to parse\n * @return {?MethodSignature} The method metadata object if a method expression was\n *   found, otherwise `undefined`\n * @private\n */\nfunction parseMethod(expression) {\n  // tries to match valid javascript property names\n  let m = expression.match(/([^\\s]+?)\\(([\\s\\S]*)\\)/);\n  if (m) {\n    let methodName = m[1];\n    let sig = { methodName, static: true, args: emptyArray };\n    if (m[2].trim()) {\n      // replace escaped commas with comma entity, split on un-escaped commas\n      let args = m[2].replace(/\\\\,/g, '&comma;').split(',');\n      return parseArgs(args, sig);\n    } else {\n      return sig;\n    }\n  }\n  return null;\n}\n\n/**\n * Parses an array of arguments and sets the `args` property of the supplied\n * signature metadata object. Sets the `static` property to false if any\n * argument is a non-literal.\n *\n * @param {!Array<string>} argList Array of argument names\n * @param {!MethodSignature} sig Method signature metadata object\n * @return {!MethodSignature} The updated signature metadata object\n * @private\n */\nfunction parseArgs(argList, sig) {\n  sig.args = argList.map(function(rawArg) {\n    let arg = parseArg(rawArg);\n    if (!arg.literal) {\n      sig.static = false;\n    }\n    return arg;\n  }, this);\n  return sig;\n}\n\n/**\n * Parses an individual argument, and returns an argument metadata object\n * with the following fields:\n *\n *   {\n *     value: 'prop',        // property/path or literal value\n *     literal: false,       // whether argument is a literal\n *     structured: false,    // whether the property is a path\n *     rootProperty: 'prop', // the root property of the path\n *     wildcard: false       // whether the argument was a wildcard '.*' path\n *   }\n *\n * @param {string} rawArg The string value of the argument\n * @return {!MethodArg} Argument metadata object\n * @private\n */\nfunction parseArg(rawArg) {\n  // clean up whitespace\n  let arg = rawArg.trim()\n    // replace comma entity with comma\n    .replace(/&comma;/g, ',')\n    // repair extra escape sequences; note only commas strictly need\n    // escaping, but we allow any other char to be escaped since its\n    // likely users will do this\n    .replace(/\\\\(.)/g, '$1')\n    ;\n  // basic argument descriptor\n  let a = {\n    name: arg,\n    value: '',\n    literal: false\n  };\n  // detect literal value (must be String or Number)\n  let fc = arg[0];\n  if (fc === '-') {\n    fc = arg[1];\n  }\n  if (fc >= '0' && fc <= '9') {\n    fc = '#';\n  }\n  switch(fc) {\n    case \"'\":\n    case '\"':\n      a.value = arg.slice(1, -1);\n      a.literal = true;\n      break;\n    case '#':\n      a.value = Number(arg);\n      a.literal = true;\n      break;\n  }\n  // if not literal, look for structured path\n  if (!a.literal) {\n    a.rootProperty = root(arg);\n    // detect structured path (has dots)\n    a.structured = isPath(arg);\n    if (a.structured) {\n      a.wildcard = (arg.slice(-2) == '.*');\n      if (a.wildcard) {\n        a.name = arg.slice(0, -2);\n      }\n    }\n  }\n  return a;\n}\n\nfunction getArgValue(data, props, path) {\n  let value = get(data, path);\n  // when data is not stored e.g. `splices`, get the value from changedProps\n  // TODO(kschaaf): Note, this can cause a rare issue where the wildcard\n  // info.value could pull a stale value out of changedProps during a reentrant\n  // change that sets the value back to undefined.\n  // https://github.com/Polymer/polymer/issues/5479\n  if (value === undefined) {\n    value = props[path];\n  }\n  return value;\n}\n\n// data api\n\n/**\n * Sends array splice notifications (`.splices` and `.length`)\n *\n * Note: this implementation only accepts normalized paths\n *\n * @param {!Polymer_PropertyEffects} inst Instance to send notifications to\n * @param {Array} array The array the mutations occurred on\n * @param {string} path The path to the array that was mutated\n * @param {Array} splices Array of splice records\n * @return {void}\n * @private\n */\nfunction notifySplices(inst, array, path, splices) {\n  const splicesData = { indexSplices: splices };\n  // Legacy behavior stored splices in `__data__` so it was *not* ephemeral.\n  // To match this behavior, we store splices directly on the array.\n  if (legacyUndefined && !inst._overrideLegacyUndefined) {\n    array.splices = splicesData;\n  }\n  inst.notifyPath(path + '.splices', splicesData);\n  inst.notifyPath(path + '.length', array.length);\n  // Clear splice data only when it's stored on the array.\n  if (legacyUndefined && !inst._overrideLegacyUndefined) {\n    splicesData.indexSplices = [];\n  }\n}\n\n/**\n * Creates a splice record and sends an array splice notification for\n * the described mutation\n *\n * Note: this implementation only accepts normalized paths\n *\n * @param {!Polymer_PropertyEffects} inst Instance to send notifications to\n * @param {Array} array The array the mutations occurred on\n * @param {string} path The path to the array that was mutated\n * @param {number} index Index at which the array mutation occurred\n * @param {number} addedCount Number of added items\n * @param {Array} removed Array of removed items\n * @return {void}\n * @private\n */\nfunction notifySplice(inst, array, path, index, addedCount, removed) {\n  notifySplices(inst, array, path, [{\n    index: index,\n    addedCount: addedCount,\n    removed: removed,\n    object: array,\n    type: 'splice'\n  }]);\n}\n\n/**\n * Returns an upper-cased version of the string.\n *\n * @param {string} name String to uppercase\n * @return {string} Uppercased string\n * @private\n */\nfunction upper(name) {\n  return name[0].toUpperCase() + name.substring(1);\n}\n\n/**\n * Element class mixin that provides meta-programming for Polymer's template\n * binding and data observation (collectively, \"property effects\") system.\n *\n * This mixin uses provides the following key static methods for adding\n * property effects to an element class:\n * - `addPropertyEffect`\n * - `createPropertyObserver`\n * - `createMethodObserver`\n * - `createNotifyingProperty`\n * - `createReadOnlyProperty`\n * - `createReflectedProperty`\n * - `createComputedProperty`\n * - `bindTemplate`\n *\n * Each method creates one or more property accessors, along with metadata\n * used by this mixin's implementation of `_propertiesChanged` to perform\n * the property effects.\n *\n * Underscored versions of the above methods also exist on the element\n * prototype for adding property effects on instances at runtime.\n *\n * Note that this mixin overrides several `PropertyAccessors` methods, in\n * many cases to maintain guarantees provided by the Polymer 1.x features;\n * notably it changes property accessors to be synchronous by default\n * whereas the default when using `PropertyAccessors` standalone is to be\n * async by default.\n *\n * @mixinFunction\n * @polymer\n * @appliesMixin TemplateStamp\n * @appliesMixin PropertyAccessors\n * @summary Element class mixin that provides meta-programming for Polymer's\n * template binding and data observation system.\n */\nexport const PropertyEffects = dedupingMixin(superClass => {\n\n  /**\n   * @constructor\n   * @implements {Polymer_PropertyAccessors}\n   * @implements {Polymer_TemplateStamp}\n   * @unrestricted\n   * @private\n   */\n  const propertyEffectsBase = TemplateStamp(PropertyAccessors(superClass));\n\n  /**\n   * @polymer\n   * @mixinClass\n   * @implements {Polymer_PropertyEffects}\n   * @extends {propertyEffectsBase}\n   * @unrestricted\n   */\n  class PropertyEffects extends propertyEffectsBase {\n\n    constructor() {\n      super();\n      /** @type {boolean} */\n      // Used to identify users of this mixin, ala instanceof\n      this.__isPropertyEffectsClient = true;\n      /** @type {boolean} */\n      this.__dataClientsReady;\n      /** @type {Array} */\n      this.__dataPendingClients;\n      /** @type {Object} */\n      this.__dataToNotify;\n      /** @type {Object} */\n      this.__dataLinkedPaths;\n      /** @type {boolean} */\n      this.__dataHasPaths;\n      /** @type {Object} */\n      this.__dataCompoundStorage;\n      /** @type {Polymer_PropertyEffects} */\n      this.__dataHost;\n      /** @type {!Object} */\n      this.__dataTemp;\n      /** @type {boolean} */\n      this.__dataClientsInitialized;\n      /** @type {!Object} */\n      this.__data;\n      /** @type {!Object|null} */\n      this.__dataPending;\n      /** @type {!Object} */\n      this.__dataOld;\n      /** @type {Object} */\n      this.__computeEffects;\n      /** @type {Object} */\n      this.__computeInfo;\n      /** @type {Object} */\n      this.__reflectEffects;\n      /** @type {Object} */\n      this.__notifyEffects;\n      /** @type {Object} */\n      this.__propagateEffects;\n      /** @type {Object} */\n      this.__observeEffects;\n      /** @type {Object} */\n      this.__readOnly;\n      /** @type {!TemplateInfo} */\n      this.__templateInfo;\n      /** @type {boolean} */\n      this._overrideLegacyUndefined;\n    }\n\n    get PROPERTY_EFFECT_TYPES() {\n      return TYPES;\n    }\n\n    /**\n     * @override\n     * @return {void}\n     */\n    _initializeProperties() {\n      super._initializeProperties();\n      this._registerHost();\n      this.__dataClientsReady = false;\n      this.__dataPendingClients = null;\n      this.__dataToNotify = null;\n      this.__dataLinkedPaths = null;\n      this.__dataHasPaths = false;\n      // May be set on instance prior to upgrade\n      this.__dataCompoundStorage = this.__dataCompoundStorage || null;\n      this.__dataHost = this.__dataHost || null;\n      this.__dataTemp = {};\n      this.__dataClientsInitialized = false;\n    }\n\n    _registerHost() {\n      if (hostStack.length) {\n        let host = hostStack[hostStack.length-1];\n        host._enqueueClient(this);\n        // This ensures even non-bound elements have a host set, as\n        // long as they upgrade synchronously\n        this.__dataHost = host;\n      }\n    }\n\n    /**\n     * Overrides `PropertyAccessors` implementation to provide a\n     * more efficient implementation of initializing properties from\n     * the prototype on the instance.\n     *\n     * @override\n     * @param {Object} props Properties to initialize on the prototype\n     * @return {void}\n     */\n    _initializeProtoProperties(props) {\n      this.__data = Object.create(props);\n      this.__dataPending = Object.create(props);\n      this.__dataOld = {};\n    }\n\n    /**\n     * Overrides `PropertyAccessors` implementation to avoid setting\n     * `_setProperty`'s `shouldNotify: true`.\n     *\n     * @override\n     * @param {Object} props Properties to initialize on the instance\n     * @return {void}\n     */\n    _initializeInstanceProperties(props) {\n      let readOnly = this[TYPES.READ_ONLY];\n      for (let prop in props) {\n        if (!readOnly || !readOnly[prop]) {\n          this.__dataPending = this.__dataPending || {};\n          this.__dataOld = this.__dataOld || {};\n          this.__data[prop] = this.__dataPending[prop] = props[prop];\n        }\n      }\n    }\n\n    // Prototype setup ----------------------------------------\n\n    /**\n     * Equivalent to static `addPropertyEffect` API but can be called on\n     * an instance to add effects at runtime.  See that method for\n     * full API docs.\n     *\n     * @override\n     * @param {string} property Property that should trigger the effect\n     * @param {string} type Effect type, from this.PROPERTY_EFFECT_TYPES\n     * @param {Object=} effect Effect metadata object\n     * @return {void}\n     * @protected\n     */\n    _addPropertyEffect(property, type, effect) {\n      this._createPropertyAccessor(property, type == TYPES.READ_ONLY);\n      // effects are accumulated into arrays per property based on type\n      let effects = ensureOwnEffectMap(this, type, true)[property];\n      if (!effects) {\n        effects = this[type][property] = [];\n      }\n      effects.push(effect);\n    }\n\n    /**\n     * Removes the given property effect.\n     *\n     * @override\n     * @param {string} property Property the effect was associated with\n     * @param {string} type Effect type, from this.PROPERTY_EFFECT_TYPES\n     * @param {Object=} effect Effect metadata object to remove\n     * @return {void}\n     */\n    _removePropertyEffect(property, type, effect) {\n      let effects = ensureOwnEffectMap(this, type, true)[property];\n      let idx = effects.indexOf(effect);\n      if (idx >= 0) {\n        effects.splice(idx, 1);\n      }\n    }\n\n    /**\n     * Returns whether the current prototype/instance has a property effect\n     * of a certain type.\n     *\n     * @override\n     * @param {string} property Property name\n     * @param {string=} type Effect type, from this.PROPERTY_EFFECT_TYPES\n     * @return {boolean} True if the prototype/instance has an effect of this\n     *     type\n     * @protected\n     */\n    _hasPropertyEffect(property, type) {\n      let effects = this[type];\n      return Boolean(effects && effects[property]);\n    }\n\n    /**\n     * Returns whether the current prototype/instance has a \"read only\"\n     * accessor for the given property.\n     *\n     * @override\n     * @param {string} property Property name\n     * @return {boolean} True if the prototype/instance has an effect of this\n     *     type\n     * @protected\n     */\n    _hasReadOnlyEffect(property) {\n      return this._hasPropertyEffect(property, TYPES.READ_ONLY);\n    }\n\n    /**\n     * Returns whether the current prototype/instance has a \"notify\"\n     * property effect for the given property.\n     *\n     * @override\n     * @param {string} property Property name\n     * @return {boolean} True if the prototype/instance has an effect of this\n     *     type\n     * @protected\n     */\n    _hasNotifyEffect(property) {\n      return this._hasPropertyEffect(property, TYPES.NOTIFY);\n    }\n\n    /**\n     * Returns whether the current prototype/instance has a \"reflect to\n     * attribute\" property effect for the given property.\n     *\n     * @override\n     * @param {string} property Property name\n     * @return {boolean} True if the prototype/instance has an effect of this\n     *     type\n     * @protected\n     */\n    _hasReflectEffect(property) {\n      return this._hasPropertyEffect(property, TYPES.REFLECT);\n    }\n\n    /**\n     * Returns whether the current prototype/instance has a \"computed\"\n     * property effect for the given property.\n     *\n     * @override\n     * @param {string} property Property name\n     * @return {boolean} True if the prototype/instance has an effect of this\n     *     type\n     * @protected\n     */\n    _hasComputedEffect(property) {\n      return this._hasPropertyEffect(property, TYPES.COMPUTE);\n    }\n\n    // Runtime ----------------------------------------\n\n    /**\n     * Sets a pending property or path.  If the root property of the path in\n     * question had no accessor, the path is set, otherwise it is enqueued\n     * via `_setPendingProperty`.\n     *\n     * This function isolates relatively expensive functionality necessary\n     * for the public API (`set`, `setProperties`, `notifyPath`, and property\n     * change listeners via {{...}} bindings), such that it is only done\n     * when paths enter the system, and not at every propagation step.  It\n     * also sets a `__dataHasPaths` flag on the instance which is used to\n     * fast-path slower path-matching code in the property effects host paths.\n     *\n     * `path` can be a path string or array of path parts as accepted by the\n     * public API.\n     *\n     * @override\n     * @param {string | !Array<number|string>} path Path to set\n     * @param {*} value Value to set\n     * @param {boolean=} shouldNotify Set to true if this change should\n     *  cause a property notification event dispatch\n     * @param {boolean=} isPathNotification If the path being set is a path\n     *   notification of an already changed value, as opposed to a request\n     *   to set and notify the change.  In the latter `false` case, a dirty\n     *   check is performed and then the value is set to the path before\n     *   enqueuing the pending property change.\n     * @return {boolean} Returns true if the property/path was enqueued in\n     *   the pending changes bag.\n     * @protected\n     */\n    _setPendingPropertyOrPath(path, value, shouldNotify, isPathNotification) {\n      if (isPathNotification ||\n          root(Array.isArray(path) ? path[0] : path) !== path) {\n        // Dirty check changes being set to a path against the actual object,\n        // since this is the entry point for paths into the system; from here\n        // the only dirty checks are against the `__dataTemp` cache to prevent\n        // duplicate work in the same turn only. Note, if this was a notification\n        // of a change already set to a path (isPathNotification: true),\n        // we always let the change through and skip the `set` since it was\n        // already dirty checked at the point of entry and the underlying\n        // object has already been updated\n        if (!isPathNotification) {\n          let old = get(this, path);\n          path = /** @type {string} */ (set(this, path, value));\n          // Use property-accessor's simpler dirty check\n          if (!path || !super._shouldPropertyChange(path, value, old)) {\n            return false;\n          }\n        }\n        this.__dataHasPaths = true;\n        if (this._setPendingProperty(/**@type{string}*/(path), value, shouldNotify)) {\n          computeLinkedPaths(this, /**@type{string}*/ (path), value);\n          return true;\n        }\n      } else {\n        if (this.__dataHasAccessor && this.__dataHasAccessor[path]) {\n          return this._setPendingProperty(/**@type{string}*/(path), value, shouldNotify);\n        } else {\n          this[path] = value;\n        }\n      }\n      return false;\n    }\n\n    /**\n     * Applies a value to a non-Polymer element/node's property.\n     *\n     * The implementation makes a best-effort at binding interop:\n     * Some native element properties have side-effects when\n     * re-setting the same value (e.g. setting `<input>.value` resets the\n     * cursor position), so we do a dirty-check before setting the value.\n     * However, for better interop with non-Polymer custom elements that\n     * accept objects, we explicitly re-set object changes coming from the\n     * Polymer world (which may include deep object changes without the\n     * top reference changing), erring on the side of providing more\n     * information.\n     *\n     * Users may override this method to provide alternate approaches.\n     *\n     * @override\n     * @param {!Node} node The node to set a property on\n     * @param {string} prop The property to set\n     * @param {*} value The value to set\n     * @return {void}\n     * @protected\n     */\n    _setUnmanagedPropertyToNode(node, prop, value) {\n      // It is a judgment call that resetting primitives is\n      // \"bad\" and resettings objects is also \"good\"; alternatively we could\n      // implement a whitelist of tag & property values that should never\n      // be reset (e.g. <input>.value && <select>.value)\n      if (value !== node[prop] || typeof value == 'object') {\n        // Note, className needs style scoping so this needs wrapping.\n        if (prop === 'className') {\n          node = /** @type {!Node} */(wrap(node));\n        }\n        node[prop] = value;\n      }\n    }\n\n    /**\n     * Overrides the `PropertiesChanged` implementation to introduce special\n     * dirty check logic depending on the property & value being set:\n     *\n     * 1. Any value set to a path (e.g. 'obj.prop': 42 or 'obj.prop': {...})\n     *    Stored in `__dataTemp`, dirty checked against `__dataTemp`\n     * 2. Object set to simple property (e.g. 'prop': {...})\n     *    Stored in `__dataTemp` and `__data`, dirty checked against\n     *    `__dataTemp` by default implementation of `_shouldPropertyChange`\n     * 3. Primitive value set to simple property (e.g. 'prop': 42)\n     *    Stored in `__data`, dirty checked against `__data`\n     *\n     * The dirty-check is important to prevent cycles due to two-way\n     * notification, but paths and objects are only dirty checked against any\n     * previous value set during this turn via a \"temporary cache\" that is\n     * cleared when the last `_propertiesChanged` exits. This is so:\n     * a. any cached array paths (e.g. 'array.3.prop') may be invalidated\n     *    due to array mutations like shift/unshift/splice; this is fine\n     *    since path changes are dirty-checked at user entry points like `set`\n     * b. dirty-checking for objects only lasts one turn to allow the user\n     *    to mutate the object in-place and re-set it with the same identity\n     *    and have all sub-properties re-propagated in a subsequent turn.\n     *\n     * The temp cache is not necessarily sufficient to prevent invalid array\n     * paths, since a splice can happen during the same turn (with pathological\n     * user code); we could introduce a \"fixup\" for temporarily cached array\n     * paths if needed: https://github.com/Polymer/polymer/issues/4227\n     *\n     * @override\n     * @param {string} property Name of the property\n     * @param {*} value Value to set\n     * @param {boolean=} shouldNotify True if property should fire notification\n     *   event (applies only for `notify: true` properties)\n     * @return {boolean} Returns true if the property changed\n     */\n    _setPendingProperty(property, value, shouldNotify) {\n      let propIsPath = this.__dataHasPaths && isPath(property);\n      let prevProps = propIsPath ? this.__dataTemp : this.__data;\n      if (this._shouldPropertyChange(property, value, prevProps[property])) {\n        if (!this.__dataPending) {\n          this.__dataPending = {};\n          this.__dataOld = {};\n        }\n        // Ensure old is captured from the last turn\n        if (!(property in this.__dataOld)) {\n          this.__dataOld[property] = this.__data[property];\n        }\n        // Paths are stored in temporary cache (cleared at end of turn),\n        // which is used for dirty-checking, all others stored in __data\n        if (propIsPath) {\n          this.__dataTemp[property] = value;\n        } else {\n          this.__data[property] = value;\n        }\n        // All changes go into pending property bag, passed to _propertiesChanged\n        this.__dataPending[property] = value;\n        // Track properties that should notify separately\n        if (propIsPath || (this[TYPES.NOTIFY] && this[TYPES.NOTIFY][property])) {\n          this.__dataToNotify = this.__dataToNotify || {};\n          this.__dataToNotify[property] = shouldNotify;\n        }\n        return true;\n      }\n      return false;\n    }\n\n    /**\n     * Overrides base implementation to ensure all accessors set `shouldNotify`\n     * to true, for per-property notification tracking.\n     *\n     * @override\n     * @param {string} property Name of the property\n     * @param {*} value Value to set\n     * @return {void}\n     */\n    _setProperty(property, value) {\n      if (this._setPendingProperty(property, value, true)) {\n        this._invalidateProperties();\n      }\n    }\n\n    /**\n     * Overrides `PropertyAccessor`'s default async queuing of\n     * `_propertiesChanged`: if `__dataReady` is false (has not yet been\n     * manually flushed), the function no-ops; otherwise flushes\n     * `_propertiesChanged` synchronously.\n     *\n     * @override\n     * @return {void}\n     */\n    _invalidateProperties() {\n      if (this.__dataReady) {\n        this._flushProperties();\n      }\n    }\n\n    /**\n     * Enqueues the given client on a list of pending clients, whose\n     * pending property changes can later be flushed via a call to\n     * `_flushClients`.\n     *\n     * @override\n     * @param {Object} client PropertyEffects client to enqueue\n     * @return {void}\n     * @protected\n     */\n    _enqueueClient(client) {\n      this.__dataPendingClients = this.__dataPendingClients || [];\n      if (client !== this) {\n        this.__dataPendingClients.push(client);\n      }\n    }\n\n    /**\n     * Flushes any clients previously enqueued via `_enqueueClient`, causing\n     * their `_flushProperties` method to run.\n     *\n     * @override\n     * @return {void}\n     * @protected\n     */\n    _flushClients() {\n      if (!this.__dataClientsReady) {\n        this.__dataClientsReady = true;\n        this._readyClients();\n        // Override point where accessors are turned on; importantly,\n        // this is after clients have fully readied, providing a guarantee\n        // that any property effects occur only after all clients are ready.\n        this.__dataReady = true;\n      } else {\n        this.__enableOrFlushClients();\n      }\n    }\n\n    // NOTE: We ensure clients either enable or flush as appropriate. This\n    // handles two corner cases:\n    // (1) clients flush properly when connected/enabled before the host\n    // enables; e.g.\n    //   (a) Templatize stamps with no properties and does not flush and\n    //   (b) the instance is inserted into dom and\n    //   (c) then the instance flushes.\n    // (2) clients enable properly when not connected/enabled when the host\n    // flushes; e.g.\n    //   (a) a template is runtime stamped and not yet connected/enabled\n    //   (b) a host sets a property, causing stamped dom to flush\n    //   (c) the stamped dom enables.\n    __enableOrFlushClients() {\n      let clients = this.__dataPendingClients;\n      if (clients) {\n        this.__dataPendingClients = null;\n        for (let i=0; i < clients.length; i++) {\n          let client = clients[i];\n          if (!client.__dataEnabled) {\n            client._enableProperties();\n          } else if (client.__dataPending) {\n            client._flushProperties();\n          }\n        }\n      }\n    }\n\n    /**\n     * Perform any initial setup on client dom. Called before the first\n     * `_flushProperties` call on client dom and before any element\n     * observers are called.\n     *\n     * @override\n     * @return {void}\n     * @protected\n     */\n    _readyClients() {\n      this.__enableOrFlushClients();\n    }\n\n    /**\n     * Sets a bag of property changes to this instance, and\n     * synchronously processes all effects of the properties as a batch.\n     *\n     * Property names must be simple properties, not paths.  Batched\n     * path propagation is not supported.\n     *\n     * @override\n     * @param {Object} props Bag of one or more key-value pairs whose key is\n     *   a property and value is the new value to set for that property.\n     * @param {boolean=} setReadOnly When true, any private values set in\n     *   `props` will be set. By default, `setProperties` will not set\n     *   `readOnly: true` root properties.\n     * @return {void}\n     * @public\n     */\n    setProperties(props, setReadOnly) {\n      for (let path in props) {\n        if (setReadOnly || !this[TYPES.READ_ONLY] || !this[TYPES.READ_ONLY][path]) {\n          //TODO(kschaaf): explicitly disallow paths in setProperty?\n          // wildcard observers currently only pass the first changed path\n          // in the `info` object, and you could do some odd things batching\n          // paths, e.g. {'foo.bar': {...}, 'foo': null}\n          this._setPendingPropertyOrPath(path, props[path], true);\n        }\n      }\n      this._invalidateProperties();\n    }\n\n    /**\n     * Overrides `PropertyAccessors` so that property accessor\n     * side effects are not enabled until after client dom is fully ready.\n     * Also calls `_flushClients` callback to ensure client dom is enabled\n     * that was not enabled as a result of flushing properties.\n     *\n     * @override\n     * @return {void}\n     */\n    ready() {\n      // It is important that `super.ready()` is not called here as it\n      // immediately turns on accessors. Instead, we wait until `readyClients`\n      // to enable accessors to provide a guarantee that clients are ready\n      // before processing any accessors side effects.\n      this._flushProperties();\n      // If no data was pending, `_flushProperties` will not `flushClients`\n      // so ensure this is done.\n      if (!this.__dataClientsReady) {\n        this._flushClients();\n      }\n      // Before ready, client notifications do not trigger _flushProperties.\n      // Therefore a flush is necessary here if data has been set.\n      if (this.__dataPending) {\n        this._flushProperties();\n      }\n    }\n\n    /**\n     * Implements `PropertyAccessors`'s properties changed callback.\n     *\n     * Runs each class of effects for the batch of changed properties in\n     * a specific order (compute, propagate, reflect, observe, notify).\n     *\n     * @override\n     * @param {!Object} currentProps Bag of all current accessor values\n     * @param {?Object} changedProps Bag of properties changed since the last\n     *   call to `_propertiesChanged`\n     * @param {?Object} oldProps Bag of previous values for each property\n     *   in `changedProps`\n     * @return {void}\n     */\n    _propertiesChanged(currentProps, changedProps, oldProps) {\n      // ----------------------------\n      // let c = Object.getOwnPropertyNames(changedProps || {});\n      // window.debug && console.group(this.localName + '#' + this.id + ': ' + c);\n      // if (window.debug) { debugger; }\n      // ----------------------------\n      let hasPaths = this.__dataHasPaths;\n      this.__dataHasPaths = false;\n      let notifyProps;\n      // Compute properties\n      runComputedEffects(this, changedProps, oldProps, hasPaths);\n      // Clear notify properties prior to possible reentry (propagate, observe),\n      // but after computing effects have a chance to add to them\n      notifyProps = this.__dataToNotify;\n      this.__dataToNotify = null;\n      // Propagate properties to clients\n      this._propagatePropertyChanges(changedProps, oldProps, hasPaths);\n      // Flush clients\n      this._flushClients();\n      // Reflect properties\n      runEffects(this, this[TYPES.REFLECT], changedProps, oldProps, hasPaths);\n      // Observe properties\n      runEffects(this, this[TYPES.OBSERVE], changedProps, oldProps, hasPaths);\n      // Notify properties to host\n      if (notifyProps) {\n        runNotifyEffects(this, notifyProps, changedProps, oldProps, hasPaths);\n      }\n      // Clear temporary cache at end of turn\n      if (this.__dataCounter == 1) {\n        this.__dataTemp = {};\n      }\n      // ----------------------------\n      // window.debug && console.groupEnd(this.localName + '#' + this.id + ': ' + c);\n      // ----------------------------\n    }\n\n    /**\n     * Called to propagate any property changes to stamped template nodes\n     * managed by this element.\n     *\n     * @override\n     * @param {Object} changedProps Bag of changed properties\n     * @param {Object} oldProps Bag of previous values for changed properties\n     * @param {boolean} hasPaths True with `props` contains one or more paths\n     * @return {void}\n     * @protected\n     */\n    _propagatePropertyChanges(changedProps, oldProps, hasPaths) {\n      if (this[TYPES.PROPAGATE]) {\n        runEffects(this, this[TYPES.PROPAGATE], changedProps, oldProps, hasPaths);\n      }\n      if (this.__templateInfo) {\n        this._runEffectsForTemplate(this.__templateInfo, changedProps, oldProps, hasPaths);\n      }\n    }\n\n    _runEffectsForTemplate(templateInfo, changedProps, oldProps, hasPaths) {\n      const baseRunEffects = (changedProps, hasPaths) => {\n        runEffects(this, templateInfo.propertyEffects, changedProps, oldProps,\n          hasPaths, templateInfo.nodeList);\n        for (let info=templateInfo.firstChild; info; info=info.nextSibling) {\n          this._runEffectsForTemplate(info, changedProps, oldProps, hasPaths);\n        }\n      };\n      if (templateInfo.runEffects) {\n        templateInfo.runEffects(baseRunEffects, changedProps, hasPaths);\n      } else {\n        baseRunEffects(changedProps, hasPaths);\n      }\n    }\n\n    /**\n     * Aliases one data path as another, such that path notifications from one\n     * are routed to the other.\n     *\n     * @override\n     * @param {string | !Array<string|number>} to Target path to link.\n     * @param {string | !Array<string|number>} from Source path to link.\n     * @return {void}\n     * @public\n     */\n    linkPaths(to, from) {\n      to = normalize(to);\n      from = normalize(from);\n      this.__dataLinkedPaths = this.__dataLinkedPaths || {};\n      this.__dataLinkedPaths[to] = from;\n    }\n\n    /**\n     * Removes a data path alias previously established with `_linkPaths`.\n     *\n     * Note, the path to unlink should be the target (`to`) used when\n     * linking the paths.\n     *\n     * @override\n     * @param {string | !Array<string|number>} path Target path to unlink.\n     * @return {void}\n     * @public\n     */\n    unlinkPaths(path) {\n      path = normalize(path);\n      if (this.__dataLinkedPaths) {\n        delete this.__dataLinkedPaths[path];\n      }\n    }\n\n    /**\n     * Notify that an array has changed.\n     *\n     * Example:\n     *\n     *     this.items = [ {name: 'Jim'}, {name: 'Todd'}, {name: 'Bill'} ];\n     *     ...\n     *     this.items.splice(1, 1, {name: 'Sam'});\n     *     this.items.push({name: 'Bob'});\n     *     this.notifySplices('items', [\n     *       { index: 1, removed: [{name: 'Todd'}], addedCount: 1,\n     *         object: this.items, type: 'splice' },\n     *       { index: 3, removed: [], addedCount: 1,\n     *         object: this.items, type: 'splice'}\n     *     ]);\n     *\n     * @param {string} path Path that should be notified.\n     * @param {Array} splices Array of splice records indicating ordered\n     *   changes that occurred to the array. Each record should have the\n     *   following fields:\n     *    * index: index at which the change occurred\n     *    * removed: array of items that were removed from this index\n     *    * addedCount: number of new items added at this index\n     *    * object: a reference to the array in question\n     *    * type: the string literal 'splice'\n     *\n     *   Note that splice records _must_ be normalized such that they are\n     *   reported in index order (raw results from `Object.observe` are not\n     *   ordered and must be normalized/merged before notifying).\n     *\n     * @override\n     * @return {void}\n     * @public\n     */\n    notifySplices(path, splices) {\n      let info = {path: ''};\n      let array = /** @type {Array} */(get(this, path, info));\n      notifySplices(this, array, info.path, splices);\n    }\n\n    /**\n     * Convenience method for reading a value from a path.\n     *\n     * Note, if any part in the path is undefined, this method returns\n     * `undefined` (this method does not throw when dereferencing undefined\n     * paths).\n     *\n     * @override\n     * @param {(string|!Array<(string|number)>)} path Path to the value\n     *   to read.  The path may be specified as a string (e.g. `foo.bar.baz`)\n     *   or an array of path parts (e.g. `['foo.bar', 'baz']`).  Note that\n     *   bracketed expressions are not supported; string-based path parts\n     *   *must* be separated by dots.  Note that when dereferencing array\n     *   indices, the index may be used as a dotted part directly\n     *   (e.g. `users.12.name` or `['users', 12, 'name']`).\n     * @param {Object=} root Root object from which the path is evaluated.\n     * @return {*} Value at the path, or `undefined` if any part of the path\n     *   is undefined.\n     * @public\n     */\n    get(path, root) {\n      return get(root || this, path);\n    }\n\n    /**\n     * Convenience method for setting a value to a path and notifying any\n     * elements bound to the same path.\n     *\n     * Note, if any part in the path except for the last is undefined,\n     * this method does nothing (this method does not throw when\n     * dereferencing undefined paths).\n     *\n     * @override\n     * @param {(string|!Array<(string|number)>)} path Path to the value\n     *   to write.  The path may be specified as a string (e.g. `'foo.bar.baz'`)\n     *   or an array of path parts (e.g. `['foo.bar', 'baz']`).  Note that\n     *   bracketed expressions are not supported; string-based path parts\n     *   *must* be separated by dots.  Note that when dereferencing array\n     *   indices, the index may be used as a dotted part directly\n     *   (e.g. `'users.12.name'` or `['users', 12, 'name']`).\n     * @param {*} value Value to set at the specified path.\n     * @param {Object=} root Root object from which the path is evaluated.\n     *   When specified, no notification will occur.\n     * @return {void}\n     * @public\n     */\n    set(path, value, root) {\n      if (root) {\n        set(root, path, value);\n      } else {\n        if (!this[TYPES.READ_ONLY] || !this[TYPES.READ_ONLY][/** @type {string} */(path)]) {\n          if (this._setPendingPropertyOrPath(path, value, true)) {\n            this._invalidateProperties();\n          }\n        }\n      }\n    }\n\n    /**\n     * Adds items onto the end of the array at the path specified.\n     *\n     * The arguments after `path` and return value match that of\n     * `Array.prototype.push`.\n     *\n     * This method notifies other paths to the same array that a\n     * splice occurred to the array.\n     *\n     * @override\n     * @param {string | !Array<string|number>} path Path to array.\n     * @param {...*} items Items to push onto array\n     * @return {number} New length of the array.\n     * @public\n     */\n    push(path, ...items) {\n      let info = {path: ''};\n      let array = /** @type {Array}*/(get(this, path, info));\n      let len = array.length;\n      let ret = array.push(...items);\n      if (items.length) {\n        notifySplice(this, array, info.path, len, items.length, []);\n      }\n      return ret;\n    }\n\n    /**\n     * Removes an item from the end of array at the path specified.\n     *\n     * The arguments after `path` and return value match that of\n     * `Array.prototype.pop`.\n     *\n     * This method notifies other paths to the same array that a\n     * splice occurred to the array.\n     *\n     * @override\n     * @param {string | !Array<string|number>} path Path to array.\n     * @return {*} Item that was removed.\n     * @public\n     */\n    pop(path) {\n      let info = {path: ''};\n      let array = /** @type {Array} */(get(this, path, info));\n      let hadLength = Boolean(array.length);\n      let ret = array.pop();\n      if (hadLength) {\n        notifySplice(this, array, info.path, array.length, 0, [ret]);\n      }\n      return ret;\n    }\n\n    /**\n     * Starting from the start index specified, removes 0 or more items\n     * from the array and inserts 0 or more new items in their place.\n     *\n     * The arguments after `path` and return value match that of\n     * `Array.prototype.splice`.\n     *\n     * This method notifies other paths to the same array that a\n     * splice occurred to the array.\n     *\n     * @override\n     * @param {string | !Array<string|number>} path Path to array.\n     * @param {number} start Index from which to start removing/inserting.\n     * @param {number=} deleteCount Number of items to remove.\n     * @param {...*} items Items to insert into array.\n     * @return {!Array} Array of removed items.\n     * @public\n     */\n    splice(path, start, deleteCount, ...items) {\n      let info = {path : ''};\n      let array = /** @type {Array} */(get(this, path, info));\n      // Normalize fancy native splice handling of crazy start values\n      if (start < 0) {\n        start = array.length - Math.floor(-start);\n      } else if (start) {\n        start = Math.floor(start);\n      }\n      // array.splice does different things based on the number of arguments\n      // you pass in. Therefore, array.splice(0) and array.splice(0, undefined)\n      // do different things. In the former, the whole array is cleared. In the\n      // latter, no items are removed.\n      // This means that we need to detect whether 1. one of the arguments\n      // is actually passed in and then 2. determine how many arguments\n      // we should pass on to the native array.splice\n      //\n      let ret;\n      // Omit any additional arguments if they were not passed in\n      if (arguments.length === 2) {\n        ret = array.splice(start);\n      // Either start was undefined and the others were defined, but in this\n      // case we can safely pass on all arguments\n      //\n      // Note: this includes the case where none of the arguments were passed in,\n      // e.g. this.splice('array'). However, if both start and deleteCount\n      // are undefined, array.splice will not modify the array (as expected)\n      } else {\n        ret = array.splice(start, deleteCount, ...items);\n      }\n      // At the end, check whether any items were passed in (e.g. insertions)\n      // or if the return array contains items (e.g. deletions).\n      // Only notify if items were added or deleted.\n      if (items.length || ret.length) {\n        notifySplice(this, array, info.path, start, items.length, ret);\n      }\n      return ret;\n    }\n\n    /**\n     * Removes an item from the beginning of array at the path specified.\n     *\n     * The arguments after `path` and return value match that of\n     * `Array.prototype.pop`.\n     *\n     * This method notifies other paths to the same array that a\n     * splice occurred to the array.\n     *\n     * @override\n     * @param {string | !Array<string|number>} path Path to array.\n     * @return {*} Item that was removed.\n     * @public\n     */\n    shift(path) {\n      let info = {path: ''};\n      let array = /** @type {Array} */(get(this, path, info));\n      let hadLength = Boolean(array.length);\n      let ret = array.shift();\n      if (hadLength) {\n        notifySplice(this, array, info.path, 0, 0, [ret]);\n      }\n      return ret;\n    }\n\n    /**\n     * Adds items onto the beginning of the array at the path specified.\n     *\n     * The arguments after `path` and return value match that of\n     * `Array.prototype.push`.\n     *\n     * This method notifies other paths to the same array that a\n     * splice occurred to the array.\n     *\n     * @override\n     * @param {string | !Array<string|number>} path Path to array.\n     * @param {...*} items Items to insert info array\n     * @return {number} New length of the array.\n     * @public\n     */\n    unshift(path, ...items) {\n      let info = {path: ''};\n      let array = /** @type {Array} */(get(this, path, info));\n      let ret = array.unshift(...items);\n      if (items.length) {\n        notifySplice(this, array, info.path, 0, items.length, []);\n      }\n      return ret;\n    }\n\n    /**\n     * Notify that a path has changed.\n     *\n     * Example:\n     *\n     *     this.item.user.name = 'Bob';\n     *     this.notifyPath('item.user.name');\n     *\n     * @override\n     * @param {string} path Path that should be notified.\n     * @param {*=} value Value at the path (optional).\n     * @return {void}\n     * @public\n     */\n    notifyPath(path, value) {\n      /** @type {string} */\n      let propPath;\n      if (arguments.length == 1) {\n        // Get value if not supplied\n        let info = {path: ''};\n        value = get(this, path, info);\n        propPath = info.path;\n      } else if (Array.isArray(path)) {\n        // Normalize path if needed\n        propPath = normalize(path);\n      } else {\n        propPath = /** @type{string} */(path);\n      }\n      if (this._setPendingPropertyOrPath(propPath, value, true, true)) {\n        this._invalidateProperties();\n      }\n    }\n\n    /**\n     * Equivalent to static `createReadOnlyProperty` API but can be called on\n     * an instance to add effects at runtime.  See that method for\n     * full API docs.\n     *\n     * @override\n     * @param {string} property Property name\n     * @param {boolean=} protectedSetter Creates a custom protected setter\n     *   when `true`.\n     * @return {void}\n     * @protected\n     */\n    _createReadOnlyProperty(property, protectedSetter) {\n      this._addPropertyEffect(property, TYPES.READ_ONLY);\n      if (protectedSetter) {\n        this['_set' + upper(property)] = /** @this {PropertyEffects} */function(value) {\n          this._setProperty(property, value);\n        };\n      }\n    }\n\n    /**\n     * Equivalent to static `createPropertyObserver` API but can be called on\n     * an instance to add effects at runtime.  See that method for\n     * full API docs.\n     *\n     * @override\n     * @param {string} property Property name\n     * @param {string|function(*,*)} method Function or name of observer method\n     *     to call\n     * @param {boolean=} dynamicFn Whether the method name should be included as\n     *   a dependency to the effect.\n     * @return {void}\n     * @protected\n     */\n    _createPropertyObserver(property, method, dynamicFn) {\n      let info = { property, method, dynamicFn: Boolean(dynamicFn) };\n      this._addPropertyEffect(property, TYPES.OBSERVE, {\n        fn: runObserverEffect, info, trigger: {name: property}\n      });\n      if (dynamicFn) {\n        this._addPropertyEffect(/** @type {string} */(method), TYPES.OBSERVE, {\n          fn: runObserverEffect, info, trigger: {name: method}\n        });\n      }\n    }\n\n    /**\n     * Equivalent to static `createMethodObserver` API but can be called on\n     * an instance to add effects at runtime.  See that method for\n     * full API docs.\n     *\n     * @override\n     * @param {string} expression Method expression\n     * @param {boolean|Object=} dynamicFn Boolean or object map indicating\n     *   whether method names should be included as a dependency to the effect.\n     * @return {void}\n     * @protected\n     */\n    _createMethodObserver(expression, dynamicFn) {\n      let sig = parseMethod(expression);\n      if (!sig) {\n        throw new Error(\"Malformed observer expression '\" + expression + \"'\");\n      }\n      createMethodEffect(this, sig, TYPES.OBSERVE, runMethodEffect, null, dynamicFn);\n    }\n\n    /**\n     * Equivalent to static `createNotifyingProperty` API but can be called on\n     * an instance to add effects at runtime.  See that method for\n     * full API docs.\n     *\n     * @override\n     * @param {string} property Property name\n     * @return {void}\n     * @protected\n     */\n    _createNotifyingProperty(property) {\n      this._addPropertyEffect(property, TYPES.NOTIFY, {\n        fn: runNotifyEffect,\n        info: {\n          eventName: camelToDashCase(property) + '-changed',\n          property: property\n        }\n      });\n    }\n\n    /**\n     * Equivalent to static `createReflectedProperty` API but can be called on\n     * an instance to add effects at runtime.  See that method for\n     * full API docs.\n     *\n     * @override\n     * @param {string} property Property name\n     * @return {void}\n     * @protected\n     * @suppress {missingProperties} go/missingfnprops\n     */\n    _createReflectedProperty(property) {\n      let attr = this.constructor.attributeNameForProperty(property);\n      if (attr[0] === '-') {\n        console.warn('Property ' + property + ' cannot be reflected to attribute ' +\n          attr + ' because \"-\" is not a valid starting attribute name. Use a lowercase first letter for the property instead.');\n      } else {\n        this._addPropertyEffect(property, TYPES.REFLECT, {\n          fn: runReflectEffect,\n          info: {\n            attrName: attr\n          }\n        });\n      }\n    }\n\n    /**\n     * Equivalent to static `createComputedProperty` API but can be called on\n     * an instance to add effects at runtime.  See that method for\n     * full API docs.\n     *\n     * @override\n     * @param {string} property Name of computed property to set\n     * @param {string} expression Method expression\n     * @param {boolean|Object=} dynamicFn Boolean or object map indicating\n     *   whether method names should be included as a dependency to the effect.\n     * @return {void}\n     * @protected\n     */\n    _createComputedProperty(property, expression, dynamicFn) {\n      let sig = parseMethod(expression);\n      if (!sig) {\n        throw new Error(\"Malformed computed expression '\" + expression + \"'\");\n      }\n      const info = createMethodEffect(this, sig, TYPES.COMPUTE, runComputedEffect, property, dynamicFn);\n      // Effects are normally stored as map of dependency->effect, but for\n      // ordered computation, we also need tree of computedProp->dependencies\n      ensureOwnEffectMap(this, COMPUTE_INFO)[property] = info;\n    }\n\n    /**\n     * Gather the argument values for a method specified in the provided array\n     * of argument metadata.\n     *\n     * The `path` and `value` arguments are used to fill in wildcard descriptor\n     * when the method is being called as a result of a path notification.\n     *\n     * @param {!Array<!MethodArg>} args Array of argument metadata\n     * @param {string} path Property/path name that triggered the method effect\n     * @param {Object} props Bag of current property changes\n     * @return {!Array<*>} Array of argument values\n     * @private\n     */\n    _marshalArgs(args, path, props) {\n      const data = this.__data;\n      const values = [];\n      for (let i=0, l=args.length; i<l; i++) {\n        let {name, structured, wildcard, value, literal} = args[i];\n        if (!literal) {\n          if (wildcard) {\n            const matches = isDescendant(name, path);\n            const pathValue = getArgValue(data, props, matches ? path : name);\n            value = {\n              path: matches ? path : name,\n              value: pathValue,\n              base: matches ? get(data, name) : pathValue\n            };\n          } else {\n            value = structured ? getArgValue(data, props, name) : data[name];\n          }\n        }\n        // When the `legacyUndefined` flag is enabled, pass a no-op value\n        // so that the observer, computed property, or compound binding is aborted.\n        if (legacyUndefined && !this._overrideLegacyUndefined && value === undefined && args.length > 1) {\n          return NOOP;\n        }\n        values[i] = value;\n      }\n      return values;\n    }\n\n    // -- static class methods ------------\n\n    /**\n     * Ensures an accessor exists for the specified property, and adds\n     * to a list of \"property effects\" that will run when the accessor for\n     * the specified property is set.  Effects are grouped by \"type\", which\n     * roughly corresponds to a phase in effect processing.  The effect\n     * metadata should be in the following form:\n     *\n     *     {\n     *       fn: effectFunction, // Reference to function to call to perform effect\n     *       info: { ... }       // Effect metadata passed to function\n     *       trigger: {          // Optional triggering metadata; if not provided\n     *         name: string      // the property is treated as a wildcard\n     *         structured: boolean\n     *         wildcard: boolean\n     *       }\n     *     }\n     *\n     * Effects are called from `_propertiesChanged` in the following order by\n     * type:\n     *\n     * 1. COMPUTE\n     * 2. PROPAGATE\n     * 3. REFLECT\n     * 4. OBSERVE\n     * 5. NOTIFY\n     *\n     * Effect functions are called with the following signature:\n     *\n     *     effectFunction(inst, path, props, oldProps, info, hasPaths)\n     *\n     * @param {string} property Property that should trigger the effect\n     * @param {string} type Effect type, from this.PROPERTY_EFFECT_TYPES\n     * @param {Object=} effect Effect metadata object\n     * @return {void}\n     * @protected\n     * @nocollapse\n     */\n    static addPropertyEffect(property, type, effect) {\n      this.prototype._addPropertyEffect(property, type, effect);\n    }\n\n    /**\n     * Creates a single-property observer for the given property.\n     *\n     * @param {string} property Property name\n     * @param {string|function(*,*)} method Function or name of observer method to call\n     * @param {boolean=} dynamicFn Whether the method name should be included as\n     *   a dependency to the effect.\n     * @return {void}\n     * @protected\n     * @nocollapse\n     */\n    static createPropertyObserver(property, method, dynamicFn) {\n      this.prototype._createPropertyObserver(property, method, dynamicFn);\n    }\n\n    /**\n     * Creates a multi-property \"method observer\" based on the provided\n     * expression, which should be a string in the form of a normal JavaScript\n     * function signature: `'methodName(arg1, [..., argn])'`.  Each argument\n     * should correspond to a property or path in the context of this\n     * prototype (or instance), or may be a literal string or number.\n     *\n     * @param {string} expression Method expression\n     * @param {boolean|Object=} dynamicFn Boolean or object map indicating\n     * @return {void}\n     *   whether method names should be included as a dependency to the effect.\n     * @protected\n     * @nocollapse\n     */\n    static createMethodObserver(expression, dynamicFn) {\n      this.prototype._createMethodObserver(expression, dynamicFn);\n    }\n\n    /**\n     * Causes the setter for the given property to dispatch `<property>-changed`\n     * events to notify of changes to the property.\n     *\n     * @param {string} property Property name\n     * @return {void}\n     * @protected\n     * @nocollapse\n     */\n    static createNotifyingProperty(property) {\n      this.prototype._createNotifyingProperty(property);\n    }\n\n    /**\n     * Creates a read-only accessor for the given property.\n     *\n     * To set the property, use the protected `_setProperty` API.\n     * To create a custom protected setter (e.g. `_setMyProp()` for\n     * property `myProp`), pass `true` for `protectedSetter`.\n     *\n     * Note, if the property will have other property effects, this method\n     * should be called first, before adding other effects.\n     *\n     * @param {string} property Property name\n     * @param {boolean=} protectedSetter Creates a custom protected setter\n     *   when `true`.\n     * @return {void}\n     * @protected\n     * @nocollapse\n     */\n    static createReadOnlyProperty(property, protectedSetter) {\n      this.prototype._createReadOnlyProperty(property, protectedSetter);\n    }\n\n    /**\n     * Causes the setter for the given property to reflect the property value\n     * to a (dash-cased) attribute of the same name.\n     *\n     * @param {string} property Property name\n     * @return {void}\n     * @protected\n     * @nocollapse\n     */\n    static createReflectedProperty(property) {\n      this.prototype._createReflectedProperty(property);\n    }\n\n    /**\n     * Creates a computed property whose value is set to the result of the\n     * method described by the given `expression` each time one or more\n     * arguments to the method changes.  The expression should be a string\n     * in the form of a normal JavaScript function signature:\n     * `'methodName(arg1, [..., argn])'`\n     *\n     * @param {string} property Name of computed property to set\n     * @param {string} expression Method expression\n     * @param {boolean|Object=} dynamicFn Boolean or object map indicating whether\n     *   method names should be included as a dependency to the effect.\n     * @return {void}\n     * @protected\n     * @nocollapse\n     */\n    static createComputedProperty(property, expression, dynamicFn) {\n      this.prototype._createComputedProperty(property, expression, dynamicFn);\n    }\n\n    /**\n     * Parses the provided template to ensure binding effects are created\n     * for them, and then ensures property accessors are created for any\n     * dependent properties in the template.  Binding effects for bound\n     * templates are stored in a linked list on the instance so that\n     * templates can be efficiently stamped and unstamped.\n     *\n     * @param {!HTMLTemplateElement} template Template containing binding\n     *   bindings\n     * @return {!TemplateInfo} Template metadata object\n     * @protected\n     * @nocollapse\n     */\n    static bindTemplate(template) {\n      return this.prototype._bindTemplate(template);\n    }\n\n    // -- binding ----------------------------------------------\n\n    /*\n     * Overview of binding flow:\n     *\n     * During finalization (`instanceBinding==false`, `wasPreBound==false`):\n     *  `_bindTemplate(t, false)` called directly during finalization - parses\n     *  the template (for the first time), and then assigns that _prototypical_\n     *  template info to `__preboundTemplateInfo` _on the prototype_; note in\n     *  this case `wasPreBound` is false; this is the first time we're binding\n     *  it, thus we create accessors.\n     *\n     * During first stamping (`instanceBinding==true`, `wasPreBound==true`):\n     *   `_stampTemplate` calls `_bindTemplate(t, true)`: the `templateInfo`\n     *   returned matches the prebound one, and so this is `wasPreBound == true`\n     *   state; thus we _skip_ creating accessors, but _do_ create an instance\n     *   of the template info to serve as the start of our linked list (needs to\n     *   be an instance, not the prototypical one, so that we can add `nodeList`\n     *   to it to contain the `nodeInfo`-ordered list of instance nodes for\n     *   bindings, and so we can chain runtime-stamped template infos off of\n     *   it). At this point, the call to `_stampTemplate` calls\n     *   `applyTemplateInfo` for each nested `<template>` found during parsing\n     *   to hand prototypical `_templateInfo` to them; we also pass the _parent_\n     *   `templateInfo` to the `<template>` so that we have the instance-time\n     *   parent to link the `templateInfo` under in the case it was\n     *   runtime-stamped.\n     *\n     * During subsequent runtime stamping (`instanceBinding==true`,\n     *   `wasPreBound==false`): `_stampTemplate` calls `_bindTemplate(t, true)`\n     *   - here `templateInfo` is guaranteed to _not_ match the prebound one,\n     *   because it was either a different template altogether, or even if it\n     *   was the same template, the step above created a instance of the info;\n     *   in this case `wasPreBound == false`, so we _do_ create accessors, _and_\n     *   link a instance into the linked list.\n     */\n\n    /**\n     * Equivalent to static `bindTemplate` API but can be called on an instance\n     * to add effects at runtime.  See that method for full API docs.\n     *\n     * This method may be called on the prototype (for prototypical template\n     * binding, to avoid creating accessors every instance) once per prototype,\n     * and will be called with `runtimeBinding: true` by `_stampTemplate` to\n     * create and link an instance of the template metadata associated with a\n     * particular stamping.\n     *\n     * @override\n     * @param {!HTMLTemplateElement} template Template containing binding\n     * bindings\n     * @param {boolean=} instanceBinding When false (default), performs\n     * \"prototypical\" binding of the template and overwrites any previously\n     * bound template for the class. When true (as passed from\n     * `_stampTemplate`), the template info is instanced and linked into the\n     * list of bound templates.\n     * @return {!TemplateInfo} Template metadata object; for `runtimeBinding`,\n     * this is an instance of the prototypical template info\n     * @protected\n     * @suppress {missingProperties} go/missingfnprops\n     */\n    _bindTemplate(template, instanceBinding) {\n      let templateInfo = this.constructor._parseTemplate(template);\n      let wasPreBound = this.__preBoundTemplateInfo == templateInfo;\n      // Optimization: since this is called twice for proto-bound templates,\n      // don't attempt to recreate accessors if this template was pre-bound\n      if (!wasPreBound) {\n        for (let prop in templateInfo.propertyEffects) {\n          this._createPropertyAccessor(prop);\n        }\n      }\n      if (instanceBinding) {\n        // For instance-time binding, create instance of template metadata\n        // and link into tree of templates if necessary\n        templateInfo = /** @type {!TemplateInfo} */(Object.create(templateInfo));\n        templateInfo.wasPreBound = wasPreBound;\n        if (!this.__templateInfo) {\n          // Set the info to the root of the tree\n          this.__templateInfo = templateInfo;\n        } else {\n          // Append this template info onto the end of its parent template's\n          // list, which will determine the tree structure via which property\n          // effects are run; if this template was not nested in another\n          // template, use the root template (the first stamped one) as the\n          // parent. Note, `parent` is the `templateInfo` instance for this\n          // template's parent (containing) template, which was set up in\n          // `applyTemplateInfo`.  While a given template's `parent` is set\n          // apriori, it is only added to the parent's child list at the point\n          // that it is being bound, since a template may or may not ever be\n          // stamped, and may be stamped more than once (in which case instances\n          // of the template info will be in the tree under its parent more than\n          // once).\n          const parent = template._parentTemplateInfo || this.__templateInfo;\n          const previous = parent.lastChild;\n          templateInfo.parent = parent;\n          parent.lastChild = templateInfo;\n          templateInfo.previousSibling = previous;\n          if (previous) {\n            previous.nextSibling = templateInfo;\n          } else {\n            parent.firstChild = templateInfo;\n          }\n        }\n      } else {\n        this.__preBoundTemplateInfo = templateInfo;\n      }\n      return templateInfo;\n    }\n\n    /**\n     * Adds a property effect to the given template metadata, which is run\n     * at the \"propagate\" stage of `_propertiesChanged` when the template\n     * has been bound to the element via `_bindTemplate`.\n     *\n     * The `effect` object should match the format in `_addPropertyEffect`.\n     *\n     * @param {Object} templateInfo Template metadata to add effect to\n     * @param {string} prop Property that should trigger the effect\n     * @param {Object=} effect Effect metadata object\n     * @return {void}\n     * @protected\n     * @nocollapse\n     */\n    static _addTemplatePropertyEffect(templateInfo, prop, effect) {\n      let hostProps = templateInfo.hostProps = templateInfo.hostProps || {};\n      hostProps[prop] = true;\n      let effects = templateInfo.propertyEffects = templateInfo.propertyEffects || {};\n      let propEffects = effects[prop] = effects[prop] || [];\n      propEffects.push(effect);\n    }\n\n    /**\n     * Stamps the provided template and performs instance-time setup for\n     * Polymer template features, including data bindings, declarative event\n     * listeners, and the `this.$` map of `id`'s to nodes.  A document fragment\n     * is returned containing the stamped DOM, ready for insertion into the\n     * DOM.\n     *\n     * This method may be called more than once; however note that due to\n     * `shadycss` polyfill limitations, only styles from templates prepared\n     * using `ShadyCSS.prepareTemplate` will be correctly polyfilled (scoped\n     * to the shadow root and support CSS custom properties), and note that\n     * `ShadyCSS.prepareTemplate` may only be called once per element. As such,\n     * any styles required by in runtime-stamped templates must be included\n     * in the main element template.\n     *\n     * @param {!HTMLTemplateElement} template Template to stamp\n     * @param {TemplateInfo=} templateInfo Optional bound template info associated\n     *   with the template to be stamped; if omitted the template will be\n     *   automatically bound.\n     * @return {!StampedTemplate} Cloned template content\n     * @override\n     * @protected\n     */\n    _stampTemplate(template, templateInfo) {\n      templateInfo =  templateInfo || /** @type {!TemplateInfo} */(this._bindTemplate(template, true));\n      // Ensures that created dom is `_enqueueClient`'d to this element so\n      // that it can be flushed on next call to `_flushProperties`\n      hostStack.push(this);\n      let dom = super._stampTemplate(template, templateInfo);\n      hostStack.pop();\n      // Add template-instance-specific data to instanced templateInfo\n      templateInfo.nodeList = dom.nodeList;\n      // Capture child nodes to allow unstamping of non-prototypical templates\n      if (!templateInfo.wasPreBound) {\n        let nodes = templateInfo.childNodes = [];\n        for (let n=dom.firstChild; n; n=n.nextSibling) {\n          nodes.push(n);\n        }\n      }\n      dom.templateInfo = templateInfo;\n      // Setup compound storage, 2-way listeners, and dataHost for bindings\n      setupBindings(this, templateInfo);\n      // Flush properties into template nodes; the check on `__dataClientsReady`\n      // ensures we don't needlessly run effects for an element's initial\n      // prototypical template stamping since they will happen as a part of the\n      // first call to `_propertiesChanged`. This flag is set to true\n      // after running the initial propagate effects, and immediately before\n      // flushing clients. Since downstream clients could cause stamping on\n      // this host (e.g. a fastDomIf `dom-if` being forced to render\n      // synchronously), this flag ensures effects for runtime-stamped templates\n      // are run at this point during the initial element boot-up.\n      if (this.__dataClientsReady) {\n        this._runEffectsForTemplate(templateInfo, this.__data, null, false);\n        this._flushClients();\n      }\n      return dom;\n    }\n\n    /**\n     * Removes and unbinds the nodes previously contained in the provided\n     * DocumentFragment returned from `_stampTemplate`.\n     *\n     * @override\n     * @param {!StampedTemplate} dom DocumentFragment previously returned\n     *   from `_stampTemplate` associated with the nodes to be removed\n     * @return {void}\n     * @protected\n     */\n    _removeBoundDom(dom) {\n      // Unlink template info; Note that while the child is unlinked from its\n      // parent list, a template's `parent` reference is never removed, since\n      // this is is determined by the tree structure and applied at\n      // `applyTemplateInfo` time.\n      const templateInfo = dom.templateInfo;\n      const {previousSibling, nextSibling, parent} = templateInfo;\n      if (previousSibling) {\n        previousSibling.nextSibling = nextSibling;\n      } else if (parent) {\n        parent.firstChild = nextSibling;\n      }\n      if (nextSibling) {\n        nextSibling.previousSibling = previousSibling;\n      } else if (parent) {\n        parent.lastChild = previousSibling;\n      }\n      templateInfo.nextSibling = templateInfo.previousSibling = null;\n      // Remove stamped nodes\n      let nodes = templateInfo.childNodes;\n      for (let i=0; i<nodes.length; i++) {\n        let node = nodes[i];\n        wrap(wrap(node).parentNode).removeChild(node);\n      }\n    }\n\n    /**\n     * Overrides default `TemplateStamp` implementation to add support for\n     * parsing bindings from `TextNode`'s' `textContent`.  A `bindings`\n     * array is added to `nodeInfo` and populated with binding metadata\n     * with information capturing the binding target, and a `parts` array\n     * with one or more metadata objects capturing the source(s) of the\n     * binding.\n     *\n     * @param {Node} node Node to parse\n     * @param {TemplateInfo} templateInfo Template metadata for current template\n     * @param {NodeInfo} nodeInfo Node metadata for current template node\n     * @return {boolean} `true` if the visited node added node-specific\n     *   metadata to `nodeInfo`\n     * @protected\n     * @suppress {missingProperties} Interfaces in closure do not inherit statics, but classes do\n     * @nocollapse\n     */\n    static _parseTemplateNode(node, templateInfo, nodeInfo) {\n      // TODO(https://github.com/google/closure-compiler/issues/3240):\n      //     Change back to just super.methodCall()\n      let noted = propertyEffectsBase._parseTemplateNode.call(\n        this, node, templateInfo, nodeInfo);\n      if (node.nodeType === Node.TEXT_NODE) {\n        let parts = this._parseBindings(node.textContent, templateInfo);\n        if (parts) {\n          // Initialize the textContent with any literal parts\n          // NOTE: default to a space here so the textNode remains; some browsers\n          // (IE) omit an empty textNode following cloneNode/importNode.\n          node.textContent = literalFromParts(parts) || ' ';\n          addBinding(this, templateInfo, nodeInfo, 'text', 'textContent', parts);\n          noted = true;\n        }\n      }\n      return noted;\n    }\n\n    /**\n     * Overrides default `TemplateStamp` implementation to add support for\n     * parsing bindings from attributes.  A `bindings`\n     * array is added to `nodeInfo` and populated with binding metadata\n     * with information capturing the binding target, and a `parts` array\n     * with one or more metadata objects capturing the source(s) of the\n     * binding.\n     *\n     * @param {Element} node Node to parse\n     * @param {TemplateInfo} templateInfo Template metadata for current template\n     * @param {NodeInfo} nodeInfo Node metadata for current template node\n     * @param {string} name Attribute name\n     * @param {string} value Attribute value\n     * @return {boolean} `true` if the visited node added node-specific\n     *   metadata to `nodeInfo`\n     * @protected\n     * @suppress {missingProperties} Interfaces in closure do not inherit statics, but classes do\n     * @nocollapse\n     */\n    static _parseTemplateNodeAttribute(node, templateInfo, nodeInfo, name, value) {\n      let parts = this._parseBindings(value, templateInfo);\n      if (parts) {\n        // Attribute or property\n        let origName = name;\n        let kind = 'property';\n        // The only way we see a capital letter here is if the attr has\n        // a capital letter in it per spec. In this case, to make sure\n        // this binding works, we go ahead and make the binding to the attribute.\n        if (capitalAttributeRegex.test(name)) {\n          kind = 'attribute';\n        } else if (name[name.length-1] == '$') {\n          name = name.slice(0, -1);\n          kind = 'attribute';\n        }\n        // Initialize attribute bindings with any literal parts\n        let literal = literalFromParts(parts);\n        if (literal && kind == 'attribute') {\n          // Ensure a ShadyCSS template scoped style is not removed\n          // when a class$ binding's initial literal value is set.\n          if (name == 'class' && node.hasAttribute('class')) {\n            literal += ' ' + node.getAttribute(name);\n          }\n          node.setAttribute(name, literal);\n        }\n        // support disable-upgrade\n        if (kind == 'attribute' && origName == 'disable-upgrade$') {\n          node.setAttribute(name, '');\n        }\n        // Clear attribute before removing, since IE won't allow removing\n        // `value` attribute if it previously had a value (can't\n        // unconditionally set '' before removing since attributes with `$`\n        // can't be set using setAttribute)\n        if (node.localName === 'input' && origName === 'value') {\n          node.setAttribute(origName, '');\n        }\n        // Remove annotation\n        node.removeAttribute(origName);\n        // Case hackery: attributes are lower-case, but bind targets\n        // (properties) are case sensitive. Gambit is to map dash-case to\n        // camel-case: `foo-bar` becomes `fooBar`.\n        // Attribute bindings are excepted.\n        if (kind === 'property') {\n          name = dashToCamelCase(name);\n        }\n        addBinding(this, templateInfo, nodeInfo, kind, name, parts, literal);\n        return true;\n      } else {\n        // TODO(https://github.com/google/closure-compiler/issues/3240):\n        //     Change back to just super.methodCall()\n        return propertyEffectsBase._parseTemplateNodeAttribute.call(\n          this, node, templateInfo, nodeInfo, name, value);\n      }\n    }\n\n    /**\n     * Overrides default `TemplateStamp` implementation to add support for\n     * binding the properties that a nested template depends on to the template\n     * as `_host_<property>`.\n     *\n     * @param {Node} node Node to parse\n     * @param {TemplateInfo} templateInfo Template metadata for current template\n     * @param {NodeInfo} nodeInfo Node metadata for current template node\n     * @return {boolean} `true` if the visited node added node-specific\n     *   metadata to `nodeInfo`\n     * @protected\n     * @suppress {missingProperties} Interfaces in closure do not inherit statics, but classes do\n     * @nocollapse\n     */\n    static _parseTemplateNestedTemplate(node, templateInfo, nodeInfo) {\n      // TODO(https://github.com/google/closure-compiler/issues/3240):\n      //     Change back to just super.methodCall()\n      let noted = propertyEffectsBase._parseTemplateNestedTemplate.call(\n        this, node, templateInfo, nodeInfo);\n      const parent = node.parentNode;\n      const nestedTemplateInfo = nodeInfo.templateInfo;\n      const isDomIf = parent.localName === 'dom-if';\n      const isDomRepeat = parent.localName === 'dom-repeat';\n      // Remove nested template and redirect its host bindings & templateInfo\n      // onto the parent (dom-if/repeat element)'s nodeInfo\n      if (removeNestedTemplates && (isDomIf || isDomRepeat)) {\n        parent.removeChild(node);\n        // Use the parent's nodeInfo (for the dom-if/repeat) to record the\n        // templateInfo, and use that for any host property bindings below\n        nodeInfo = nodeInfo.parentInfo;\n        nodeInfo.templateInfo = nestedTemplateInfo;\n        // Ensure the parent dom-if/repeat is noted since it now may have host\n        // bindings; it may not have been if it did not have its own bindings\n        nodeInfo.noted = true;\n        noted = false;\n      }\n      // Merge host props into outer template and add bindings\n      let hostProps = nestedTemplateInfo.hostProps;\n      if (fastDomIf && isDomIf) {\n        // `fastDomIf` mode uses runtime-template stamping to add accessors/\n        // effects to properties used in its template; as such we don't need to\n        // tax the host element with `_host_` bindings for the `dom-if`.\n        // However, in the event it is nested in a `dom-repeat`, it is still\n        // important that its host properties are added to the\n        // TemplateInstance's `hostProps` so that they are forwarded to the\n        // TemplateInstance.\n        if (hostProps) {\n          templateInfo.hostProps =\n            Object.assign(templateInfo.hostProps || {}, hostProps);\n          // Ensure the dom-if is noted so that it has a __dataHost, since\n          // `fastDomIf` uses the host for runtime template stamping; note this\n          // was already ensured above in the `removeNestedTemplates` case\n          if (!removeNestedTemplates) {\n            nodeInfo.parentInfo.noted = true;\n          }\n        }\n      } else {\n        let mode = '{';\n        for (let source in hostProps) {\n          let parts = [{ mode, source, dependencies: [source], hostProp: true }];\n          addBinding(this, templateInfo, nodeInfo, 'property', '_host_' + source, parts);\n        }\n      }\n      return noted;\n    }\n\n    /**\n     * Called to parse text in a template (either attribute values or\n     * textContent) into binding metadata.\n     *\n     * Any overrides of this method should return an array of binding part\n     * metadata  representing one or more bindings found in the provided text\n     * and any \"literal\" text in between.  Any non-literal parts will be passed\n     * to `_evaluateBinding` when any dependencies change.  The only required\n     * fields of each \"part\" in the returned array are as follows:\n     *\n     * - `dependencies` - Array containing trigger metadata for each property\n     *   that should trigger the binding to update\n     * - `literal` - String containing text if the part represents a literal;\n     *   in this case no `dependencies` are needed\n     *\n     * Additional metadata for use by `_evaluateBinding` may be provided in\n     * each part object as needed.\n     *\n     * The default implementation handles the following types of bindings\n     * (one or more may be intermixed with literal strings):\n     * - Property binding: `[[prop]]`\n     * - Path binding: `[[object.prop]]`\n     * - Negated property or path bindings: `[[!prop]]` or `[[!object.prop]]`\n     * - Two-way property or path bindings (supports negation):\n     *   `{{prop}}`, `{{object.prop}}`, `{{!prop}}` or `{{!object.prop}}`\n     * - Inline computed method (supports negation):\n     *   `[[compute(a, 'literal', b)]]`, `[[!compute(a, 'literal', b)]]`\n     *\n     * The default implementation uses a regular expression for best\n     * performance. However, the regular expression uses a white-list of\n     * allowed characters in a data-binding, which causes problems for\n     * data-bindings that do use characters not in this white-list.\n     *\n     * Instead of updating the white-list with all allowed characters,\n     * there is a StrictBindingParser (see lib/mixins/strict-binding-parser)\n     * that uses a state machine instead. This state machine is able to handle\n     * all characters. However, it is slightly less performant, therefore we\n     * extracted it into a separate optional mixin.\n     *\n     * @param {string} text Text to parse from attribute or textContent\n     * @param {Object} templateInfo Current template metadata\n     * @return {Array<!BindingPart>} Array of binding part metadata\n     * @protected\n     * @nocollapse\n     */\n    static _parseBindings(text, templateInfo) {\n      let parts = [];\n      let lastIndex = 0;\n      let m;\n      // Example: \"literal1{{prop}}literal2[[!compute(foo,bar)]]final\"\n      // Regex matches:\n      //        Iteration 1:  Iteration 2:\n      // m[1]: '{{'          '[['\n      // m[2]: ''            '!'\n      // m[3]: 'prop'        'compute(foo,bar)'\n      while ((m = bindingRegex.exec(text)) !== null) {\n        // Add literal part\n        if (m.index > lastIndex) {\n          parts.push({literal: text.slice(lastIndex, m.index)});\n        }\n        // Add binding part\n        let mode = m[1][0];\n        let negate = Boolean(m[2]);\n        let source = m[3].trim();\n        let customEvent = false, notifyEvent = '', colon = -1;\n        if (mode == '{' && (colon = source.indexOf('::')) > 0) {\n          notifyEvent = source.substring(colon + 2);\n          source = source.substring(0, colon);\n          customEvent = true;\n        }\n        let signature = parseMethod(source);\n        let dependencies = [];\n        if (signature) {\n          // Inline computed function\n          let {args, methodName} = signature;\n          for (let i=0; i<args.length; i++) {\n            let arg = args[i];\n            if (!arg.literal) {\n              dependencies.push(arg);\n            }\n          }\n          let dynamicFns = templateInfo.dynamicFns;\n          if (dynamicFns && dynamicFns[methodName] || signature.static) {\n            dependencies.push(methodName);\n            signature.dynamicFn = true;\n          }\n        } else {\n          // Property or path\n          dependencies.push(source);\n        }\n        parts.push({\n          source, mode, negate, customEvent, signature, dependencies,\n          event: notifyEvent\n        });\n        lastIndex = bindingRegex.lastIndex;\n      }\n      // Add a final literal part\n      if (lastIndex && lastIndex < text.length) {\n        let literal = text.substring(lastIndex);\n        if (literal) {\n          parts.push({\n            literal: literal\n          });\n        }\n      }\n      if (parts.length) {\n        return parts;\n      } else {\n        return null;\n      }\n    }\n\n    /**\n     * Called to evaluate a previously parsed binding part based on a set of\n     * one or more changed dependencies.\n     *\n     * @param {!Polymer_PropertyEffects} inst Element that should be used as\n     *     scope for binding dependencies\n     * @param {BindingPart} part Binding part metadata\n     * @param {string} path Property/path that triggered this effect\n     * @param {Object} props Bag of current property changes\n     * @param {Object} oldProps Bag of previous values for changed properties\n     * @param {boolean} hasPaths True with `props` contains one or more paths\n     * @return {*} Value the binding part evaluated to\n     * @protected\n     * @nocollapse\n     */\n    static _evaluateBinding(inst, part, path, props, oldProps, hasPaths) {\n      let value;\n      if (part.signature) {\n        value = runMethodEffect(inst, path, props, oldProps, part.signature);\n      } else if (path != part.source) {\n        value = get(inst, part.source);\n      } else {\n        if (hasPaths && isPath(path)) {\n          value = get(inst, path);\n        } else {\n          value = inst.__data[path];\n        }\n      }\n      if (part.negate) {\n        value = !value;\n      }\n      return value;\n    }\n\n  }\n\n  return PropertyEffects;\n});\n\n/**\n * Stack for enqueuing client dom created by a host element.\n *\n * By default elements are flushed via `_flushProperties` when\n * `connectedCallback` is called. Elements attach their client dom to\n * themselves at `ready` time which results from this first flush.\n * This provides an ordering guarantee that the client dom an element\n * creates is flushed before the element itself (i.e. client `ready`\n * fires before host `ready`).\n *\n * However, if `_flushProperties` is called *before* an element is connected,\n * as for example `Templatize` does, this ordering guarantee cannot be\n * satisfied because no elements are connected. (Note: Bound elements that\n * receive data do become enqueued clients and are properly ordered but\n * unbound elements are not.)\n *\n * To maintain the desired \"client before host\" ordering guarantee for this\n * case we rely on the \"host stack. Client nodes registers themselves with\n * the creating host element when created. This ensures that all client dom\n * is readied in the proper order, maintaining the desired guarantee.\n *\n * @private\n */\nconst hostStack = [];\n"
  },
  {
    "path": "lib/mixins/strict-binding-parser.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n// tslint:disable:no-any describes the API as best we are able today\n\nimport {isPath} from '../utils/path.js';\n\nimport {dedupingMixin} from '../utils/mixin.js';\n\nimport {PropertyEffects} from './property-effects.js';\n\n\n/**\n * Mixin that parses binding expressions and generates corresponding metadata.\n * The implementation is different than in `property-effects`, as it uses a\n * state machine instead of a regex. As such, this implementation is able to\n * handle more cases, with the potential performance hit.\n */\ndeclare function StrictBindingParser<T extends new (...args: any[]) => {}>(base: T): T & StrictBindingParserConstructor & PropertyEffectsConstructor & TemplateStampConstructor & PropertyAccessorsConstructor & PropertiesChangedConstructor;\n\nimport {PropertyEffectsConstructor} from './property-effects.js';\n\nimport {TemplateStampConstructor, TemplateStamp} from './template-stamp.js';\n\nimport {PropertyAccessorsConstructor, PropertyAccessors} from './property-accessors.js';\n\nimport {PropertiesChangedConstructor, PropertiesChanged} from './properties-changed.js';\n\ninterface StrictBindingParserConstructor {\n  new(...args: any[]): StrictBindingParser;\n\n  /**\n   * Called to parse text in a template (either attribute values or\n   * textContent) into binding metadata.\n   *\n   * Any overrides of this method should return an array of binding part\n   * metadata  representing one or more bindings found in the provided text\n   * and any \"literal\" text in between.  Any non-literal parts will be passed\n   * to `_evaluateBinding` when any dependencies change.  The only required\n   * fields of each \"part\" in the returned array are as follows:\n   *\n   * - `dependencies` - Array containing trigger metadata for each property\n   *   that should trigger the binding to update\n   * - `literal` - String containing text if the part represents a literal;\n   *   in this case no `dependencies` are needed\n   *\n   * Additional metadata for use by `_evaluateBinding` may be provided in\n   * each part object as needed.\n   *\n   * The default implementation handles the following types of bindings\n   * (one or more may be intermixed with literal strings):\n   * - Property binding: `[[prop]]`\n   * - Path binding: `[[object.prop]]`\n   * - Negated property or path bindings: `[[!prop]]` or `[[!object.prop]]`\n   * - Two-way property or path bindings (supports negation):\n   *   `{{prop}}`, `{{object.prop}}`, `{{!prop}}` or `{{!object.prop}}`\n   * - Inline computed method (supports negation):\n   *   `[[compute(a, 'literal', b)]]`, `[[!compute(a, 'literal', b)]]`\n   *\n   * @param text Text to parse from attribute or textContent\n   * @param templateInfo Current template metadata\n   * @returns Array of binding part metadata\n   */\n  _parseBindings(text: string, templateInfo: object|null): BindingPart[]|null;\n}\n\nexport {StrictBindingParserConstructor};\n\ninterface StrictBindingParser extends PropertyEffects, TemplateStamp, PropertyAccessors, PropertiesChanged {\n}\n\nexport {StrictBindingParser};\n\nimport {BindingPart} from '../../interfaces';\n"
  },
  {
    "path": "lib/mixins/strict-binding-parser.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport '../utils/boot.js';\n\nimport { isPath } from '../utils/path.js';\nimport { dedupingMixin } from '../utils/mixin.js';\nimport { PropertyEffects } from './property-effects.js';\n\n/**\n * The open and corresponding closing brackets for surrounding bindings.\n * @enum {string}\n */\nconst BINDINGS = {\n  '{': '}',\n  '[': ']'\n};\n\n/**\n * All states that the parser can be in. The states represent the state-machine as a whole.\n * @enum {number}\n */\nconst STATE = {\n  INITIAL: 1,\n  FIRSTOPENINGBINDING: 2,\n  FIRSTCHARACTERBINDING: 3,\n  BINDING: 4,\n  FIRSTCOLON: 5,\n  COLONNOTIFYEVENT: 6,\n  COLONNOTIFYEVENTFIRSTCLOSINGBINDING: 7,\n  FIRSTCLOSINGBINDING: 8,\n  STRING: 9,\n  METHOD: 10,\n  STRINGARG: 11,\n  NUMBERARG: 12,\n  VARIABLEARG: 13,\n  METHODCLOSED: 14,\n  METHODCLOSEDBINDING: 15\n};\n\nfunction pushLiteral(text, i, parts, startChar) {\n  const literal = text.substring(startChar || 0, i);\n  if (literal) {\n    parts.push({\n      literal\n    });\n  }\n}\n\nfunction storeMethod(bindingData, templateInfo) {\n  const methodName = bindingData.signature.methodName;\n  const dynamicFns = templateInfo.dynamicFns;\n  if (dynamicFns && dynamicFns[methodName] || bindingData.signature.static) {\n    bindingData.dependencies.push(methodName);\n    bindingData.signature.dynamicFn = true;\n  }\n}\n\nfunction storeVariableBinding(parts, bindingData, prop, i) {\n  bindingData.source = prop;\n  bindingData.dependencies.push(prop);\n  bindingData.startChar = i + 1;\n  parts.push(bindingData);\n}\n\nfunction storeMethodVariable(bindingData, text, i) {\n  const name = text.substring(bindingData.startChar, i).trim();\n  if (name) {\n    if (name === 'true' || name === 'false') {\n      bindingData.signature.args.push({\n        name,\n        value: name == 'true',\n        literal: true\n      });\n    } else {\n      const arg = {\n        name\n      };\n      arg.structured = isPath(name);\n      if (arg.structured) {\n        arg.wildcard = (name.slice(-2) == '.*');\n        if (arg.wildcard) {\n          arg.name = name.slice(0, -2);\n        }\n      }\n      bindingData.signature.args.push(arg);\n      bindingData.dependencies.push(name);\n      bindingData.signature.static = false;\n    }\n  }\n}\n\nfunction storeMethodNumber(bindingData, text, i) {\n  const value = text.substring(bindingData.startChar, i).trim();\n  bindingData.signature.args.push({\n    name: value,\n    value: Number(value),\n    literal: true\n  });\n}\n\n/**\n * Mixin that parses binding expressions and generates corresponding metadata.\n * The implementation is different than in `property-effects`, as it uses a\n * state machine instead of a regex. As such, this implementation is able to\n * handle more cases, with the potential performance hit.\n *\n * @mixinFunction\n * @appliesMixin PropertyEffects\n * @polymer\n * @summary Mixin that parses binding expressions and generates corresponding metadata.\n * @template T\n * @param {function(new:T)} superClass Class to apply mixin to.\n * @return {function(new:T)} superClass with mixin applied.\n */\nconst StrictBindingParser = dedupingMixin((base) => {\n\n  /**\n   * @constructor\n   * @extends {base}\n   * @implements {Polymer_PropertyEffects}\n   * @private\n   */\n  const elementBase = PropertyEffects(base);\n\n  /**\n   * @polymer\n   * @mixinClass\n   * @implements {Polymer_PropertyEffects}\n   */\n  return class extends elementBase {\n\n    /**\n     * Called to parse text in a template (either attribute values or\n     * textContent) into binding metadata.\n     *\n     * Any overrides of this method should return an array of binding part\n     * metadata  representing one or more bindings found in the provided text\n     * and any \"literal\" text in between.  Any non-literal parts will be passed\n     * to `_evaluateBinding` when any dependencies change.  The only required\n     * fields of each \"part\" in the returned array are as follows:\n     *\n     * - `dependencies` - Array containing trigger metadata for each property\n     *   that should trigger the binding to update\n     * - `literal` - String containing text if the part represents a literal;\n     *   in this case no `dependencies` are needed\n     *\n     * Additional metadata for use by `_evaluateBinding` may be provided in\n     * each part object as needed.\n     *\n     * The default implementation handles the following types of bindings\n     * (one or more may be intermixed with literal strings):\n     * - Property binding: `[[prop]]`\n     * - Path binding: `[[object.prop]]`\n     * - Negated property or path bindings: `[[!prop]]` or `[[!object.prop]]`\n     * - Two-way property or path bindings (supports negation):\n     *   `{{prop}}`, `{{object.prop}}`, `{{!prop}}` or `{{!object.prop}}`\n     * - Inline computed method (supports negation):\n     *   `[[compute(a, 'literal', b)]]`, `[[!compute(a, 'literal', b)]]`\n     *\n     * @param {string} text Text to parse from attribute or textContent\n     * @param {Object} templateInfo Current template metadata\n     * @return {Array<!BindingPart>} Array of binding part metadata\n     * @protected\n     */\n    static _parseBindings(text, templateInfo) {\n      const parts = [];\n      let bindingData = {};\n      let escaped = false;\n      /** @type {string} */\n      let quote;\n      /** @type {number} */\n      let state = STATE.INITIAL;\n      let i,l;\n\n      for (i=0,l=text.length; i<l; i++) {\n        const char = text.charAt(i);\n        switch (state) {\n          case STATE.INITIAL: {\n            if ((char === '{' || char === '[')) {\n              bindingData = {\n                mode: char,\n                dependencies: [],\n                startChar: bindingData.startChar\n              };\n              state = STATE.FIRSTOPENINGBINDING;\n            }\n            break;\n          }\n          case STATE.FIRSTOPENINGBINDING: {\n            if (char === bindingData.mode) {\n              pushLiteral(text, i - 1, parts, bindingData.startChar);\n              bindingData.startChar = i + 1;\n              state = STATE.FIRSTCHARACTERBINDING;\n            } else {\n              bindingData = {};\n              state = STATE.INITIAL;\n            }\n            break;\n          }\n          case STATE.FIRSTCHARACTERBINDING: {\n            if (char !== ' ' && char !== '\\t' && char !== '\\n') {\n              if (char === '!') {\n                bindingData.negate = true;\n                bindingData.startChar = i + 1;\n              }\n              state = STATE.BINDING;\n            }\n            break;\n          }\n          case STATE.BINDING: {\n            switch (char) {\n              case BINDINGS[bindingData.mode]: {\n                state = STATE.FIRSTCLOSINGBINDING;\n                break;\n              }\n              case '\\'':\n              case '\"': {\n                quote = char;\n                state = STATE.STRING;\n                break;\n              }\n              case '(': {\n                bindingData.signature = {\n                  methodName: text.substring(bindingData.startChar, i).trim(),\n                  args: [],\n                  static: true\n                };\n                bindingData.startChar = i + 1;\n                state = STATE.METHOD;\n                break;\n              }\n              case ':': {\n                state = STATE.FIRSTCOLON;\n              }\n            }\n            break;\n          }\n          case STATE.FIRSTCOLON: {\n            if (char === ':') {\n              bindingData.customEvent = true;\n              bindingData.startCharAfterColon = i + 1;\n              state = STATE.COLONNOTIFYEVENT;\n            } else {\n              state = STATE.BINDING;\n            }\n            break;\n          }\n          case STATE.COLONNOTIFYEVENT: {\n            if (char === BINDINGS[bindingData.mode]) {\n              state = STATE.COLONNOTIFYEVENTFIRSTCLOSINGBINDING;\n            }\n            break;\n          }\n          case STATE.COLONNOTIFYEVENTFIRSTCLOSINGBINDING: {\n            if (char === BINDINGS[bindingData.mode]) {\n              bindingData.event = text.substring(bindingData.startCharAfterColon, i - 1).trim();\n              const prop = text.substring(bindingData.startChar, bindingData.startCharAfterColon - 2).trim();\n              storeVariableBinding(parts, bindingData, prop, i);\n              state = STATE.INITIAL;\n            } else {\n              state = STATE.BINDING;\n            }\n            break;\n          }\n          case STATE.FIRSTCLOSINGBINDING: {\n            if (char === BINDINGS[bindingData.mode]) {\n              const prop = text.substring(bindingData.startChar, i - 1).trim();\n              storeVariableBinding(parts, bindingData, prop, i);\n              state = STATE.INITIAL;\n            } else {\n              state = STATE.BINDING;\n            }\n            break;\n          }\n          case STATE.STRING: {\n            if (char === '\\\\') {\n              escaped = true;\n            } else if (char === quote && !escaped) {\n              state = STATE.BINDING;\n            } else {\n              escaped = false;\n            }\n            break;\n          }\n          case STATE.METHOD: {\n            switch (char) {\n              case ')': {\n                storeMethodVariable(bindingData, text, i);\n                storeMethod(bindingData, templateInfo);\n                bindingData.startChar = i + 1;\n                state = STATE.METHODCLOSED;\n                break;\n              }\n              case ',': {\n                storeMethodVariable(bindingData, text, i);\n                bindingData.startChar = i + 1;\n                break;\n              }\n              case '\\'':\n              case '\"': {\n                quote = char;\n                state = STATE.STRINGARG;\n                break;\n              }\n              default: {\n                if (char >= '0' && char <= '9' || char === '-') {\n                  state = STATE.NUMBERARG;\n                } else if (char != ' ' && char != '\\n') {\n                  state = STATE.VARIABLEARG;\n                }\n              }\n            }\n            break;\n          }\n          case STATE.STRINGARG: {\n            if (char === '\\\\') {\n              escaped = true;\n            } else if (char === quote && !escaped) {\n              const value = text.substring(bindingData.startChar, i)\n                  .replace(/^\\s+/, '')\n                  .substring(1)\n                  // replace comma entity with comma\n                  .replace(/&comma;/g, ',')\n                  // repair extra escape sequences; note only commas strictly need\n                  // escaping, but we allow any other char to be escaped since its\n                  // likely users will do this\n                  .replace(/\\\\(.)/g, '\\$1');\n              bindingData.signature.args.push({\n                value,\n                name: value,\n                literal: true\n              });\n              bindingData.startChar = i + 1;\n              state = STATE.METHOD;\n            } else {\n              escaped = false;\n            }\n            break;\n          }\n          case STATE.NUMBERARG: {\n            switch (char) {\n              case ',': {\n                storeMethodNumber(bindingData, text, i);\n                bindingData.startChar = i + 1;\n                state = STATE.METHOD;\n                break;\n              }\n              case ')': {\n                storeMethodNumber(bindingData, text, i);\n                storeMethod(bindingData, templateInfo);\n                state = STATE.METHODCLOSED;\n                break;\n              }\n              default: {\n                if (char < '0' || char > '9') {\n                  state = STATE.VARIABLEARG;\n                }\n              }\n            }\n            break;\n          }\n          case STATE.VARIABLEARG: {\n            switch (char) {\n              case ',': {\n                storeMethodVariable(bindingData, text, i);\n                bindingData.startChar = i + 1;\n                state = STATE.METHOD;\n                break;\n              }\n              case ')': {\n                storeMethodVariable(bindingData, text, i);\n                storeMethod(bindingData, templateInfo);\n                state = STATE.METHODCLOSED;\n                break;\n              }\n            }\n            break;\n          }\n          case STATE.METHODCLOSED: {\n            if (char === BINDINGS[bindingData.mode]) {\n              state = STATE.METHODCLOSEDBINDING;\n            } else if (char !== ' ' && char !== '\\t' && char !== '\\n') {\n              console.warn(`Expected two closing \"${BINDINGS[bindingData.mode]}\" for binding \"${text}\"`);\n            }\n            break;\n          }\n          case STATE.METHODCLOSEDBINDING: {\n            if (char === BINDINGS[bindingData.mode]) {\n              bindingData.startChar = i + 1;\n              parts.push(bindingData);\n              state = STATE.INITIAL;\n            } else if (char !== ' ' && char !== '\\t' && char !== '\\n') {\n              console.warn(`Expected one closing \"${BINDINGS[bindingData.mode]}\" for binding \"${text}\"`);\n            }\n            break;\n          }\n        }\n      }\n\n      if (parts.length) {\n        pushLiteral(text, i, parts, parts[parts.length - 1].startChar);\n        return parts;\n      }\n\n      return null;\n    }\n  };\n});\n\nexport { StrictBindingParser };\n"
  },
  {
    "path": "lib/mixins/template-stamp.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n// tslint:disable:no-any describes the API as best we are able today\n\nimport {dedupingMixin} from '../utils/mixin.js';\n\nexport {TemplateStamp};\n\n\n/**\n * Element mixin that provides basic template parsing and stamping, including\n * the following template-related features for stamped templates:\n *\n * - Declarative event listeners (`on-eventname=\"listener\"`)\n * - Map of node id's to stamped node instances (`this.$.id`)\n * - Nested template content caching/removal and re-installation (performance\n *   optimization)\n */\ndeclare function TemplateStamp<T extends new (...args: any[]) => {}>(base: T): T & TemplateStampConstructor;\n\ninterface TemplateStampConstructor {\n  new(...args: any[]): TemplateStamp;\n\n  /**\n   * Scans a template to produce template metadata.\n   *\n   * Template-specific metadata are stored in the object returned, and node-\n   * specific metadata are stored in objects in its flattened `nodeInfoList`\n   * array.  Only nodes in the template that were parsed as nodes of\n   * interest contain an object in `nodeInfoList`.  Each `nodeInfo` object\n   * contains an `index` (`childNodes` index in parent) and optionally\n   * `parent`, which points to node info of its parent (including its index).\n   *\n   * The template metadata object returned from this method has the following\n   * structure (many fields optional):\n   *\n   * ```js\n   *   {\n   *     // Flattened list of node metadata (for nodes that generated metadata)\n   *     nodeInfoList: [\n   *       {\n   *         // `id` attribute for any nodes with id's for generating `$` map\n   *         id: {string},\n   *         // `on-event=\"handler\"` metadata\n   *         events: [\n   *           {\n   *             name: {string},   // event name\n   *             value: {string},  // handler method name\n   *           }, ...\n   *         ],\n   *         // Notes when the template contained a `<slot>` for shady DOM\n   *         // optimization purposes\n   *         hasInsertionPoint: {boolean},\n   *         // For nested `<template>`` nodes, nested template metadata\n   *         templateInfo: {object}, // nested template metadata\n   *         // Metadata to allow efficient retrieval of instanced node\n   *         // corresponding to this metadata\n   *         parentInfo: {number},   // reference to parent nodeInfo>\n   *         parentIndex: {number},  // index in parent's `childNodes` collection\n   *         infoIndex: {number},    // index of this `nodeInfo` in `templateInfo.nodeInfoList`\n   *       },\n   *       ...\n   *     ],\n   *     // When true, the template had the `strip-whitespace` attribute\n   *     // or was nested in a template with that setting\n   *     stripWhitespace: {boolean},\n   *     // For nested templates, nested template content is moved into\n   *     // a document fragment stored here; this is an optimization to\n   *     // avoid the cost of nested template cloning\n   *     content: {DocumentFragment}\n   *   }\n   * ```\n   *\n   * This method kicks off a recursive treewalk as follows:\n   *\n   * ```\n   *    _parseTemplate <---------------------+\n   *      _parseTemplateContent              |\n   *        _parseTemplateNode  <------------|--+\n   *          _parseTemplateNestedTemplate --+  |\n   *          _parseTemplateChildNodes ---------+\n   *          _parseTemplateNodeAttributes\n   *            _parseTemplateNodeAttribute\n   *\n   * ```\n   *\n   * These methods may be overridden to add custom metadata about templates\n   * to either `templateInfo` or `nodeInfo`.\n   *\n   * Note that this method may be destructive to the template, in that\n   * e.g. event annotations may be removed after being noted in the\n   * template metadata.\n   *\n   * @param template Template to parse\n   * @param outerTemplateInfo Template metadata from the outer\n   *   template, for parsing nested templates\n   * @returns Parsed template metadata\n   */\n  _parseTemplate(template: HTMLTemplateElement, outerTemplateInfo?: TemplateInfo|null): TemplateInfo;\n\n  /**\n   * See docs for _parseTemplateNode.\n   *\n   * @param template .\n   * @param templateInfo .\n   * @param nodeInfo .\n   * @returns .\n   */\n  _parseTemplateContent(template: HTMLTemplateElement, templateInfo: TemplateInfo, nodeInfo: NodeInfo): boolean;\n\n  /**\n   * Parses template node and adds template and node metadata based on\n   * the current node, and its `childNodes` and `attributes`.\n   *\n   * This method may be overridden to add custom node or template specific\n   * metadata based on this node.\n   *\n   * @param node Node to parse\n   * @param templateInfo Template metadata for current template\n   * @param nodeInfo Node metadata for current template.\n   * @returns `true` if the visited node added node-specific\n   *   metadata to `nodeInfo`\n   */\n  _parseTemplateNode(node: Node|null, templateInfo: TemplateInfo, nodeInfo: NodeInfo): boolean;\n\n  /**\n   * Parses template child nodes for the given root node.\n   *\n   * This method also wraps whitelisted legacy template extensions\n   * (`is=\"dom-if\"` and `is=\"dom-repeat\"`) with their equivalent element\n   * wrappers, collapses text nodes, and strips whitespace from the template\n   * if the `templateInfo.stripWhitespace` setting was provided.\n   *\n   * @param root Root node whose `childNodes` will be parsed\n   * @param templateInfo Template metadata for current template\n   * @param nodeInfo Node metadata for current template.\n   */\n  _parseTemplateChildNodes(root: Node|null, templateInfo: TemplateInfo, nodeInfo: NodeInfo): void;\n\n  /**\n   * Parses template content for the given nested `<template>`.\n   *\n   * Nested template info is stored as `templateInfo` in the current node's\n   * `nodeInfo`. `template.content` is removed and stored in `templateInfo`.\n   * It will then be the responsibility of the host to set it back to the\n   * template and for users stamping nested templates to use the\n   * `_contentForTemplate` method to retrieve the content for this template\n   * (an optimization to avoid the cost of cloning nested template content).\n   *\n   * @param node Node to parse (a <template>)\n   * @param outerTemplateInfo Template metadata for current template\n   *   that includes the template `node`\n   * @param nodeInfo Node metadata for current template.\n   * @returns `true` if the visited node added node-specific\n   *   metadata to `nodeInfo`\n   */\n  _parseTemplateNestedTemplate(node: HTMLTemplateElement|null, outerTemplateInfo: TemplateInfo|null, nodeInfo: NodeInfo): boolean;\n\n  /**\n   * Parses template node attributes and adds node metadata to `nodeInfo`\n   * for nodes of interest.\n   *\n   * @param node Node to parse\n   * @param templateInfo Template metadata for current\n   *     template\n   * @param nodeInfo Node metadata for current template.\n   * @returns `true` if the visited node added node-specific\n   *   metadata to `nodeInfo`\n   */\n  _parseTemplateNodeAttributes(node: Element|null, templateInfo: TemplateInfo, nodeInfo: NodeInfo): boolean;\n\n  /**\n   * Parses a single template node attribute and adds node metadata to\n   * `nodeInfo` for attributes of interest.\n   *\n   * This implementation adds metadata for `on-event=\"handler\"` attributes\n   * and `id` attributes.\n   *\n   * @param node Node to parse\n   * @param templateInfo Template metadata for current template\n   * @param nodeInfo Node metadata for current template.\n   * @param name Attribute name\n   * @param value Attribute value\n   * @returns `true` if the visited node added node-specific\n   *   metadata to `nodeInfo`\n   */\n  _parseTemplateNodeAttribute(node: Element|null, templateInfo: TemplateInfo, nodeInfo: NodeInfo, name: string, value: string): boolean;\n\n  /**\n   * Returns the `content` document fragment for a given template.\n   *\n   * For nested templates, Polymer performs an optimization to cache nested\n   * template content to avoid the cost of cloning deeply nested templates.\n   * This method retrieves the cached content for a given template.\n   *\n   * @param template Template to retrieve `content` for\n   * @returns Content fragment\n   */\n  _contentForTemplate(template: HTMLTemplateElement|null): DocumentFragment|null;\n}\n\nexport {TemplateStampConstructor};\n\ninterface TemplateStamp {\n\n  /**\n   * Clones the provided template content and returns a document fragment\n   * containing the cloned dom.\n   *\n   * The template is parsed (once and memoized) using this library's\n   * template parsing features, and provides the following value-added\n   * features:\n   * * Adds declarative event listeners for `on-event=\"handler\"` attributes\n   * * Generates an \"id map\" for all nodes with id's under `$` on returned\n   *   document fragment\n   * * Passes template info including `content` back to templates as\n   *   `_templateInfo` (a performance optimization to avoid deep template\n   *   cloning)\n   *\n   * Note that the memoized template parsing process is destructive to the\n   * template: attributes for bindings and declarative event listeners are\n   * removed after being noted in notes, and any nested `<template>.content`\n   * is removed and stored in notes as well.\n   *\n   * @param template Template to stamp\n   * @param templateInfo Optional template info associated\n   *   with the template to be stamped; if omitted the template will be\n   *   automatically parsed.\n   * @returns Cloned template content\n   */\n  _stampTemplate(template: HTMLTemplateElement, templateInfo?: TemplateInfo|null): StampedTemplate;\n\n  /**\n   * Adds an event listener by method name for the event provided.\n   *\n   * This method generates a handler function that looks up the method\n   * name at handling time.\n   *\n   * @param node Node to add listener on\n   * @param eventName Name of event\n   * @param methodName Name of method\n   * @param context Context the method will be called on (defaults\n   *   to `node`)\n   * @returns Generated handler function\n   */\n  _addMethodEventListenerToNode(node: EventTarget, eventName: string, methodName: string, context?: any): Function|null;\n\n  /**\n   * Override point for adding custom or simulated event handling.\n   *\n   * @param node Node to add event listener to\n   * @param eventName Name of event\n   * @param handler Listener function to add\n   */\n  _addEventListenerToNode(node: EventTarget, eventName: string, handler: (p0: Event) => void): void;\n\n  /**\n   * Override point for adding custom or simulated event handling.\n   *\n   * @param node Node to remove event listener from\n   * @param eventName Name of event\n   * @param handler Listener function to remove\n   */\n  _removeEventListenerFromNode(node: EventTarget, eventName: string, handler: (p0: Event) => void): void;\n}\n\nimport {TemplateInfo} from '../../interfaces';\n\nimport {NodeInfo} from '../../interfaces';\n\nimport {StampedTemplate} from '../../interfaces';\n"
  },
  {
    "path": "lib/mixins/template-stamp.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport '../utils/boot.js';\n\nimport { dedupingMixin } from '../utils/mixin.js';\n\n// 1.x backwards-compatible auto-wrapper for template type extensions\n// This is a clear layering violation and gives favored-nation status to\n// dom-if and dom-repeat templates.  This is a conceit we're choosing to keep\n// a.) to ease 1.x backwards-compatibility due to loss of `is`, and\n// b.) to maintain if/repeat capability in parser-constrained elements\n//     (e.g. table, select) in lieu of native CE type extensions without\n//     massive new invention in this space (e.g. directive system)\nconst templateExtensions = {\n  'dom-if': true,\n  'dom-repeat': true\n};\n\nlet placeholderBugDetect = false;\nlet placeholderBug = false;\n\nfunction hasPlaceholderBug() {\n  if (!placeholderBugDetect) {\n    placeholderBugDetect = true;\n    const t = document.createElement('textarea');\n    t.placeholder = 'a';\n    placeholderBug = t.placeholder === t.textContent;\n  }\n  return placeholderBug;\n}\n\n/**\n * Some browsers have a bug with textarea, where placeholder text is copied as\n * a textnode child of the textarea.\n *\n * If the placeholder is a binding, this can break template stamping in two\n * ways.\n *\n * One issue is that when the `placeholder` attribute is removed when the\n * binding is processed, the textnode child of the textarea is deleted, and the\n * template info tries to bind into that node.\n *\n * With `legacyOptimizations` in use, when the template is stamped and the\n * `textarea.textContent` binding is processed, no corresponding node is found\n * because it was removed during parsing. An exception is generated when this\n * binding is updated.\n *\n * With `legacyOptimizations` not in use, the template is cloned before\n * processing and this changes the above behavior. The cloned template also has\n * a value property set to the placeholder and textContent. This prevents the\n * removal of the textContent when the placeholder attribute is removed.\n * Therefore the exception does not occur. However, there is an extra\n * unnecessary binding.\n *\n * @param {!Node} node Check node for placeholder bug\n * @return {void}\n */\nfunction fixPlaceholder(node) {\n  if (hasPlaceholderBug() && node.localName === 'textarea' && node.placeholder\n        && node.placeholder === node.textContent) {\n    node.textContent = null;\n  }\n}\n\n/**\n * Copies an attribute from one element to another, converting the value to a\n * `TrustedScript` if it is named like a Polymer template event listener.\n *\n * @param {!Element} dest The element to set the attribute on\n * @param {!Element} src The element to read the attribute from\n * @param {string} name The name of the attribute\n */\nconst copyAttributeWithTemplateEventPolicy = (() => {\n  /**\n   * This `TrustedTypePolicy` is used to work around a Chrome bug in the Trusted\n   * Types API where any attribute that starts with `on` may only be set to a\n   * `TrustedScript` value, even if that attribute would not cause an event\n   * listener to be created. (See https://crbug.com/993268 for details.)\n   *\n   * Polymer's template system allows `<dom-if>` and `<dom-repeat>` to be\n   * written using the `<template is=\"...\">` syntax, even if there is no UA\n   * support for custom element extensions of built-in elements. In doing so, it\n   * copies attributes from the original `<template>` to a newly created\n   * `<dom-if>` or `<dom-repeat>`, which can trigger the bug mentioned above if\n   * any of those attributes uses Polymer's `on-` syntax for event listeners.\n   * (Note, the value of these `on-` listeners is not evaluated as script: it is\n   * the name of a member function of a component that will be used as the event\n   * listener.)\n   *\n   * @type {!TrustedTypePolicy|undefined}\n   */\n  const polymerTemplateEventAttributePolicy = window.trustedTypes &&\n      window.trustedTypes.createPolicy(\n          'polymer-template-event-attribute-policy', {\n            createScript: x => x,\n          });\n\n  return (dest, src, name) => {\n    const value = src.getAttribute(name);\n\n    if (polymerTemplateEventAttributePolicy && name.startsWith('on-')) {\n      dest.setAttribute(\n          name, polymerTemplateEventAttributePolicy.createScript(value, name));\n      return;\n    }\n\n    dest.setAttribute(name, value);\n  };\n})();\n\nfunction wrapTemplateExtension(node) {\n  let is = node.getAttribute('is');\n  if (is && templateExtensions[is]) {\n    let t = node;\n    t.removeAttribute('is');\n    node = t.ownerDocument.createElement(is);\n    t.parentNode.replaceChild(node, t);\n    node.appendChild(t);\n    while(t.attributes.length) {\n      const {name} = t.attributes[0];\n      copyAttributeWithTemplateEventPolicy(node, t, name);\n      t.removeAttribute(name);\n    }\n  }\n  return node;\n}\n\nfunction findTemplateNode(root, nodeInfo) {\n  // recursively ascend tree until we hit root\n  let parent = nodeInfo.parentInfo && findTemplateNode(root, nodeInfo.parentInfo);\n  // unwind the stack, returning the indexed node at each level\n  if (parent) {\n    // note: marginally faster than indexing via childNodes\n    // (http://jsperf.com/childnodes-lookup)\n    for (let n=parent.firstChild, i=0; n; n=n.nextSibling) {\n      if (nodeInfo.parentIndex === i++) {\n        return n;\n      }\n    }\n  } else {\n    return root;\n  }\n}\n\n// construct `$` map (from id annotations)\nfunction applyIdToMap(inst, map, node, nodeInfo) {\n  if (nodeInfo.id) {\n    map[nodeInfo.id] = node;\n  }\n}\n\n// install event listeners (from event annotations)\nfunction applyEventListener(inst, node, nodeInfo) {\n  if (nodeInfo.events && nodeInfo.events.length) {\n    for (let j=0, e$=nodeInfo.events, e; (j<e$.length) && (e=e$[j]); j++) {\n      inst._addMethodEventListenerToNode(node, e.name, e.value, inst);\n    }\n  }\n}\n\n// push configuration references at configure time\nfunction applyTemplateInfo(inst, node, nodeInfo, parentTemplateInfo) {\n  if (nodeInfo.templateInfo) {\n    // Give the node an instance of this templateInfo and set its parent\n    node._templateInfo = nodeInfo.templateInfo;\n    node._parentTemplateInfo = parentTemplateInfo;\n  }\n}\n\nfunction createNodeEventHandler(context, eventName, methodName) {\n  // Instances can optionally have a _methodHost which allows redirecting where\n  // to find methods. Currently used by `templatize`.\n  context = context._methodHost || context;\n  let handler = function(e) {\n    if (context[methodName]) {\n      context[methodName](e, e.detail);\n    } else {\n      console.warn('listener method `' + methodName + '` not defined');\n    }\n  };\n  return handler;\n}\n\n/**\n * Element mixin that provides basic template parsing and stamping, including\n * the following template-related features for stamped templates:\n *\n * - Declarative event listeners (`on-eventname=\"listener\"`)\n * - Map of node id's to stamped node instances (`this.$.id`)\n * - Nested template content caching/removal and re-installation (performance\n *   optimization)\n *\n * @mixinFunction\n * @polymer\n * @summary Element class mixin that provides basic template parsing and stamping\n */\nexport const TemplateStamp = dedupingMixin(\n    /**\n     * @template T\n     * @param {function(new:T)} superClass Class to apply mixin to.\n     * @return {function(new:T)} superClass with mixin applied.\n     */\n    (superClass) => {\n\n  /**\n   * @polymer\n   * @mixinClass\n   * @implements {Polymer_TemplateStamp}\n   */\n  class TemplateStamp extends superClass {\n\n    /**\n     * Scans a template to produce template metadata.\n     *\n     * Template-specific metadata are stored in the object returned, and node-\n     * specific metadata are stored in objects in its flattened `nodeInfoList`\n     * array.  Only nodes in the template that were parsed as nodes of\n     * interest contain an object in `nodeInfoList`.  Each `nodeInfo` object\n     * contains an `index` (`childNodes` index in parent) and optionally\n     * `parent`, which points to node info of its parent (including its index).\n     *\n     * The template metadata object returned from this method has the following\n     * structure (many fields optional):\n     *\n     * ```js\n     *   {\n     *     // Flattened list of node metadata (for nodes that generated metadata)\n     *     nodeInfoList: [\n     *       {\n     *         // `id` attribute for any nodes with id's for generating `$` map\n     *         id: {string},\n     *         // `on-event=\"handler\"` metadata\n     *         events: [\n     *           {\n     *             name: {string},   // event name\n     *             value: {string},  // handler method name\n     *           }, ...\n     *         ],\n     *         // Notes when the template contained a `<slot>` for shady DOM\n     *         // optimization purposes\n     *         hasInsertionPoint: {boolean},\n     *         // For nested `<template>`` nodes, nested template metadata\n     *         templateInfo: {object}, // nested template metadata\n     *         // Metadata to allow efficient retrieval of instanced node\n     *         // corresponding to this metadata\n     *         parentInfo: {number},   // reference to parent nodeInfo>\n     *         parentIndex: {number},  // index in parent's `childNodes` collection\n     *         infoIndex: {number},    // index of this `nodeInfo` in `templateInfo.nodeInfoList`\n     *       },\n     *       ...\n     *     ],\n     *     // When true, the template had the `strip-whitespace` attribute\n     *     // or was nested in a template with that setting\n     *     stripWhitespace: {boolean},\n     *     // For nested templates, nested template content is moved into\n     *     // a document fragment stored here; this is an optimization to\n     *     // avoid the cost of nested template cloning\n     *     content: {DocumentFragment}\n     *   }\n     * ```\n     *\n     * This method kicks off a recursive treewalk as follows:\n     *\n     * ```\n     *    _parseTemplate <---------------------+\n     *      _parseTemplateContent              |\n     *        _parseTemplateNode  <------------|--+\n     *          _parseTemplateNestedTemplate --+  |\n     *          _parseTemplateChildNodes ---------+\n     *          _parseTemplateNodeAttributes\n     *            _parseTemplateNodeAttribute\n     *\n     * ```\n     *\n     * These methods may be overridden to add custom metadata about templates\n     * to either `templateInfo` or `nodeInfo`.\n     *\n     * Note that this method may be destructive to the template, in that\n     * e.g. event annotations may be removed after being noted in the\n     * template metadata.\n     *\n     * @param {!HTMLTemplateElement} template Template to parse\n     * @param {TemplateInfo=} outerTemplateInfo Template metadata from the outer\n     *   template, for parsing nested templates\n     * @return {!TemplateInfo} Parsed template metadata\n     * @nocollapse\n     */\n    static _parseTemplate(template, outerTemplateInfo) {\n      // since a template may be re-used, memo-ize metadata\n      if (!template._templateInfo) {\n        // TODO(rictic): fix typing\n        let /** ? */ templateInfo = template._templateInfo = {};\n        templateInfo.nodeInfoList = [];\n        templateInfo.nestedTemplate = Boolean(outerTemplateInfo);\n        templateInfo.stripWhiteSpace =\n          (outerTemplateInfo && outerTemplateInfo.stripWhiteSpace) ||\n          (template.hasAttribute && template.hasAttribute('strip-whitespace'));\n         // TODO(rictic): fix typing\n         this._parseTemplateContent(\n             template, templateInfo, /** @type {?} */ ({parent: null}));\n      }\n      return template._templateInfo;\n    }\n\n    /**\n     * See docs for _parseTemplateNode.\n     *\n     * @param {!HTMLTemplateElement} template .\n     * @param {!TemplateInfo} templateInfo .\n     * @param {!NodeInfo} nodeInfo .\n     * @return {boolean} .\n     * @nocollapse\n     */\n    static _parseTemplateContent(template, templateInfo, nodeInfo) {\n      return this._parseTemplateNode(template.content, templateInfo, nodeInfo);\n    }\n\n    /**\n     * Parses template node and adds template and node metadata based on\n     * the current node, and its `childNodes` and `attributes`.\n     *\n     * This method may be overridden to add custom node or template specific\n     * metadata based on this node.\n     *\n     * @param {Node} node Node to parse\n     * @param {!TemplateInfo} templateInfo Template metadata for current template\n     * @param {!NodeInfo} nodeInfo Node metadata for current template.\n     * @return {boolean} `true` if the visited node added node-specific\n     *   metadata to `nodeInfo`\n     * @nocollapse\n     */\n    static _parseTemplateNode(node, templateInfo, nodeInfo) {\n      let noted = false;\n      let element = /** @type {!HTMLTemplateElement} */ (node);\n      if (element.localName == 'template' && !element.hasAttribute('preserve-content')) {\n        noted = this._parseTemplateNestedTemplate(element, templateInfo, nodeInfo) || noted;\n      } else if (element.localName === 'slot') {\n        // For ShadyDom optimization, indicating there is an insertion point\n        templateInfo.hasInsertionPoint = true;\n      }\n      fixPlaceholder(element);\n      if (element.firstChild) {\n        this._parseTemplateChildNodes(element, templateInfo, nodeInfo);\n      }\n      if (element.hasAttributes && element.hasAttributes()) {\n        noted = this._parseTemplateNodeAttributes(element, templateInfo, nodeInfo) || noted;\n      }\n      // Checking `nodeInfo.noted` allows a child node of this node (who gets\n      // access to `parentInfo`) to cause the parent to be noted, which\n      // otherwise has no return path via `_parseTemplateChildNodes` (used by\n      // some optimizations)\n      return noted || nodeInfo.noted;\n    }\n\n    /**\n     * Parses template child nodes for the given root node.\n     *\n     * This method also wraps whitelisted legacy template extensions\n     * (`is=\"dom-if\"` and `is=\"dom-repeat\"`) with their equivalent element\n     * wrappers, collapses text nodes, and strips whitespace from the template\n     * if the `templateInfo.stripWhitespace` setting was provided.\n     *\n     * @param {Node} root Root node whose `childNodes` will be parsed\n     * @param {!TemplateInfo} templateInfo Template metadata for current template\n     * @param {!NodeInfo} nodeInfo Node metadata for current template.\n     * @return {void}\n     */\n    static _parseTemplateChildNodes(root, templateInfo, nodeInfo) {\n      if (root.localName === 'script' || root.localName === 'style') {\n        return;\n      }\n      for (let node=root.firstChild, parentIndex=0, next; node; node=next) {\n        // Wrap templates\n        if (node.localName == 'template') {\n          node = wrapTemplateExtension(node);\n        }\n        // collapse adjacent textNodes: fixes an IE issue that can cause\n        // text nodes to be inexplicably split =(\n        // note that root.normalize() should work but does not so we do this\n        // manually.\n        next = node.nextSibling;\n        if (node.nodeType === Node.TEXT_NODE) {\n          let /** Node */ n = next;\n          while (n && (n.nodeType === Node.TEXT_NODE)) {\n            node.textContent += n.textContent;\n            next = n.nextSibling;\n            root.removeChild(n);\n            n = next;\n          }\n          // optionally strip whitespace\n          if (templateInfo.stripWhiteSpace && !node.textContent.trim()) {\n            root.removeChild(node);\n            continue;\n          }\n        }\n        let childInfo =\n            /** @type {!NodeInfo} */ ({parentIndex, parentInfo: nodeInfo});\n        if (this._parseTemplateNode(node, templateInfo, childInfo)) {\n          childInfo.infoIndex = templateInfo.nodeInfoList.push(childInfo) - 1;\n        }\n        // Increment if not removed\n        if (node.parentNode) {\n          parentIndex++;\n        }\n      }\n    }\n\n    /**\n     * Parses template content for the given nested `<template>`.\n     *\n     * Nested template info is stored as `templateInfo` in the current node's\n     * `nodeInfo`. `template.content` is removed and stored in `templateInfo`.\n     * It will then be the responsibility of the host to set it back to the\n     * template and for users stamping nested templates to use the\n     * `_contentForTemplate` method to retrieve the content for this template\n     * (an optimization to avoid the cost of cloning nested template content).\n     *\n     * @param {HTMLTemplateElement} node Node to parse (a <template>)\n     * @param {TemplateInfo} outerTemplateInfo Template metadata for current template\n     *   that includes the template `node`\n     * @param {!NodeInfo} nodeInfo Node metadata for current template.\n     * @return {boolean} `true` if the visited node added node-specific\n     *   metadata to `nodeInfo`\n     * @nocollapse\n     */\n    static _parseTemplateNestedTemplate(node, outerTemplateInfo, nodeInfo) {\n      // TODO(rictic): the type of node should be non-null\n      let element = /** @type {!HTMLTemplateElement} */ (node);\n      let templateInfo = this._parseTemplate(element, outerTemplateInfo);\n      let content = templateInfo.content =\n          element.content.ownerDocument.createDocumentFragment();\n      content.appendChild(element.content);\n      nodeInfo.templateInfo = templateInfo;\n      return true;\n    }\n\n    /**\n     * Parses template node attributes and adds node metadata to `nodeInfo`\n     * for nodes of interest.\n     *\n     * @param {Element} node Node to parse\n     * @param {!TemplateInfo} templateInfo Template metadata for current\n     *     template\n     * @param {!NodeInfo} nodeInfo Node metadata for current template.\n     * @return {boolean} `true` if the visited node added node-specific\n     *   metadata to `nodeInfo`\n     * @nocollapse\n     */\n    static _parseTemplateNodeAttributes(node, templateInfo, nodeInfo) {\n      // Make copy of original attribute list, since the order may change\n      // as attributes are added and removed\n      let noted = false;\n      let attrs = Array.from(node.attributes);\n      for (let i=attrs.length-1, a; (a=attrs[i]); i--) {\n        noted = this._parseTemplateNodeAttribute(node, templateInfo, nodeInfo, a.name, a.value) || noted;\n      }\n      return noted;\n    }\n\n    /**\n     * Parses a single template node attribute and adds node metadata to\n     * `nodeInfo` for attributes of interest.\n     *\n     * This implementation adds metadata for `on-event=\"handler\"` attributes\n     * and `id` attributes.\n     *\n     * @param {Element} node Node to parse\n     * @param {!TemplateInfo} templateInfo Template metadata for current template\n     * @param {!NodeInfo} nodeInfo Node metadata for current template.\n     * @param {string} name Attribute name\n     * @param {string} value Attribute value\n     * @return {boolean} `true` if the visited node added node-specific\n     *   metadata to `nodeInfo`\n     * @nocollapse\n     */\n    static _parseTemplateNodeAttribute(node, templateInfo, nodeInfo, name, value) {\n      // events (on-*)\n      if (name.slice(0, 3) === 'on-') {\n        node.removeAttribute(name);\n        nodeInfo.events = nodeInfo.events || [];\n        nodeInfo.events.push({\n          name: name.slice(3),\n          value\n        });\n        return true;\n      }\n      // static id\n      else if (name === 'id') {\n        nodeInfo.id = value;\n        return true;\n      }\n      return false;\n    }\n\n    /**\n     * Returns the `content` document fragment for a given template.\n     *\n     * For nested templates, Polymer performs an optimization to cache nested\n     * template content to avoid the cost of cloning deeply nested templates.\n     * This method retrieves the cached content for a given template.\n     *\n     * @param {HTMLTemplateElement} template Template to retrieve `content` for\n     * @return {DocumentFragment} Content fragment\n     * @nocollapse\n     */\n    static _contentForTemplate(template) {\n      let templateInfo = /** @type {HTMLTemplateElementWithInfo} */ (template)._templateInfo;\n      return (templateInfo && templateInfo.content) || template.content;\n    }\n\n    /**\n     * Clones the provided template content and returns a document fragment\n     * containing the cloned dom.\n     *\n     * The template is parsed (once and memoized) using this library's\n     * template parsing features, and provides the following value-added\n     * features:\n     * * Adds declarative event listeners for `on-event=\"handler\"` attributes\n     * * Generates an \"id map\" for all nodes with id's under `$` on returned\n     *   document fragment\n     * * Passes template info including `content` back to templates as\n     *   `_templateInfo` (a performance optimization to avoid deep template\n     *   cloning)\n     *\n     * Note that the memoized template parsing process is destructive to the\n     * template: attributes for bindings and declarative event listeners are\n     * removed after being noted in notes, and any nested `<template>.content`\n     * is removed and stored in notes as well.\n     *\n     * @param {!HTMLTemplateElement} template Template to stamp\n     * @param {TemplateInfo=} templateInfo Optional template info associated\n     *   with the template to be stamped; if omitted the template will be\n     *   automatically parsed.\n     * @return {!StampedTemplate} Cloned template content\n     * @override\n     */\n    _stampTemplate(template, templateInfo) {\n      // Polyfill support: bootstrap the template if it has not already been\n      if (template && !template.content &&\n          window.HTMLTemplateElement && HTMLTemplateElement.decorate) {\n        HTMLTemplateElement.decorate(template);\n      }\n      // Accepting the `templateInfo` via an argument allows for creating\n      // instances of the `templateInfo` by the caller, useful for adding\n      // instance-time information to the prototypical data\n      templateInfo = templateInfo || this.constructor._parseTemplate(template);\n      let nodeInfo = templateInfo.nodeInfoList;\n      let content = templateInfo.content || template.content;\n      let dom = /** @type {DocumentFragment} */ (document.importNode(content, true));\n      // NOTE: ShadyDom optimization indicating there is an insertion point\n      dom.__noInsertionPoint = !templateInfo.hasInsertionPoint;\n      let nodes = dom.nodeList = new Array(nodeInfo.length);\n      dom.$ = {};\n      for (let i=0, l=nodeInfo.length, info; (i<l) && (info=nodeInfo[i]); i++) {\n        let node = nodes[i] = findTemplateNode(dom, info);\n        applyIdToMap(this, dom.$, node, info);\n        applyTemplateInfo(this, node, info, templateInfo);\n        applyEventListener(this, node, info);\n      }\n      dom = /** @type {!StampedTemplate} */(dom); // eslint-disable-line no-self-assign\n      return dom;\n    }\n\n    /**\n     * Adds an event listener by method name for the event provided.\n     *\n     * This method generates a handler function that looks up the method\n     * name at handling time.\n     *\n     * @param {!EventTarget} node Node to add listener on\n     * @param {string} eventName Name of event\n     * @param {string} methodName Name of method\n     * @param {*=} context Context the method will be called on (defaults\n     *   to `node`)\n     * @return {Function} Generated handler function\n     * @override\n     */\n    _addMethodEventListenerToNode(node, eventName, methodName, context) {\n      context = context || node;\n      let handler = createNodeEventHandler(context, eventName, methodName);\n      this._addEventListenerToNode(node, eventName, handler);\n      return handler;\n    }\n\n    /**\n     * Override point for adding custom or simulated event handling.\n     *\n     * @param {!EventTarget} node Node to add event listener to\n     * @param {string} eventName Name of event\n     * @param {function(!Event):void} handler Listener function to add\n     * @return {void}\n     * @override\n     */\n    _addEventListenerToNode(node, eventName, handler) {\n      node.addEventListener(eventName, handler);\n    }\n\n    /**\n     * Override point for adding custom or simulated event handling.\n     *\n     * @param {!EventTarget} node Node to remove event listener from\n     * @param {string} eventName Name of event\n     * @param {function(!Event):void} handler Listener function to remove\n     * @return {void}\n     * @override\n     */\n    _removeEventListenerFromNode(node, eventName, handler) {\n      node.removeEventListener(eventName, handler);\n    }\n\n  }\n\n  return TemplateStamp;\n\n});\n"
  },
  {
    "path": "lib/utils/array-splice.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n// tslint:disable:no-any describes the API as best we are able today\n\nexport {calculateSplices};\n\n\n/**\n * Returns an array of splice records indicating the minimum edits required\n * to transform the `previous` array into the `current` array.\n *\n * Splice records are ordered by index and contain the following fields:\n * - `index`: index where edit started\n * - `removed`: array of removed items from this index\n * - `addedCount`: number of items added at this index\n *\n * This function is based on the Levenshtein \"minimum edit distance\"\n * algorithm. Note that updates are treated as removal followed by addition.\n *\n * The worst-case time complexity of this algorithm is `O(l * p)`\n *   l: The length of the current array\n *   p: The length of the previous array\n *\n * However, the worst-case complexity is reduced by an `O(n)` optimization\n * to detect any shared prefix & suffix between the two arrays and only\n * perform the more expensive minimum edit distance calculation over the\n * non-shared portions of the arrays.\n *\n * @returns Returns an array of splice record objects. Each of these\n * contains: `index` the location where the splice occurred; `removed`\n * the array of removed items from this location; `addedCount` the number\n * of items added at this location.\n */\ndeclare function calculateSplices(current: any[], previous: any[]): any[];\n"
  },
  {
    "path": "lib/utils/array-splice.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport './boot.js';\n\nfunction newSplice(index, removed, addedCount) {\n  return {\n    index: index,\n    removed: removed,\n    addedCount: addedCount\n  };\n}\n\nconst EDIT_LEAVE = 0;\nconst EDIT_UPDATE = 1;\nconst EDIT_ADD = 2;\nconst EDIT_DELETE = 3;\n\n// Note: This function is *based* on the computation of the Levenshtein\n// \"edit\" distance. The one change is that \"updates\" are treated as two\n// edits - not one. With Array splices, an update is really a delete\n// followed by an add. By retaining this, we optimize for \"keeping\" the\n// maximum array items in the original array. For example:\n//\n//   'xxxx123' -> '123yyyy'\n//\n// With 1-edit updates, the shortest path would be just to update all seven\n// characters. With 2-edit updates, we delete 4, leave 3, and add 4. This\n// leaves the substring '123' intact.\nfunction calcEditDistances(current, currentStart, currentEnd,\n                            old, oldStart, oldEnd) {\n  // \"Deletion\" columns\n  let rowCount = oldEnd - oldStart + 1;\n  let columnCount = currentEnd - currentStart + 1;\n  let distances = new Array(rowCount);\n\n  // \"Addition\" rows. Initialize null column.\n  for (let i = 0; i < rowCount; i++) {\n    distances[i] = new Array(columnCount);\n    distances[i][0] = i;\n  }\n\n  // Initialize null row\n  for (let j = 0; j < columnCount; j++)\n    distances[0][j] = j;\n\n  for (let i = 1; i < rowCount; i++) {\n    for (let j = 1; j < columnCount; j++) {\n      if (equals(current[currentStart + j - 1], old[oldStart + i - 1]))\n        distances[i][j] = distances[i - 1][j - 1];\n      else {\n        let north = distances[i - 1][j] + 1;\n        let west = distances[i][j - 1] + 1;\n        distances[i][j] = north < west ? north : west;\n      }\n    }\n  }\n\n  return distances;\n}\n\n// This starts at the final weight, and walks \"backward\" by finding\n// the minimum previous weight recursively until the origin of the weight\n// matrix.\nfunction spliceOperationsFromEditDistances(distances) {\n  let i = distances.length - 1;\n  let j = distances[0].length - 1;\n  let current = distances[i][j];\n  let edits = [];\n  while (i > 0 || j > 0) {\n    if (i == 0) {\n      edits.push(EDIT_ADD);\n      j--;\n      continue;\n    }\n    if (j == 0) {\n      edits.push(EDIT_DELETE);\n      i--;\n      continue;\n    }\n    let northWest = distances[i - 1][j - 1];\n    let west = distances[i - 1][j];\n    let north = distances[i][j - 1];\n\n    let min;\n    if (west < north)\n      min = west < northWest ? west : northWest;\n    else\n      min = north < northWest ? north : northWest;\n\n    if (min == northWest) {\n      if (northWest == current) {\n        edits.push(EDIT_LEAVE);\n      } else {\n        edits.push(EDIT_UPDATE);\n        current = northWest;\n      }\n      i--;\n      j--;\n    } else if (min == west) {\n      edits.push(EDIT_DELETE);\n      i--;\n      current = west;\n    } else {\n      edits.push(EDIT_ADD);\n      j--;\n      current = north;\n    }\n  }\n\n  edits.reverse();\n  return edits;\n}\n\n/**\n * Splice Projection functions:\n *\n * A splice map is a representation of how a previous array of items\n * was transformed into a new array of items. Conceptually it is a list of\n * tuples of\n *\n *   <index, removed, addedCount>\n *\n * which are kept in ascending index order of. The tuple represents that at\n * the |index|, |removed| sequence of items were removed, and counting forward\n * from |index|, |addedCount| items were added.\n */\n\n/**\n * Lacking individual splice mutation information, the minimal set of\n * splices can be synthesized given the previous state and final state of an\n * array. The basic approach is to calculate the edit distance matrix and\n * choose the shortest path through it.\n *\n * Complexity: O(l * p)\n *   l: The length of the current array\n *   p: The length of the old array\n *\n * @param {!Array} current The current \"changed\" array for which to\n * calculate splices.\n * @param {number} currentStart Starting index in the `current` array for\n * which splices are calculated.\n * @param {number} currentEnd Ending index in the `current` array for\n * which splices are calculated.\n * @param {!Array} old The original \"unchanged\" array to compare `current`\n * against to determine splices.\n * @param {number} oldStart Starting index in the `old` array for\n * which splices are calculated.\n * @param {number} oldEnd Ending index in the `old` array for\n * which splices are calculated.\n * @return {!Array} Returns an array of splice record objects. Each of these\n * contains: `index` the location where the splice occurred; `removed`\n * the array of removed items from this location; `addedCount` the number\n * of items added at this location.\n */\nfunction calcSplices(current, currentStart, currentEnd,\n                      old, oldStart, oldEnd) {\n  let prefixCount = 0;\n  let suffixCount = 0;\n  let splice;\n\n  let minLength = Math.min(currentEnd - currentStart, oldEnd - oldStart);\n  if (currentStart == 0 && oldStart == 0)\n    prefixCount = sharedPrefix(current, old, minLength);\n\n  if (currentEnd == current.length && oldEnd == old.length)\n    suffixCount = sharedSuffix(current, old, minLength - prefixCount);\n\n  currentStart += prefixCount;\n  oldStart += prefixCount;\n  currentEnd -= suffixCount;\n  oldEnd -= suffixCount;\n\n  if (currentEnd - currentStart == 0 && oldEnd - oldStart == 0)\n    return [];\n\n  if (currentStart == currentEnd) {\n    splice = newSplice(currentStart, [], 0);\n    while (oldStart < oldEnd)\n      splice.removed.push(old[oldStart++]);\n\n    return [ splice ];\n  } else if (oldStart == oldEnd)\n    return [ newSplice(currentStart, [], currentEnd - currentStart) ];\n\n  let ops = spliceOperationsFromEditDistances(\n      calcEditDistances(current, currentStart, currentEnd,\n                             old, oldStart, oldEnd));\n\n  splice = undefined;\n  let splices = [];\n  let index = currentStart;\n  let oldIndex = oldStart;\n  for (let i = 0; i < ops.length; i++) {\n    switch(ops[i]) {\n      case EDIT_LEAVE:\n        if (splice) {\n          splices.push(splice);\n          splice = undefined;\n        }\n\n        index++;\n        oldIndex++;\n        break;\n      case EDIT_UPDATE:\n        if (!splice)\n          splice = newSplice(index, [], 0);\n\n        splice.addedCount++;\n        index++;\n\n        splice.removed.push(old[oldIndex]);\n        oldIndex++;\n        break;\n      case EDIT_ADD:\n        if (!splice)\n          splice = newSplice(index, [], 0);\n\n        splice.addedCount++;\n        index++;\n        break;\n      case EDIT_DELETE:\n        if (!splice)\n          splice = newSplice(index, [], 0);\n\n        splice.removed.push(old[oldIndex]);\n        oldIndex++;\n        break;\n    }\n  }\n\n  if (splice) {\n    splices.push(splice);\n  }\n  return splices;\n}\n\nfunction sharedPrefix(current, old, searchLength) {\n  for (let i = 0; i < searchLength; i++)\n    if (!equals(current[i], old[i]))\n      return i;\n  return searchLength;\n}\n\nfunction sharedSuffix(current, old, searchLength) {\n  let index1 = current.length;\n  let index2 = old.length;\n  let count = 0;\n  while (count < searchLength && equals(current[--index1], old[--index2]))\n    count++;\n\n  return count;\n}\n\n/**\n * Returns an array of splice records indicating the minimum edits required\n * to transform the `previous` array into the `current` array.\n *\n * Splice records are ordered by index and contain the following fields:\n * - `index`: index where edit started\n * - `removed`: array of removed items from this index\n * - `addedCount`: number of items added at this index\n *\n * This function is based on the Levenshtein \"minimum edit distance\"\n * algorithm. Note that updates are treated as removal followed by addition.\n *\n * The worst-case time complexity of this algorithm is `O(l * p)`\n *   l: The length of the current array\n *   p: The length of the previous array\n *\n * However, the worst-case complexity is reduced by an `O(n)` optimization\n * to detect any shared prefix & suffix between the two arrays and only\n * perform the more expensive minimum edit distance calculation over the\n * non-shared portions of the arrays.\n *\n * @function\n * @param {!Array} current The \"changed\" array for which splices will be\n * calculated.\n * @param {!Array} previous The \"unchanged\" original array to compare\n * `current` against to determine the splices.\n * @return {!Array} Returns an array of splice record objects. Each of these\n * contains: `index` the location where the splice occurred; `removed`\n * the array of removed items from this location; `addedCount` the number\n * of items added at this location.\n */\nexport function calculateSplices(current, previous) {\n  return calcSplices(current, 0, current.length, previous, 0,\n                          previous.length);\n}\n\nfunction equals(currentValue, previousValue) {\n  return currentValue === previousValue;\n}\n"
  },
  {
    "path": "lib/utils/async.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n\n/**\n * Async interface wrapper around `setTimeout`.\n */\ndeclare namespace timeOut {\n\n\n  /**\n   * Returns a sub-module with the async interface providing the provided\n   * delay.\n   *\n   * @returns An async timeout interface\n   */\n  function after(delay?: number): AsyncInterface;\n\n\n  /**\n   * Enqueues a function called in the next task.\n   *\n   * @returns Handle used for canceling task\n   */\n  function run(fn: Function, delay?: number): number;\n\n\n  /**\n   * Cancels a previously enqueued `timeOut` callback.\n   */\n  function cancel(handle: number): void;\n}\n\nexport {timeOut};\n\n/**\n * Async interface wrapper around `requestAnimationFrame`.\n */\ndeclare namespace animationFrame {\n\n\n  /**\n   * Enqueues a function called at `requestAnimationFrame` timing.\n   *\n   * @returns Handle used for canceling task\n   */\n  function run(fn: (p0: number) => void): number;\n\n\n  /**\n   * Cancels a previously enqueued `animationFrame` callback.\n   */\n  function cancel(handle: number): void;\n}\n\nexport {animationFrame};\n\n/**\n * Async interface wrapper around `requestIdleCallback`.  Falls back to\n * `setTimeout` on browsers that do not support `requestIdleCallback`.\n */\ndeclare namespace idlePeriod {\n\n\n  /**\n   * Enqueues a function called at `requestIdleCallback` timing.\n   *\n   * @returns Handle used for canceling task\n   */\n  function run(fn: (p0: IdleDeadline) => void): number;\n\n\n  /**\n   * Cancels a previously enqueued `idlePeriod` callback.\n   */\n  function cancel(handle: number): void;\n}\n\nexport {idlePeriod};\n\n/**\n * Async interface for enqueuing callbacks that run at microtask timing.\n *\n * Note that microtask timing is achieved via a single `MutationObserver`,\n * and thus callbacks enqueued with this API will all run in a single\n * batch, and not interleaved with other microtasks such as promises.\n * Promises are avoided as an implementation choice for the time being\n * due to Safari bugs that cause Promises to lack microtask guarantees.\n */\ndeclare namespace microTask {\n\n\n  /**\n   * Enqueues a function called at microtask timing.\n   *\n   * @returns Handle used for canceling task\n   */\n  function run(callback?: Function): number;\n\n\n  /**\n   * Cancels a previously enqueued `microTask` callback.\n   */\n  function cancel(handle: number): void;\n}\n\nexport {microTask};\n\nimport {AsyncInterface} from '../../interfaces';\n\nimport {IdleDeadline} from '../../interfaces';\n"
  },
  {
    "path": "lib/utils/async.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n/**\n * @fileoverview\n *\n * This module provides a number of strategies for enqueuing asynchronous\n * tasks. Each sub-module provides a standard `run(fn)` interface that returns a\n * handle, and a `cancel(handle)` interface for canceling async tasks before\n * they run.\n *\n * @summary Module that provides a number of strategies for enqueuing\n * asynchronous tasks.\n */\n\nimport './boot.js';\n\n// Microtask implemented using Mutation Observer\nlet microtaskCurrHandle = 0;\nlet microtaskLastHandle = 0;\nlet microtaskCallbacks = [];\nlet microtaskNodeContent = 0;\nlet microtaskScheduled = false;\nlet microtaskNode = document.createTextNode('');\nnew window.MutationObserver(microtaskFlush).observe(microtaskNode, {characterData: true});\n\nfunction microtaskFlush() {\n  microtaskScheduled = false;\n  const len = microtaskCallbacks.length;\n  for (let i = 0; i < len; i++) {\n    let cb = microtaskCallbacks[i];\n    if (cb) {\n      try {\n        cb();\n      } catch (e) {\n        setTimeout(() => { throw e; });\n      }\n    }\n  }\n  microtaskCallbacks.splice(0, len);\n  microtaskLastHandle += len;\n}\n\n/**\n * Async interface wrapper around `setTimeout`.\n *\n * @namespace\n * @summary Async interface wrapper around `setTimeout`.\n */\nconst timeOut = {\n  /**\n   * Returns a sub-module with the async interface providing the provided\n   * delay.\n   *\n   * @memberof timeOut\n   * @param {number=} delay Time to wait before calling callbacks in ms\n   * @return {!AsyncInterface} An async timeout interface\n   */\n  after(delay) {\n    return {\n      run(fn) { return window.setTimeout(fn, delay); },\n      cancel(handle) {\n        window.clearTimeout(handle);\n      }\n    };\n  },\n  /**\n   * Enqueues a function called in the next task.\n   *\n   * @memberof timeOut\n   * @param {!Function} fn Callback to run\n   * @param {number=} delay Delay in milliseconds\n   * @return {number} Handle used for canceling task\n   */\n  run(fn, delay) {\n    return window.setTimeout(fn, delay);\n  },\n  /**\n   * Cancels a previously enqueued `timeOut` callback.\n   *\n   * @memberof timeOut\n   * @param {number} handle Handle returned from `run` of callback to cancel\n   * @return {void}\n   */\n  cancel(handle) {\n    window.clearTimeout(handle);\n  }\n};\nexport {timeOut};\n\n/**\n * Async interface wrapper around `requestAnimationFrame`.\n *\n * @namespace\n * @summary Async interface wrapper around `requestAnimationFrame`.\n */\nconst animationFrame = {\n  /**\n   * Enqueues a function called at `requestAnimationFrame` timing.\n   *\n   * @memberof animationFrame\n   * @param {function(number):void} fn Callback to run\n   * @return {number} Handle used for canceling task\n   */\n  run(fn) {\n    return window.requestAnimationFrame(fn);\n  },\n  /**\n   * Cancels a previously enqueued `animationFrame` callback.\n   *\n   * @memberof animationFrame\n   * @param {number} handle Handle returned from `run` of callback to cancel\n   * @return {void}\n   */\n  cancel(handle) {\n    window.cancelAnimationFrame(handle);\n  }\n};\nexport {animationFrame};\n\n/**\n * Async interface wrapper around `requestIdleCallback`.  Falls back to\n * `setTimeout` on browsers that do not support `requestIdleCallback`.\n *\n * @namespace\n * @summary Async interface wrapper around `requestIdleCallback`.\n */\nconst idlePeriod = {\n  /**\n   * Enqueues a function called at `requestIdleCallback` timing.\n   *\n   * @memberof idlePeriod\n   * @param {function(!IdleDeadline):void} fn Callback to run\n   * @return {number} Handle used for canceling task\n   */\n  run(fn) {\n    return window.requestIdleCallback ?\n      window.requestIdleCallback(fn) :\n      window.setTimeout(fn, 16);\n  },\n  /**\n   * Cancels a previously enqueued `idlePeriod` callback.\n   *\n   * @memberof idlePeriod\n   * @param {number} handle Handle returned from `run` of callback to cancel\n   * @return {void}\n   */\n  cancel(handle) {\n    window.cancelIdleCallback ?\n      window.cancelIdleCallback(handle) :\n      window.clearTimeout(handle);\n  }\n};\nexport {idlePeriod};\n\n/**\n * Async interface for enqueuing callbacks that run at microtask timing.\n *\n * Note that microtask timing is achieved via a single `MutationObserver`,\n * and thus callbacks enqueued with this API will all run in a single\n * batch, and not interleaved with other microtasks such as promises.\n * Promises are avoided as an implementation choice for the time being\n * due to Safari bugs that cause Promises to lack microtask guarantees.\n *\n * @namespace\n * @summary Async interface for enqueuing callbacks that run at microtask\n *   timing.\n */\nconst microTask = {\n\n  /**\n   * Enqueues a function called at microtask timing.\n   *\n   * @memberof microTask\n   * @param {!Function=} callback Callback to run\n   * @return {number} Handle used for canceling task\n   */\n  run(callback) {\n    if (!microtaskScheduled) {\n      microtaskScheduled = true;\n      microtaskNode.textContent = microtaskNodeContent++;\n    }\n    microtaskCallbacks.push(callback);\n    return microtaskCurrHandle++;\n  },\n\n  /**\n   * Cancels a previously enqueued `microTask` callback.\n   *\n   * @memberof microTask\n   * @param {number} handle Handle returned from `run` of callback to cancel\n   * @return {void}\n   */\n  cancel(handle) {\n    const idx = handle - microtaskLastHandle;\n    if (idx >= 0) {\n      if (!microtaskCallbacks[idx]) {\n        throw new Error('invalid async handle: ' + handle);\n      }\n      microtaskCallbacks[idx] = null;\n    }\n  }\n\n};\nexport {microTask};\n"
  },
  {
    "path": "lib/utils/boot.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n\n\nexport {};\n"
  },
  {
    "path": "lib/utils/boot.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n/* eslint-disable no-unused-vars */\n/**\n * When using Closure Compiler, JSCompiler_renameProperty(property, object) is replaced by the munged name for object[property]\n * We cannot alias this function, so we have to use a small shim that has the same behavior when not compiling.\n *\n * @param {?} prop Property name\n * @param {*} obj Reference object\n * @return {string} Potentially renamed property name\n */\nwindow.JSCompiler_renameProperty = function(prop, obj) {\n  return prop;\n};\n/* eslint-enable */\n\nexport {};\n"
  },
  {
    "path": "lib/utils/case-map.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n\nexport {dashToCamelCase};\n\n\n/**\n * Converts \"dash-case\" identifier (e.g. `foo-bar-baz`) to \"camelCase\"\n * (e.g. `fooBarBaz`).\n *\n * @returns Camel-case representation of the identifier\n */\ndeclare function dashToCamelCase(dash: string): string;\n\nexport {camelToDashCase};\n\n\n/**\n * Converts \"camelCase\" identifier (e.g. `fooBarBaz`) to \"dash-case\"\n * (e.g. `foo-bar-baz`).\n *\n * @returns Dash-case representation of the identifier\n */\ndeclare function camelToDashCase(camel: string): string;\n"
  },
  {
    "path": "lib/utils/case-map.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport './boot.js';\n\nconst caseMap = {};\nconst DASH_TO_CAMEL = /-[a-z]/g;\nconst CAMEL_TO_DASH = /([A-Z])/g;\n\n/**\n * @fileoverview Module with utilities for converting between \"dash-case\" and\n * \"camelCase\" identifiers.\n */\n\n/**\n * Converts \"dash-case\" identifier (e.g. `foo-bar-baz`) to \"camelCase\"\n * (e.g. `fooBarBaz`).\n *\n * @param {string} dash Dash-case identifier\n * @return {string} Camel-case representation of the identifier\n */\nexport function dashToCamelCase(dash) {\n  return caseMap[dash] || (\n    caseMap[dash] = dash.indexOf('-') < 0 ? dash : dash.replace(DASH_TO_CAMEL,\n      (m) => m[1].toUpperCase()\n    )\n  );\n}\n\n/**\n * Converts \"camelCase\" identifier (e.g. `fooBarBaz`) to \"dash-case\"\n * (e.g. `foo-bar-baz`).\n *\n * @param {string} camel Camel-case identifier\n * @return {string} Dash-case representation of the identifier\n */\nexport function camelToDashCase(camel) {\n  return caseMap[camel] || (\n    caseMap[camel] = camel.replace(CAMEL_TO_DASH, '-$1').toLowerCase()\n  );\n}\n"
  },
  {
    "path": "lib/utils/debounce.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n// tslint:disable:no-any describes the API as best we are able today\n\nexport {Debouncer};\n\ndeclare class Debouncer {\n  constructor();\n\n  /**\n   * Creates a debouncer if no debouncer is passed as a parameter\n   * or it cancels an active debouncer otherwise. The following\n   * example shows how a debouncer can be called multiple times within a\n   * microtask and \"debounced\" such that the provided callback function is\n   * called once. Add this method to a custom element:\n   *\n   * ```js\n   * import {microTask} from '@polymer/polymer/lib/utils/async.js';\n   * import {Debouncer} from '@polymer/polymer/lib/utils/debounce.js';\n   * // ...\n   *\n   * _debounceWork() {\n   *   this._debounceJob = Debouncer.debounce(this._debounceJob,\n   *       microTask, () => this._doWork());\n   * }\n   * ```\n   *\n   * If the `_debounceWork` method is called multiple times within the same\n   * microtask, the `_doWork` function will be called only once at the next\n   * microtask checkpoint.\n   *\n   * Note: In testing it is often convenient to avoid asynchrony. To accomplish\n   * this with a debouncer, you can use `enqueueDebouncer` and\n   * `flush`. For example, extend the above example by adding\n   * `enqueueDebouncer(this._debounceJob)` at the end of the\n   * `_debounceWork` method. Then in a test, call `flush` to ensure\n   * the debouncer has completed.\n   *\n   * @param debouncer Debouncer object.\n   * @param asyncModule Object with Async interface\n   * @param callback Callback to run.\n   * @returns Returns a debouncer object.\n   */\n  static debounce(debouncer: Debouncer|null, asyncModule: AsyncInterface, callback: () => any): Debouncer;\n\n  /**\n   * Sets the scheduler; that is, a module with the Async interface,\n   * a callback and optional arguments to be passed to the run function\n   * from the async module.\n   *\n   * @param asyncModule Object with Async interface.\n   * @param callback Callback to run.\n   */\n  setConfig(asyncModule: AsyncInterface, callback: () => any): void;\n\n  /**\n   * Cancels an active debouncer and returns a reference to itself.\n   */\n  cancel(): void;\n\n  /**\n   * Cancels a debouncer's async callback.\n   */\n  _cancelAsync(): void;\n\n  /**\n   * Flushes an active debouncer and returns a reference to itself.\n   */\n  flush(): void;\n\n  /**\n   * Returns true if the debouncer is active.\n   *\n   * @returns True if active.\n   */\n  isActive(): boolean;\n}\n\nexport {enqueueDebouncer};\n\n\n/**\n * Adds a `Debouncer` to a list of globally flushable tasks.\n */\ndeclare function enqueueDebouncer(debouncer: Debouncer): void;\n\nexport {flushDebouncers};\n\n\n/**\n * Flushes any enqueued debouncers\n *\n * @returns Returns whether any debouncers were flushed\n */\ndeclare function flushDebouncers(): boolean;\n\nimport {AsyncInterface} from '../../interfaces';\n"
  },
  {
    "path": "lib/utils/debounce.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport './boot.js';\n\nimport './mixin.js';\nimport './async.js';\n\n/**\n * @summary Collapse multiple callbacks into one invocation after a timer.\n */\nexport class Debouncer {\n  constructor() {\n    this._asyncModule = null;\n    this._callback = null;\n    this._timer = null;\n  }\n  /**\n   * Sets the scheduler; that is, a module with the Async interface,\n   * a callback and optional arguments to be passed to the run function\n   * from the async module.\n   *\n   * @param {!AsyncInterface} asyncModule Object with Async interface.\n   * @param {function()} callback Callback to run.\n   * @return {void}\n   */\n  setConfig(asyncModule, callback) {\n    this._asyncModule = asyncModule;\n    this._callback = callback;\n    this._timer = this._asyncModule.run(() => {\n      this._timer = null;\n      debouncerQueue.delete(this);\n      this._callback();\n    });\n  }\n  /**\n   * Cancels an active debouncer and returns a reference to itself.\n   *\n   * @return {void}\n   */\n  cancel() {\n    if (this.isActive()) {\n      this._cancelAsync();\n      // Canceling a debouncer removes its spot from the flush queue,\n      // so if a debouncer is manually canceled and re-debounced, it\n      // will reset its flush order (this is a very minor difference from 1.x)\n      // Re-debouncing via the `debounce` API retains the 1.x FIFO flush order\n      debouncerQueue.delete(this);\n    }\n  }\n  /**\n   * Cancels a debouncer's async callback.\n   *\n   * @return {void}\n   */\n  _cancelAsync() {\n    if (this.isActive()) {\n      this._asyncModule.cancel(/** @type {number} */(this._timer));\n      this._timer = null;\n    }\n  }\n  /**\n   * Flushes an active debouncer and returns a reference to itself.\n   *\n   * @return {void}\n   */\n  flush() {\n    if (this.isActive()) {\n      this.cancel();\n      this._callback();\n    }\n  }\n  /**\n   * Returns true if the debouncer is active.\n   *\n   * @return {boolean} True if active.\n   */\n  isActive() {\n    return this._timer != null;\n  }\n  /**\n   * Creates a debouncer if no debouncer is passed as a parameter\n   * or it cancels an active debouncer otherwise. The following\n   * example shows how a debouncer can be called multiple times within a\n   * microtask and \"debounced\" such that the provided callback function is\n   * called once. Add this method to a custom element:\n   *\n   * ```js\n   * import {microTask} from '@polymer/polymer/lib/utils/async.js';\n   * import {Debouncer} from '@polymer/polymer/lib/utils/debounce.js';\n   * // ...\n   *\n   * _debounceWork() {\n   *   this._debounceJob = Debouncer.debounce(this._debounceJob,\n   *       microTask, () => this._doWork());\n   * }\n   * ```\n   *\n   * If the `_debounceWork` method is called multiple times within the same\n   * microtask, the `_doWork` function will be called only once at the next\n   * microtask checkpoint.\n   *\n   * Note: In testing it is often convenient to avoid asynchrony. To accomplish\n   * this with a debouncer, you can use `enqueueDebouncer` and\n   * `flush`. For example, extend the above example by adding\n   * `enqueueDebouncer(this._debounceJob)` at the end of the\n   * `_debounceWork` method. Then in a test, call `flush` to ensure\n   * the debouncer has completed.\n   *\n   * @param {Debouncer?} debouncer Debouncer object.\n   * @param {!AsyncInterface} asyncModule Object with Async interface\n   * @param {function()} callback Callback to run.\n   * @return {!Debouncer} Returns a debouncer object.\n   */\n  static debounce(debouncer, asyncModule, callback) {\n    if (debouncer instanceof Debouncer) {\n      // Cancel the async callback, but leave in debouncerQueue if it was\n      // enqueued, to maintain 1.x flush order\n      debouncer._cancelAsync();\n    } else {\n      debouncer = new Debouncer();\n    }\n    debouncer.setConfig(asyncModule, callback);\n    return debouncer;\n  }\n}\n\nlet debouncerQueue = new Set();\n\n/**\n * Adds a `Debouncer` to a list of globally flushable tasks.\n *\n * @param {!Debouncer} debouncer Debouncer to enqueue\n * @return {void}\n */\nexport const enqueueDebouncer = function(debouncer) {\n  debouncerQueue.add(debouncer);\n};\n\n/**\n * Flushes any enqueued debouncers\n *\n * @return {boolean} Returns whether any debouncers were flushed\n */\nexport const flushDebouncers = function() {\n  const didFlush = Boolean(debouncerQueue.size);\n  // If new debouncers are added while flushing, Set.forEach will ensure\n  // newly added ones are also flushed\n  debouncerQueue.forEach(debouncer => {\n    try {\n      debouncer.flush();\n    } catch(e) {\n      setTimeout(() => {\n        throw e;\n      });\n    }\n  });\n  return didFlush;\n};"
  },
  {
    "path": "lib/utils/flattened-nodes-observer.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n// tslint:disable:no-any describes the API as best we are able today\n\nimport {calculateSplices} from './array-splice.js';\n\nimport {microTask} from './async.js';\n\nexport {FlattenedNodesObserver};\n\n/**\n * Class that listens for changes (additions or removals) to\n * \"flattened nodes\" on a given `node`. The list of flattened nodes consists\n * of a node's children and, for any children that are `<slot>` elements,\n * the expanded flattened list of `assignedNodes`.\n * For example, if the observed node has children `<a></a><slot></slot><b></b>`\n * and the `<slot>` has one `<div>` assigned to it, then the flattened\n * nodes list is `<a></a><div></div><b></b>`. If the `<slot>` has other\n * `<slot>` elements assigned to it, these are flattened as well.\n *\n * The provided `callback` is called whenever any change to this list\n * of flattened nodes occurs, where an addition or removal of a node is\n * considered a change. The `callback` is called with one argument, an object\n * containing an array of any `addedNodes` and `removedNodes`.\n *\n * Note: the callback is called asynchronous to any changes\n * at a microtask checkpoint. This is because observation is performed using\n * `MutationObserver` and the `<slot>` element's `slotchange` event which\n * are asynchronous.\n *\n * An example:\n * ```js\n * class TestSelfObserve extends PolymerElement {\n *   static get is() { return 'test-self-observe';}\n *   connectedCallback() {\n *     super.connectedCallback();\n *     this._observer = new FlattenedNodesObserver(this, (info) => {\n *       this.info = info;\n *     });\n *   }\n *   disconnectedCallback() {\n *     super.disconnectedCallback();\n *     this._observer.disconnect();\n *   }\n * }\n * customElements.define(TestSelfObserve.is, TestSelfObserve);\n * ```\n */\ndeclare class FlattenedNodesObserver {\n\n  /**\n   * eslint-disable-next-line\n   */\n  constructor(target: any, callback: any);\n\n  /**\n   * eslint-disable-next-line\n   */\n  static getFlattenedNodes(node: any): any;\n\n  /**\n   * Activates an observer. This method is automatically called when\n   * a `FlattenedNodesObserver` is created. It should only be called to\n   * re-activate an observer that has been deactivated via the `disconnect` method.\n   */\n  connect(): void;\n\n  /**\n   * Deactivates the flattened nodes observer. After calling this method\n   * the observer callback will not be called when changes to flattened nodes\n   * occur. The `connect` method may be subsequently called to reactivate\n   * the observer.\n   */\n  disconnect(): void;\n\n  /**\n   * Flushes the observer causing any pending changes to be immediately\n   * delivered the observer callback. By default these changes are delivered\n   * asynchronously at the next microtask checkpoint.\n   *\n   * @returns Returns true if any pending changes caused the observer\n   * callback to run.\n   */\n  flush(): boolean;\n}\n"
  },
  {
    "path": "lib/utils/flattened-nodes-observer.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport './boot.js';\n\nimport { calculateSplices } from './array-splice.js';\nimport { microTask } from './async.js';\nimport { wrap } from './wrap.js';\n\n/**\n * Returns true if `node` is a slot element\n * @param {!Node} node Node to test.\n * @return {boolean} Returns true if the given `node` is a slot\n * @private\n */\nfunction isSlot(node) {\n  return (node.localName === 'slot');\n}\n\n/**\n * Class that listens for changes (additions or removals) to\n * \"flattened nodes\" on a given `node`. The list of flattened nodes consists\n * of a node's children and, for any children that are `<slot>` elements,\n * the expanded flattened list of `assignedNodes`.\n * For example, if the observed node has children `<a></a><slot></slot><b></b>`\n * and the `<slot>` has one `<div>` assigned to it, then the flattened\n * nodes list is `<a></a><div></div><b></b>`. If the `<slot>` has other\n * `<slot>` elements assigned to it, these are flattened as well.\n *\n * The provided `callback` is called whenever any change to this list\n * of flattened nodes occurs, where an addition or removal of a node is\n * considered a change. The `callback` is called with one argument, an object\n * containing an array of any `addedNodes` and `removedNodes`.\n *\n * Note: the callback is called asynchronous to any changes\n * at a microtask checkpoint. This is because observation is performed using\n * `MutationObserver` and the `<slot>` element's `slotchange` event which\n * are asynchronous.\n *\n * An example:\n * ```js\n * class TestSelfObserve extends PolymerElement {\n *   static get is() { return 'test-self-observe';}\n *   connectedCallback() {\n *     super.connectedCallback();\n *     this._observer = new FlattenedNodesObserver(this, (info) => {\n *       this.info = info;\n *     });\n *   }\n *   disconnectedCallback() {\n *     super.disconnectedCallback();\n *     this._observer.disconnect();\n *   }\n * }\n * customElements.define(TestSelfObserve.is, TestSelfObserve);\n * ```\n *\n * @summary Class that listens for changes (additions or removals) to\n * \"flattened nodes\" on a given `node`.\n * @implements {PolymerDomApi.ObserveHandle}\n */\nexport let FlattenedNodesObserver = class {\n\n  /**\n   * Returns the list of flattened nodes for the given `node`.\n   * This list consists of a node's children and, for any children\n   * that are `<slot>` elements, the expanded flattened list of `assignedNodes`.\n   * For example, if the observed node has children `<a></a><slot></slot><b></b>`\n   * and the `<slot>` has one `<div>` assigned to it, then the flattened\n   * nodes list is `<a></a><div></div><b></b>`. If the `<slot>` has other\n   * `<slot>` elements assigned to it, these are flattened as well.\n   *\n   * @param {!HTMLElement|!HTMLSlotElement} node The node for which to\n   *      return the list of flattened nodes.\n   * @return {!Array<!Node>} The list of flattened nodes for the given `node`.\n   * @nocollapse See https://github.com/google/closure-compiler/issues/2763\n   */\n  // eslint-disable-next-line\n  static getFlattenedNodes(node) {\n    const wrapped = wrap(node);\n    if (isSlot(node)) {\n      node = /** @type {!HTMLSlotElement} */(node); // eslint-disable-line no-self-assign\n      return wrapped.assignedNodes({flatten: true});\n    } else {\n      const results = [];\n      for (let i = 0; i < wrapped.childNodes.length; i++) {\n        const node = wrapped.childNodes[i];\n        if (isSlot(node)) {\n          const slotNode = /** @type {!HTMLSlotElement} */ (node);\n          results.push(...wrap(slotNode).assignedNodes({ flatten: true }));\n        } else {\n          results.push(node);\n        }\n      }\n      return results;\n    }\n  }\n\n  /**\n   * @param {!HTMLElement} target Node on which to listen for changes.\n   * @param {?function(this: Element, { target: !HTMLElement, addedNodes: !Array<!Element>, removedNodes: !Array<!Element> }):void} callback Function called when there are additions\n   * or removals from the target's list of flattened nodes.\n   */\n  // eslint-disable-next-line\n  constructor(target, callback) {\n    /**\n     * @type {MutationObserver}\n     * @private\n     */\n    this._shadyChildrenObserver = null;\n    /**\n     * @type {MutationObserver}\n     * @private\n     */\n    this._nativeChildrenObserver = null;\n    this._connected = false;\n    /**\n     * @type {!HTMLElement}\n     * @private\n     */\n    this._target = target;\n    this.callback = callback;\n    this._effectiveNodes = [];\n    this._observer = null;\n    this._scheduled = false;\n    /**\n     * @type {function()}\n     * @private\n     */\n    this._boundSchedule = () => {\n      this._schedule();\n    };\n    this.connect();\n    this._schedule();\n  }\n\n  /**\n   * Activates an observer. This method is automatically called when\n   * a `FlattenedNodesObserver` is created. It should only be called to\n   * re-activate an observer that has been deactivated via the `disconnect` method.\n   *\n   * @return {void}\n   */\n  connect() {\n    if (isSlot(this._target)) {\n      this._listenSlots([this._target]);\n    } else if (wrap(this._target).children) {\n      this._listenSlots(\n          /** @type {!NodeList<!Node>} */ (wrap(this._target).children));\n      if (window.ShadyDOM) {\n        this._shadyChildrenObserver =\n          window.ShadyDOM.observeChildren(this._target, (mutations) => {\n            this._processMutations(mutations);\n          });\n      } else {\n        this._nativeChildrenObserver =\n          new MutationObserver((mutations) => {\n            this._processMutations(mutations);\n          });\n        this._nativeChildrenObserver.observe(this._target, {childList: true});\n      }\n    }\n    this._connected = true;\n  }\n\n  /**\n   * Deactivates the flattened nodes observer. After calling this method\n   * the observer callback will not be called when changes to flattened nodes\n   * occur. The `connect` method may be subsequently called to reactivate\n   * the observer.\n   *\n   * @return {void}\n   * @override\n   */\n  disconnect() {\n    if (isSlot(this._target)) {\n      this._unlistenSlots([this._target]);\n    } else if (wrap(this._target).children) {\n      this._unlistenSlots(\n          /** @type {!NodeList<!Node>} */ (wrap(this._target).children));\n      if (window.ShadyDOM && this._shadyChildrenObserver) {\n        window.ShadyDOM.unobserveChildren(this._shadyChildrenObserver);\n        this._shadyChildrenObserver = null;\n      } else if (this._nativeChildrenObserver) {\n        this._nativeChildrenObserver.disconnect();\n        this._nativeChildrenObserver = null;\n      }\n    }\n    this._connected = false;\n  }\n\n  /**\n   * @return {void}\n   * @private\n   */\n  _schedule() {\n    if (!this._scheduled) {\n      this._scheduled = true;\n      microTask.run(() => this.flush());\n    }\n  }\n\n  /**\n   * @param {Array<MutationRecord>} mutations Mutations signaled by the mutation observer\n   * @return {void}\n   * @private\n   */\n  _processMutations(mutations) {\n    this._processSlotMutations(mutations);\n    this.flush();\n  }\n\n  /**\n   * @param {Array<MutationRecord>} mutations Mutations signaled by the mutation observer\n   * @return {void}\n   * @private\n   */\n  _processSlotMutations(mutations) {\n    if (mutations) {\n      for (let i=0; i < mutations.length; i++) {\n        let mutation = mutations[i];\n        if (mutation.addedNodes) {\n          this._listenSlots(mutation.addedNodes);\n        }\n        if (mutation.removedNodes) {\n          this._unlistenSlots(mutation.removedNodes);\n        }\n      }\n    }\n  }\n\n  /**\n   * Flushes the observer causing any pending changes to be immediately\n   * delivered the observer callback. By default these changes are delivered\n   * asynchronously at the next microtask checkpoint.\n   *\n   * @return {boolean} Returns true if any pending changes caused the observer\n   * callback to run.\n   */\n  flush() {\n    if (!this._connected) {\n      return false;\n    }\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    if (this._nativeChildrenObserver) {\n      this._processSlotMutations(this._nativeChildrenObserver.takeRecords());\n    } else if (this._shadyChildrenObserver) {\n      this._processSlotMutations(this._shadyChildrenObserver.takeRecords());\n    }\n    this._scheduled = false;\n    let info = {\n      target: this._target,\n      addedNodes: [],\n      removedNodes: []\n    };\n    let newNodes = this.constructor.getFlattenedNodes(this._target);\n    let splices = calculateSplices(newNodes,\n      this._effectiveNodes);\n    // process removals\n    for (let i=0, s; (i<splices.length) && (s=splices[i]); i++) {\n      for (let j=0, n; (j < s.removed.length) && (n=s.removed[j]); j++) {\n        info.removedNodes.push(n);\n      }\n    }\n    // process adds\n    for (let i=0, s; (i<splices.length) && (s=splices[i]); i++) {\n      for (let j=s.index; j < s.index + s.addedCount; j++) {\n        info.addedNodes.push(newNodes[j]);\n      }\n    }\n    // update cache\n    this._effectiveNodes = newNodes;\n    let didFlush = false;\n    if (info.addedNodes.length || info.removedNodes.length) {\n      didFlush = true;\n      this.callback.call(this._target, info);\n    }\n    return didFlush;\n  }\n\n  /**\n   * @param {!Array<!Node>|!NodeList<!Node>} nodeList Nodes that could change\n   * @return {void}\n   * @private\n   */\n  _listenSlots(nodeList) {\n    for (let i=0; i < nodeList.length; i++) {\n      let n = nodeList[i];\n      if (isSlot(n)) {\n        n.addEventListener('slotchange', this._boundSchedule);\n      }\n    }\n  }\n\n  /**\n   * @param {!Array<!Node>|!NodeList<!Node>} nodeList Nodes that could change\n   * @return {void}\n   * @private\n   */\n  _unlistenSlots(nodeList) {\n    for (let i=0; i < nodeList.length; i++) {\n      let n = nodeList[i];\n      if (isSlot(n)) {\n        n.removeEventListener('slotchange', this._boundSchedule);\n      }\n    }\n  }\n\n};\n"
  },
  {
    "path": "lib/utils/flush.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n\nimport {enqueueDebouncer, flushDebouncers} from '../utils/debounce.js';\n\nexport {enqueueDebouncer};\n\nexport {flush};\n\n\n/**\n * Forces several classes of asynchronously queued tasks to flush:\n * - Debouncers added via `enqueueDebouncer`\n * - ShadyDOM distribution\n */\ndeclare function flush(): void;\n"
  },
  {
    "path": "lib/utils/flush.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport './boot.js';\nimport {enqueueDebouncer, flushDebouncers} from '../utils/debounce.js';\nexport {enqueueDebouncer};\n\n/**\n * Forces several classes of asynchronously queued tasks to flush:\n * - Debouncers added via `enqueueDebouncer`\n * - ShadyDOM distribution\n *\n * @return {void}\n */\nexport const flush = function() {\n  let shadyDOM, debouncers;\n  do {\n    shadyDOM = window.ShadyDOM && ShadyDOM.flush();\n    if (window.ShadyCSS && window.ShadyCSS.ScopingShim) {\n      window.ShadyCSS.ScopingShim.flush();\n    }\n    debouncers = flushDebouncers();\n  } while (shadyDOM || debouncers);\n};\n"
  },
  {
    "path": "lib/utils/gestures.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n\nimport {timeOut, microTask} from './async.js';\n\nimport {Debouncer} from './debounce.js';\n\nexport {deepTargetFind};\n\n\n/**\n * Finds the element rendered on the screen at the provided coordinates.\n *\n * Similar to `document.elementFromPoint`, but pierces through\n * shadow roots.\n *\n * @returns Returns the deepest shadowRoot inclusive element\n * found at the screen position given.\n */\ndeclare function deepTargetFind(x: number, y: number): Element|null;\n\nexport {addListener};\n\n\n/**\n * Adds an event listener to a node for the given gesture type.\n *\n * @returns Returns true if a gesture event listener was added.\n */\ndeclare function addListener(node: EventTarget, evType: string, handler: (p0: Event) => void): boolean;\n\nexport {removeListener};\n\n\n/**\n * Removes an event listener from a node for the given gesture type.\n *\n * @returns Returns true if a gesture event listener was removed.\n */\ndeclare function removeListener(node: EventTarget, evType: string, handler: (p0: Event) => void): boolean;\n\nexport {register};\n\n\n/**\n * Registers a new gesture event recognizer for adding new custom\n * gesture event types.\n */\ndeclare function register(recog: GestureRecognizer): void;\n\nexport {setTouchAction};\n\n\n/**\n * Sets scrolling direction on node.\n *\n * This value is checked on first move, thus it should be called prior to\n * adding event listeners.\n */\ndeclare function setTouchAction(node: EventTarget, value: string): void;\n\nexport {prevent};\n\n\n/**\n * Prevents the dispatch and default action of the given event name.\n */\ndeclare function prevent(evName: string): void;\n\nexport {resetMouseCanceller};\n\n\n/**\n * Reset the 2500ms timeout on processing mouse input after detecting touch input.\n *\n * Touch inputs create synthesized mouse inputs anywhere from 0 to 2000ms after the touch.\n * This method should only be called during testing with simulated touch inputs.\n * Calling this method in production may cause duplicate taps or other Gestures.\n */\ndeclare function resetMouseCanceller(): void;\n\nimport {GestureRecognizer} from '../../interfaces';\n"
  },
  {
    "path": "lib/utils/gestures.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n/**\n * @fileoverview\n *\n * Module for adding listeners to a node for the following normalized\n * cross-platform \"gesture\" events:\n * - `down` - mouse or touch went down\n * - `up` - mouse or touch went up\n * - `tap` - mouse click or finger tap\n * - `track` - mouse drag or touch move\n *\n * @summary Module for adding cross-platform gesture event listeners.\n */\n\nimport './boot.js';\n\nimport { timeOut, microTask } from './async.js';\nimport { Debouncer } from './debounce.js';\nimport { passiveTouchGestures, cancelSyntheticClickEvents } from './settings.js';\nimport { wrap } from './wrap.js';\n\n// detect native touch action support\nlet HAS_NATIVE_TA = typeof document.head.style.touchAction === 'string';\nlet GESTURE_KEY = '__polymerGestures';\nlet HANDLED_OBJ = '__polymerGesturesHandled';\nlet TOUCH_ACTION = '__polymerGesturesTouchAction';\n// radius for tap and track\nlet TAP_DISTANCE = 25;\nlet TRACK_DISTANCE = 5;\n// number of last N track positions to keep\nlet TRACK_LENGTH = 2;\n\n// Disabling \"mouse\" handlers for 2500ms is enough\nlet MOUSE_TIMEOUT = 2500;\nlet MOUSE_EVENTS = ['mousedown', 'mousemove', 'mouseup', 'click'];\n// an array of bitmask values for mapping MouseEvent.which to MouseEvent.buttons\nlet MOUSE_WHICH_TO_BUTTONS = [0, 1, 4, 2];\nlet MOUSE_HAS_BUTTONS = (function() {\n  try {\n    return new MouseEvent('test', {buttons: 1}).buttons === 1;\n  } catch (e) {\n    return false;\n  }\n})();\n\n/**\n * @param {string} name Possible mouse event name\n * @return {boolean} true if mouse event, false if not\n */\nfunction isMouseEvent(name) {\n  return MOUSE_EVENTS.indexOf(name) > -1;\n}\n\n/* eslint no-empty: [\"error\", { \"allowEmptyCatch\": true }] */\n// check for passive event listeners\nlet supportsPassive = false;\n(function() {\n  try {\n    let opts = Object.defineProperty({}, 'passive', {get() {supportsPassive = true;}});\n    window.addEventListener('test', null, opts);\n    window.removeEventListener('test', null, opts);\n  } catch(e) {}\n})();\n\n/**\n * Generate settings for event listeners, dependant on `passiveTouchGestures`\n *\n * @param {string} eventName Event name to determine if `{passive}` option is\n *   needed\n * @return {{passive: boolean} | undefined} Options to use for addEventListener\n *   and removeEventListener\n */\nfunction PASSIVE_TOUCH(eventName) {\n  if (isMouseEvent(eventName) || eventName === 'touchend') {\n    return;\n  }\n  if (HAS_NATIVE_TA && supportsPassive && passiveTouchGestures) {\n    return {passive: true};\n  } else {\n    return;\n  }\n}\n\n// Check for touch-only devices\nlet IS_TOUCH_ONLY = navigator.userAgent.match(/iP(?:[oa]d|hone)|Android/);\n\n// keep track of any labels hit by the mouseCanceller\n/** @type {!Array<!HTMLLabelElement>} */\nconst clickedLabels = [];\n\n/** @type {!Object<boolean>} */\nconst labellable = {\n  'button': true,\n  'input': true,\n  'keygen': true,\n  'meter': true,\n  'output': true,\n  'textarea': true,\n  'progress': true,\n  'select': true\n};\n\n// Defined at https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#enabling-and-disabling-form-controls:-the-disabled-attribute\n/** @type {!Object<boolean>} */\nconst canBeDisabled = {\n  'button': true,\n  'command': true,\n  'fieldset': true,\n  'input': true,\n  'keygen': true,\n  'optgroup': true,\n  'option': true,\n  'select': true,\n  'textarea': true\n};\n\n/**\n * @param {HTMLElement} el Element to check labelling status\n * @return {boolean} element can have labels\n */\nfunction canBeLabelled(el) {\n  return labellable[el.localName] || false;\n}\n\n/**\n * @param {HTMLElement} el Element that may be labelled.\n * @return {!Array<!HTMLLabelElement>} Relevant label for `el`\n */\nfunction matchingLabels(el) {\n  let labels = Array.prototype.slice.call(/** @type {HTMLInputElement} */(el).labels || []);\n  // IE doesn't have `labels` and Safari doesn't populate `labels`\n  // if element is in a shadowroot.\n  // In this instance, finding the non-ancestor labels is enough,\n  // as the mouseCancellor code will handle ancstor labels\n  if (!labels.length) {\n    labels = [];\n    try {\n      let root = el.getRootNode();\n      // if there is an id on `el`, check for all labels with a matching `for` attribute\n      if (el.id) {\n        let matching = root.querySelectorAll(`label[for = '${el.id}']`);\n        for (let i = 0; i < matching.length; i++) {\n          labels.push(/** @type {!HTMLLabelElement} */(matching[i]));\n        }\n      }\n    } catch (e) {\n      // Either:\n      // 1. el.getRootNode() failed.\n      // 2. el.id cannot be used in `querySelectorAll`\n      // In both cases, do nothing.\n    }\n  }\n  return labels;\n}\n\n// touch will make synthetic mouse events\n// `preventDefault` on touchend will cancel them,\n// but this breaks `<input>` focus and link clicks\n// disable mouse handlers for MOUSE_TIMEOUT ms after\n// a touchend to ignore synthetic mouse events\nlet mouseCanceller = function(mouseEvent) {\n  // Check for sourceCapabilities, used to distinguish synthetic events\n  // if mouseEvent did not come from a device that fires touch events,\n  // it was made by a real mouse and should be counted\n  // http://wicg.github.io/InputDeviceCapabilities/#dom-inputdevicecapabilities-firestouchevents\n  let sc = mouseEvent.sourceCapabilities;\n  if (sc && !sc.firesTouchEvents) {\n    return;\n  }\n  // skip synthetic mouse events\n  mouseEvent[HANDLED_OBJ] = {skip: true};\n  // disable \"ghost clicks\"\n  if (mouseEvent.type === 'click') {\n    let clickFromLabel = false;\n    let path = getComposedPath(mouseEvent);\n    for (let i = 0; i < path.length; i++) {\n      if (path[i].nodeType === Node.ELEMENT_NODE) {\n        if (path[i].localName === 'label') {\n          clickedLabels.push(/** @type {!HTMLLabelElement} */ (path[i]));\n        } else if (canBeLabelled(/** @type {!HTMLElement} */ (path[i]))) {\n          let ownerLabels =\n              matchingLabels(/** @type {!HTMLElement} */ (path[i]));\n          // check if one of the clicked labels is labelling this element\n          for (let j = 0; j < ownerLabels.length; j++) {\n            clickFromLabel = clickFromLabel || clickedLabels.indexOf(ownerLabels[j]) > -1;\n          }\n        }\n      }\n      if (path[i] === POINTERSTATE.mouse.target) {\n        return;\n      }\n    }\n    // if one of the clicked labels was labelling the target element,\n    // this is not a ghost click\n    if (clickFromLabel) {\n      return;\n    }\n    mouseEvent.preventDefault();\n    mouseEvent.stopPropagation();\n  }\n};\n\n/**\n * @param {boolean=} setup True to add, false to remove.\n * @return {void}\n */\nfunction setupTeardownMouseCanceller(setup) {\n  let events = IS_TOUCH_ONLY ? ['click'] : MOUSE_EVENTS;\n  for (let i = 0, en; i < events.length; i++) {\n    en = events[i];\n    if (setup) {\n      // reset clickLabels array\n      clickedLabels.length = 0;\n      document.addEventListener(en, mouseCanceller, true);\n    } else {\n      document.removeEventListener(en, mouseCanceller, true);\n    }\n  }\n}\n\nfunction ignoreMouse(e) {\n  if (!cancelSyntheticClickEvents) {\n    return;\n  }\n  if (!POINTERSTATE.mouse.mouseIgnoreJob) {\n    setupTeardownMouseCanceller(true);\n  }\n  let unset = function() {\n    setupTeardownMouseCanceller();\n    POINTERSTATE.mouse.target = null;\n    POINTERSTATE.mouse.mouseIgnoreJob = null;\n  };\n  POINTERSTATE.mouse.target = getComposedPath(e)[0];\n  POINTERSTATE.mouse.mouseIgnoreJob = Debouncer.debounce(\n        POINTERSTATE.mouse.mouseIgnoreJob\n      , timeOut.after(MOUSE_TIMEOUT)\n      , unset);\n}\n\n/**\n * @param {MouseEvent} ev event to test for left mouse button down\n * @return {boolean} has left mouse button down\n */\nfunction hasLeftMouseButton(ev) {\n  let type = ev.type;\n  // exit early if the event is not a mouse event\n  if (!isMouseEvent(type)) {\n    return false;\n  }\n  // ev.button is not reliable for mousemove (0 is overloaded as both left button and no buttons)\n  // instead we use ev.buttons (bitmask of buttons) or fall back to ev.which (deprecated, 0 for no buttons, 1 for left button)\n  if (type === 'mousemove') {\n    // allow undefined for testing events\n    let buttons = ev.buttons === undefined ? 1 : ev.buttons;\n    if ((ev instanceof window.MouseEvent) && !MOUSE_HAS_BUTTONS) {\n      buttons = MOUSE_WHICH_TO_BUTTONS[ev.which] || 0;\n    }\n    // buttons is a bitmask, check that the left button bit is set (1)\n    return Boolean(buttons & 1);\n  } else {\n    // allow undefined for testing events\n    let button = ev.button === undefined ? 0 : ev.button;\n    // ev.button is 0 in mousedown/mouseup/click for left button activation\n    return button === 0;\n  }\n}\n\nfunction isSyntheticClick(ev) {\n  if (ev.type === 'click') {\n    // ev.detail is 0 for HTMLElement.click in most browsers\n    if (ev.detail === 0) {\n      return true;\n    }\n    // in the worst case, check that the x/y position of the click is within\n    // the bounding box of the target of the event\n    // Thanks IE 10 >:(\n    let t = _findOriginalTarget(ev);\n    // make sure the target of the event is an element so we can use getBoundingClientRect,\n    // if not, just assume it is a synthetic click\n    if (!t.nodeType || /** @type {Element} */(t).nodeType !== Node.ELEMENT_NODE) {\n      return true;\n    }\n    let bcr = /** @type {Element} */(t).getBoundingClientRect();\n    // use page x/y to account for scrolling\n    let x = ev.pageX, y = ev.pageY;\n    // ev is a synthetic click if the position is outside the bounding box of the target\n    return !((x >= bcr.left && x <= bcr.right) && (y >= bcr.top && y <= bcr.bottom));\n  }\n  return false;\n}\n\nlet POINTERSTATE = {\n  mouse: {\n    target: null,\n    mouseIgnoreJob: null\n  },\n  touch: {\n    x: 0,\n    y: 0,\n    id: -1,\n    scrollDecided: false\n  }\n};\n\nfunction firstTouchAction(ev) {\n  let ta = 'auto';\n  let path = getComposedPath(ev);\n  for (let i = 0, n; i < path.length; i++) {\n    n = path[i];\n    if (n[TOUCH_ACTION]) {\n      ta = n[TOUCH_ACTION];\n      break;\n    }\n  }\n  return ta;\n}\n\nfunction trackDocument(stateObj, movefn, upfn) {\n  stateObj.movefn = movefn;\n  stateObj.upfn = upfn;\n  document.addEventListener('mousemove', movefn);\n  document.addEventListener('mouseup', upfn);\n}\n\nfunction untrackDocument(stateObj) {\n  document.removeEventListener('mousemove', stateObj.movefn);\n  document.removeEventListener('mouseup', stateObj.upfn);\n  stateObj.movefn = null;\n  stateObj.upfn = null;\n}\n\nif (cancelSyntheticClickEvents) {\n  // use a document-wide touchend listener to start the ghost-click prevention mechanism\n  // Use passive event listeners, if supported, to not affect scrolling performance\n  document.addEventListener('touchend', ignoreMouse, supportsPassive ? {passive: true} : false);\n}\n\n/**\n * Returns the composedPath for the given event.\n * @param {Event} event to process\n * @return {!Array<!EventTarget>} Path of the event\n */\nconst getComposedPath = window.ShadyDOM && window.ShadyDOM.noPatch ?\n  window.ShadyDOM.composedPath :\n  (event) => event.composedPath && event.composedPath() || [];\n\n/** @type {!Object<string, !GestureRecognizer>} */\nexport const gestures = {};\n\n/** @type {!Array<!GestureRecognizer>} */\nexport const recognizers = [];\n\n/**\n * Finds the element rendered on the screen at the provided coordinates.\n *\n * Similar to `document.elementFromPoint`, but pierces through\n * shadow roots.\n *\n * @param {number} x Horizontal pixel coordinate\n * @param {number} y Vertical pixel coordinate\n * @return {Element} Returns the deepest shadowRoot inclusive element\n * found at the screen position given.\n */\nexport function deepTargetFind(x, y) {\n  let node = document.elementFromPoint(x, y);\n  let next = node;\n  // this code path is only taken when native ShadowDOM is used\n  // if there is a shadowroot, it may have a node at x/y\n  // if there is not a shadowroot, exit the loop\n  while (next && next.shadowRoot && !window.ShadyDOM) {\n    // if there is a node at x/y in the shadowroot, look deeper\n    let oldNext = next;\n    next = next.shadowRoot.elementFromPoint(x, y);\n    // on Safari, elementFromPoint may return the shadowRoot host\n    if (oldNext === next) {\n      break;\n    }\n    if (next) {\n      node = next;\n    }\n  }\n  return node;\n}\n\n/**\n * a cheaper check than ev.composedPath()[0];\n *\n * @private\n * @param {Event|Touch} ev Event.\n * @return {EventTarget} Returns the event target.\n */\nfunction _findOriginalTarget(ev) {\n  const path = getComposedPath(/** @type {?Event} */ (ev));\n  // It shouldn't be, but sometimes path is empty (window on Safari).\n  return path.length > 0 ? path[0] : ev.target;\n}\n\n/**\n * @private\n * @param {Event} ev Event.\n * @return {void}\n */\nfunction _handleNative(ev) {\n  let handled;\n  let type = ev.type;\n  let node = ev.currentTarget;\n  let gobj = node[GESTURE_KEY];\n  if (!gobj) {\n    return;\n  }\n  let gs = gobj[type];\n  if (!gs) {\n    return;\n  }\n  if (!ev[HANDLED_OBJ]) {\n    ev[HANDLED_OBJ] = {};\n    if (type.slice(0, 5) === 'touch') {\n      ev = /** @type {TouchEvent} */(ev); // eslint-disable-line no-self-assign\n      let t = ev.changedTouches[0];\n      if (type === 'touchstart') {\n        // only handle the first finger\n        if (ev.touches.length === 1) {\n          POINTERSTATE.touch.id = t.identifier;\n        }\n      }\n      if (POINTERSTATE.touch.id !== t.identifier) {\n        return;\n      }\n      if (!HAS_NATIVE_TA) {\n        if (type === 'touchstart' || type === 'touchmove') {\n          _handleTouchAction(ev);\n        }\n      }\n    }\n  }\n  handled = ev[HANDLED_OBJ];\n  // used to ignore synthetic mouse events\n  if (handled.skip) {\n    return;\n  }\n  // reset recognizer state\n  for (let i = 0, r; i < recognizers.length; i++) {\n    r = recognizers[i];\n    if (gs[r.name] && !handled[r.name]) {\n      if (r.flow && r.flow.start.indexOf(ev.type) > -1 && r.reset) {\n        r.reset();\n      }\n    }\n  }\n  // enforce gesture recognizer order\n  for (let i = 0, r; i < recognizers.length; i++) {\n    r = recognizers[i];\n    if (gs[r.name] && !handled[r.name]) {\n      handled[r.name] = true;\n      r[type](ev);\n    }\n  }\n}\n\n/**\n * @private\n * @param {TouchEvent} ev Event.\n * @return {void}\n */\nfunction _handleTouchAction(ev) {\n  let t = ev.changedTouches[0];\n  let type = ev.type;\n  if (type === 'touchstart') {\n    POINTERSTATE.touch.x = t.clientX;\n    POINTERSTATE.touch.y = t.clientY;\n    POINTERSTATE.touch.scrollDecided = false;\n  } else if (type === 'touchmove') {\n    if (POINTERSTATE.touch.scrollDecided) {\n      return;\n    }\n    POINTERSTATE.touch.scrollDecided = true;\n    let ta = firstTouchAction(ev);\n    let shouldPrevent = false;\n    let dx = Math.abs(POINTERSTATE.touch.x - t.clientX);\n    let dy = Math.abs(POINTERSTATE.touch.y - t.clientY);\n    if (!ev.cancelable) {\n      // scrolling is happening\n    } else if (ta === 'none') {\n      shouldPrevent = true;\n    } else if (ta === 'pan-x') {\n      shouldPrevent = dy > dx;\n    } else if (ta === 'pan-y') {\n      shouldPrevent = dx > dy;\n    }\n    if (shouldPrevent) {\n      ev.preventDefault();\n    } else {\n      prevent('track');\n    }\n  }\n}\n\n/**\n * Adds an event listener to a node for the given gesture type.\n *\n * @param {!EventTarget} node Node to add listener on\n * @param {string} evType Gesture type: `down`, `up`, `track`, or `tap`\n * @param {!function(!Event):void} handler Event listener function to call\n * @return {boolean} Returns true if a gesture event listener was added.\n */\nexport function addListener(node, evType, handler) {\n  if (gestures[evType]) {\n    _add(node, evType, handler);\n    return true;\n  }\n  return false;\n}\n\n/**\n * Removes an event listener from a node for the given gesture type.\n *\n * @param {!EventTarget} node Node to remove listener from\n * @param {string} evType Gesture type: `down`, `up`, `track`, or `tap`\n * @param {!function(!Event):void} handler Event listener function previously passed to\n *  `addListener`.\n * @return {boolean} Returns true if a gesture event listener was removed.\n */\nexport function removeListener(node, evType, handler) {\n  if (gestures[evType]) {\n    _remove(node, evType, handler);\n    return true;\n  }\n  return false;\n}\n\n/**\n * automate the event listeners for the native events\n *\n * @private\n * @param {!EventTarget} node Node on which to add the event.\n * @param {string} evType Event type to add.\n * @param {function(!Event)} handler Event handler function.\n * @return {void}\n */\nfunction _add(node, evType, handler) {\n  let recognizer = gestures[evType];\n  let deps = recognizer.deps;\n  let name = recognizer.name;\n  let gobj = node[GESTURE_KEY];\n  if (!gobj) {\n    node[GESTURE_KEY] = gobj = {};\n  }\n  for (let i = 0, dep, gd; i < deps.length; i++) {\n    dep = deps[i];\n    // don't add mouse handlers on iOS because they cause gray selection overlays\n    if (IS_TOUCH_ONLY && isMouseEvent(dep) && dep !== 'click') {\n      continue;\n    }\n    gd = gobj[dep];\n    if (!gd) {\n      gobj[dep] = gd = {_count: 0};\n    }\n    if (gd._count === 0) {\n      node.addEventListener(dep, _handleNative, PASSIVE_TOUCH(dep));\n    }\n    gd[name] = (gd[name] || 0) + 1;\n    gd._count = (gd._count || 0) + 1;\n  }\n  node.addEventListener(evType, handler);\n  if (recognizer.touchAction) {\n    setTouchAction(node, recognizer.touchAction);\n  }\n}\n\n/**\n * automate event listener removal for native events\n *\n * @private\n * @param {!EventTarget} node Node on which to remove the event.\n * @param {string} evType Event type to remove.\n * @param {function(!Event): void} handler Event handler function.\n * @return {void}\n */\nfunction _remove(node, evType, handler) {\n  let recognizer = gestures[evType];\n  let deps = recognizer.deps;\n  let name = recognizer.name;\n  let gobj = node[GESTURE_KEY];\n  if (gobj) {\n    for (let i = 0, dep, gd; i < deps.length; i++) {\n      dep = deps[i];\n      gd = gobj[dep];\n      if (gd && gd[name]) {\n        gd[name] = (gd[name] || 1) - 1;\n        gd._count = (gd._count || 1) - 1;\n        if (gd._count === 0) {\n          node.removeEventListener(dep, _handleNative, PASSIVE_TOUCH(dep));\n        }\n      }\n    }\n  }\n  node.removeEventListener(evType, handler);\n}\n\n/**\n * Registers a new gesture event recognizer for adding new custom\n * gesture event types.\n *\n * @param {!GestureRecognizer} recog Gesture recognizer descriptor\n * @return {void}\n */\nexport function register(recog) {\n  recognizers.push(recog);\n  for (let i = 0; i < recog.emits.length; i++) {\n    gestures[recog.emits[i]] = recog;\n  }\n}\n\n/**\n * @private\n * @param {string} evName Event name.\n * @return {Object} Returns the gesture for the given event name.\n */\nfunction _findRecognizerByEvent(evName) {\n  for (let i = 0, r; i < recognizers.length; i++) {\n    r = recognizers[i];\n    for (let j = 0, n; j < r.emits.length; j++) {\n      n = r.emits[j];\n      if (n === evName) {\n        return r;\n      }\n    }\n  }\n  return null;\n}\n\n/**\n * Sets scrolling direction on node.\n *\n * This value is checked on first move, thus it should be called prior to\n * adding event listeners.\n *\n * @param {!EventTarget} node Node to set touch action setting on\n * @param {string} value Touch action value\n * @return {void}\n */\nexport function setTouchAction(node, value) {\n  if (HAS_NATIVE_TA && node instanceof HTMLElement) {\n    // NOTE: add touchAction async so that events can be added in\n    // custom element constructors. Otherwise we run afoul of custom\n    // elements restriction against settings attributes (style) in the\n    // constructor.\n    microTask.run(() => {\n      node.style.touchAction = value;\n    });\n  }\n  node[TOUCH_ACTION] = value;\n}\n\n/**\n * Dispatches an event on the `target` element of `type` with the given\n * `detail`.\n * @private\n * @param {!EventTarget} target The element on which to fire an event.\n * @param {string} type The type of event to fire.\n * @param {!Object=} detail The detail object to populate on the event.\n * @return {void}\n */\nfunction _fire(target, type, detail) {\n  let ev = new Event(type, { bubbles: true, cancelable: true, composed: true });\n  ev.detail = detail;\n  wrap(/** @type {!Node} */(target)).dispatchEvent(ev);\n  // forward `preventDefault` in a clean way\n  if (ev.defaultPrevented) {\n    let preventer = detail.preventer || detail.sourceEvent;\n    if (preventer && preventer.preventDefault) {\n      preventer.preventDefault();\n    }\n  }\n}\n\n/**\n * Prevents the dispatch and default action of the given event name.\n *\n * @param {string} evName Event name.\n * @return {void}\n */\nexport function prevent(evName) {\n  let recognizer = _findRecognizerByEvent(evName);\n  if (recognizer.info) {\n    recognizer.info.prevent = true;\n  }\n}\n\n/**\n * Reset the 2500ms timeout on processing mouse input after detecting touch input.\n *\n * Touch inputs create synthesized mouse inputs anywhere from 0 to 2000ms after the touch.\n * This method should only be called during testing with simulated touch inputs.\n * Calling this method in production may cause duplicate taps or other Gestures.\n *\n * @return {void}\n */\nexport function resetMouseCanceller() {\n  if (POINTERSTATE.mouse.mouseIgnoreJob) {\n    POINTERSTATE.mouse.mouseIgnoreJob.flush();\n  }\n}\n\n/* eslint-disable valid-jsdoc */\n\nregister({\n  name: 'downup',\n  deps: ['mousedown', 'touchstart', 'touchend'],\n  flow: {\n    start: ['mousedown', 'touchstart'],\n    end: ['mouseup', 'touchend']\n  },\n  emits: ['down', 'up'],\n\n  info: {\n    movefn: null,\n    upfn: null\n  },\n\n  /**\n   * @this {GestureRecognizer}\n   * @return {void}\n   */\n  reset: function() {\n    untrackDocument(this.info);\n  },\n\n  /**\n   * @this {GestureRecognizer}\n   * @param {MouseEvent} e\n   * @return {void}\n   */\n  mousedown: function(e) {\n    if (!hasLeftMouseButton(e)) {\n      return;\n    }\n    let t = _findOriginalTarget(e);\n    let self = this;\n    let movefn = function movefn(e) {\n      if (!hasLeftMouseButton(e)) {\n        downupFire('up', t, e);\n        untrackDocument(self.info);\n      }\n    };\n    let upfn = function upfn(e) {\n      if (hasLeftMouseButton(e)) {\n        downupFire('up', t, e);\n      }\n      untrackDocument(self.info);\n    };\n    trackDocument(this.info, movefn, upfn);\n    downupFire('down', t, e);\n  },\n  /**\n   * @this {GestureRecognizer}\n   * @param {TouchEvent} e\n   * @return {void}\n   */\n  touchstart: function(e) {\n    downupFire('down', _findOriginalTarget(e), e.changedTouches[0], e);\n  },\n  /**\n   * @this {GestureRecognizer}\n   * @param {TouchEvent} e\n   * @return {void}\n   */\n  touchend: function(e) {\n    downupFire('up', _findOriginalTarget(e), e.changedTouches[0], e);\n  }\n});\n\n/**\n * @param {string} type\n * @param {EventTarget} target\n * @param {Event|Touch} event\n * @param {Event=} preventer\n * @return {void}\n */\nfunction downupFire(type, target, event, preventer) {\n  if (!target) {\n    return;\n  }\n  _fire(target, type, {\n    x: event.clientX,\n    y: event.clientY,\n    sourceEvent: event,\n    preventer: preventer,\n    prevent: function(e) {\n      return prevent(e);\n    }\n  });\n}\n\nregister({\n  name: 'track',\n  touchAction: 'none',\n  deps: ['mousedown', 'touchstart', 'touchmove', 'touchend'],\n  flow: {\n    start: ['mousedown', 'touchstart'],\n    end: ['mouseup', 'touchend']\n  },\n  emits: ['track'],\n\n  info: {\n    x: 0,\n    y: 0,\n    state: 'start',\n    started: false,\n    moves: [],\n    /** @this {GestureInfo} */\n    addMove: function(move) {\n      if (this.moves.length > TRACK_LENGTH) {\n        this.moves.shift();\n      }\n      this.moves.push(move);\n    },\n    movefn: null,\n    upfn: null,\n    prevent: false\n  },\n\n  /**\n   * @this {GestureRecognizer}\n   * @return {void}\n   */\n  reset: function() {\n    this.info.state = 'start';\n    this.info.started = false;\n    this.info.moves = [];\n    this.info.x = 0;\n    this.info.y = 0;\n    this.info.prevent = false;\n    untrackDocument(this.info);\n  },\n\n  /**\n   * @this {GestureRecognizer}\n   * @param {MouseEvent} e\n   * @return {void}\n   */\n  mousedown: function(e) {\n    if (!hasLeftMouseButton(e)) {\n      return;\n    }\n    let t = _findOriginalTarget(e);\n    let self = this;\n    let movefn = function movefn(e) {\n      let x = e.clientX, y = e.clientY;\n      if (trackHasMovedEnough(self.info, x, y)) {\n        // first move is 'start', subsequent moves are 'move', mouseup is 'end'\n        self.info.state = self.info.started ? (e.type === 'mouseup' ? 'end' : 'track') : 'start';\n        if (self.info.state === 'start') {\n          // if and only if tracking, always prevent tap\n          prevent('tap');\n        }\n        self.info.addMove({x: x, y: y});\n        if (!hasLeftMouseButton(e)) {\n          // always fire \"end\"\n          self.info.state = 'end';\n          untrackDocument(self.info);\n        }\n        if (t) {\n          trackFire(self.info, t, e);\n        }\n        self.info.started = true;\n      }\n    };\n    let upfn = function upfn(e) {\n      if (self.info.started) {\n        movefn(e);\n      }\n\n      // remove the temporary listeners\n      untrackDocument(self.info);\n    };\n    // add temporary document listeners as mouse retargets\n    trackDocument(this.info, movefn, upfn);\n    this.info.x = e.clientX;\n    this.info.y = e.clientY;\n  },\n  /**\n   * @this {GestureRecognizer}\n   * @param {TouchEvent} e\n   * @return {void}\n   */\n  touchstart: function(e) {\n    let ct = e.changedTouches[0];\n    this.info.x = ct.clientX;\n    this.info.y = ct.clientY;\n  },\n  /**\n   * @this {GestureRecognizer}\n   * @param {TouchEvent} e\n   * @return {void}\n   */\n  touchmove: function(e) {\n    let t = _findOriginalTarget(e);\n    let ct = e.changedTouches[0];\n    let x = ct.clientX, y = ct.clientY;\n    if (trackHasMovedEnough(this.info, x, y)) {\n      if (this.info.state === 'start') {\n        // if and only if tracking, always prevent tap\n        prevent('tap');\n      }\n      this.info.addMove({x: x, y: y});\n      trackFire(this.info, t, ct);\n      this.info.state = 'track';\n      this.info.started = true;\n    }\n  },\n  /**\n   * @this {GestureRecognizer}\n   * @param {TouchEvent} e\n   * @return {void}\n   */\n  touchend: function(e) {\n    let t = _findOriginalTarget(e);\n    let ct = e.changedTouches[0];\n    // only trackend if track was started and not aborted\n    if (this.info.started) {\n      // reset started state on up\n      this.info.state = 'end';\n      this.info.addMove({x: ct.clientX, y: ct.clientY});\n      trackFire(this.info, t, ct);\n    }\n  }\n});\n\n/**\n * @param {!GestureInfo} info\n * @param {number} x\n * @param {number} y\n * @return {boolean}\n */\nfunction trackHasMovedEnough(info, x, y) {\n  if (info.prevent) {\n    return false;\n  }\n  if (info.started) {\n    return true;\n  }\n  let dx = Math.abs(info.x - x);\n  let dy = Math.abs(info.y - y);\n  return (dx >= TRACK_DISTANCE || dy >= TRACK_DISTANCE);\n}\n\n/**\n * @param {!GestureInfo} info\n * @param {?EventTarget} target\n * @param {Touch} touch\n * @return {void}\n */\nfunction trackFire(info, target, touch) {\n  if (!target) {\n    return;\n  }\n  let secondlast = info.moves[info.moves.length - 2];\n  let lastmove = info.moves[info.moves.length - 1];\n  let dx = lastmove.x - info.x;\n  let dy = lastmove.y - info.y;\n  let ddx, ddy = 0;\n  if (secondlast) {\n    ddx = lastmove.x - secondlast.x;\n    ddy = lastmove.y - secondlast.y;\n  }\n  _fire(target, 'track', {\n    state: info.state,\n    x: touch.clientX,\n    y: touch.clientY,\n    dx: dx,\n    dy: dy,\n    ddx: ddx,\n    ddy: ddy,\n    sourceEvent: touch,\n    hover: function() {\n      return deepTargetFind(touch.clientX, touch.clientY);\n    }\n  });\n}\n\nregister({\n  name: 'tap',\n  deps: ['mousedown', 'click', 'touchstart', 'touchend'],\n  flow: {\n    start: ['mousedown', 'touchstart'],\n    end: ['click', 'touchend']\n  },\n  emits: ['tap'],\n  info: {\n    x: NaN,\n    y: NaN,\n    prevent: false\n  },\n  /**\n   * @this {GestureRecognizer}\n   * @return {void}\n   */\n  reset: function() {\n    this.info.x = NaN;\n    this.info.y = NaN;\n    this.info.prevent = false;\n  },\n  /**\n   * @this {GestureRecognizer}\n   * @param {MouseEvent} e\n   * @return {void}\n   */\n  mousedown: function(e) {\n    if (hasLeftMouseButton(e)) {\n      this.info.x = e.clientX;\n      this.info.y = e.clientY;\n    }\n  },\n  /**\n   * @this {GestureRecognizer}\n   * @param {MouseEvent} e\n   * @return {void}\n   */\n  click: function(e) {\n    if (hasLeftMouseButton(e)) {\n      trackForward(this.info, e);\n    }\n  },\n  /**\n   * @this {GestureRecognizer}\n   * @param {TouchEvent} e\n   * @return {void}\n   */\n  touchstart: function(e) {\n    const touch = e.changedTouches[0];\n    this.info.x = touch.clientX;\n    this.info.y = touch.clientY;\n  },\n  /**\n   * @this {GestureRecognizer}\n   * @param {TouchEvent} e\n   * @return {void}\n   */\n  touchend: function(e) {\n    trackForward(this.info, e.changedTouches[0], e);\n  }\n});\n\n/**\n * @param {!GestureInfo} info\n * @param {Event | Touch} e\n * @param {Event=} preventer\n * @return {void}\n */\nfunction trackForward(info, e, preventer) {\n  let dx = Math.abs(e.clientX - info.x);\n  let dy = Math.abs(e.clientY - info.y);\n  // find original target from `preventer` for TouchEvents, or `e` for MouseEvents\n  let t = _findOriginalTarget((preventer || e));\n  if (!t || (canBeDisabled[/** @type {!HTMLElement} */(t).localName] && t.hasAttribute('disabled'))) {\n    return;\n  }\n  // dx,dy can be NaN if `click` has been simulated and there was no `down` for `start`\n  if (isNaN(dx) || isNaN(dy) || (dx <= TAP_DISTANCE && dy <= TAP_DISTANCE) || isSyntheticClick(e)) {\n    // prevent taps from being generated if an event has canceled them\n    if (!info.prevent) {\n      _fire(t, 'tap', {\n        x: e.clientX,\n        y: e.clientY,\n        sourceEvent: e,\n        preventer: preventer\n      });\n    }\n  }\n}\n\n/* eslint-enable valid-jsdoc */\n\n/** @deprecated */\nexport const findOriginalTarget = _findOriginalTarget;\n\n/** @deprecated */\nexport const add = addListener;\n\n/** @deprecated */\nexport const remove = removeListener;\n"
  },
  {
    "path": "lib/utils/hide-template-controls.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n\nexport {hideElementsGlobally};\n\n\n/**\n * @returns True if elements will be hidden globally\n */\ndeclare function hideElementsGlobally(): boolean;\n"
  },
  {
    "path": "lib/utils/hide-template-controls.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n/**\n * @fileoverview\n *\n * Module to hide `<dom-bind>`, `<dom-if>`, and `<dom-repeat>` elements\n * optimally in ShadyDOM\n */\n\nimport {legacyOptimizations, useShadow} from './settings.js';\n\nlet elementsHidden = false;\n\n/**\n * @return {boolean} True if elements will be hidden globally\n */\nexport function hideElementsGlobally() {\n  if (legacyOptimizations && !useShadow) {\n    if (!elementsHidden) {\n      elementsHidden = true;\n      const style = document.createElement('style');\n      style.textContent = 'dom-bind,dom-if,dom-repeat{display:none;}';\n      document.head.appendChild(style);\n    }\n    return true;\n  }\n  return false;\n}"
  },
  {
    "path": "lib/utils/html-tag.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n// tslint:disable:no-any describes the API as best we are able today\n\n/**\n * Class representing a static string value which can be used to filter\n * strings by asseting that they have been created via this class. The\n * `value` property returns the string passed to the constructor.\n */\ndeclare class LiteralString {\n  value: string;\n  constructor(string: any);\n\n  /**\n   * @returns LiteralString string value\n   */\n  toString(): string;\n}\n\nexport {html};\n\n\n/**\n * A template literal tag that creates an HTML <template> element from the\n * contents of the string.\n *\n * This allows you to write a Polymer Template in JavaScript.\n *\n * Templates can be composed by interpolating `HTMLTemplateElement`s in\n * expressions in the JavaScript template literal. The nested template's\n * `innerHTML` is included in the containing template.  The only other\n * values allowed in expressions are those returned from `htmlLiteral`\n * which ensures only literal values from JS source ever reach the HTML, to\n * guard against XSS risks.\n *\n * All other values are disallowed in expressions to help prevent XSS\n * attacks; however, `htmlLiteral` can be used to compose static\n * string values into templates. This is useful to compose strings into\n * places that do not accept html, like the css text of a `style`\n * element.\n *\n * Example:\n *\n *     static get template() {\n *       return html`\n *         <style>:host{ content:\"...\" }</style>\n *         <div class=\"shadowed\">${this.partialTemplate}</div>\n *         ${super.template}\n *       `;\n *     }\n *     static get partialTemplate() { return html`<span>Partial!</span>`; }\n *\n * @returns Constructed HTMLTemplateElement\n */\ndeclare function html(strings: TemplateStringsArray, ...values: any[]): HTMLTemplateElement;\n\nexport {htmlLiteral};\n\n\n/**\n * An html literal tag that can be used with `html` to compose.\n * a literal string.\n *\n * Example:\n *\n *     static get template() {\n *       return html`\n *         <style>\n *           :host { display: block; }\n *           ${this.styleTemplate()}\n *         </style>\n *         <div class=\"shadowed\">${staticValue}</div>\n *         ${super.template}\n *       `;\n *     }\n *     static get styleTemplate() {\n *        return htmlLiteral`.shadowed { background: gray; }`;\n *     }\n *\n * @returns Constructed literal string\n */\ndeclare function htmlLiteral(strings: TemplateStringsArray, ...values: any[]): LiteralString;\n"
  },
  {
    "path": "lib/utils/html-tag.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport './boot.js';\n\n/**\n * Our TrustedTypePolicy for HTML which is declared using the Polymer html\n * template tag function.\n *\n * That HTML is a developer-authored constant, and is parsed with innerHTML\n * before any untrusted expressions have been mixed in. Therefor it is\n * considered safe by construction.\n *\n * @type {!TrustedTypePolicy|undefined}\n */\nconst policy = window.trustedTypes &&\n    trustedTypes.createPolicy('polymer-html-literal', {createHTML: (s) => s});\n\n/**\n * Class representing a static string value which can be used to filter\n * strings by asseting that they have been created via this class. The\n * `value` property returns the string passed to the constructor.\n */\nclass LiteralString {\n  /**\n   * @param {!ITemplateArray} strings Constant parts of tagged template literal\n   * @param {!Array<*>} values Variable parts of tagged template literal\n   */\n  constructor(strings, values) {\n    assertValidTemplateStringParameters(strings, values);\n    const string = values.reduce(\n        (acc, v, idx) => acc + literalValue(v) + strings[idx + 1], strings[0]);\n    /** @type {string} */\n    this.value = string.toString();\n  }\n  /**\n   * @return {string} LiteralString string value\n   * @override\n   */\n  toString() {\n    return this.value;\n  }\n}\n\n/**\n * @param {*} value Object to stringify into HTML\n * @return {string} HTML stringified form of `obj`\n */\nfunction literalValue(value) {\n  if (value instanceof LiteralString) {\n    return /** @type {!LiteralString} */(value).value;\n  } else {\n    throw new Error(\n        `non-literal value passed to Polymer's htmlLiteral function: ${value}`\n    );\n  }\n}\n\n/**\n * @param {*} value Object to stringify into HTML\n * @return {string} HTML stringified form of `obj`\n */\nfunction htmlValue(value) {\n  if (value instanceof HTMLTemplateElement) {\n    // This might be an mXSS risk – mainly in the case where this template\n    // contains untrusted content that was believed to be sanitized.\n    // However we can't just use the XMLSerializer here because it misencodes\n    // `>` characters inside style tags.\n    // For an example of an actual case that hit this encoding issue,\n    // see b/198592167\n    return /** @type {!HTMLTemplateElement } */(value).innerHTML;\n  } else if (value instanceof LiteralString) {\n    return literalValue(value);\n  } else {\n    throw new Error(\n        `non-template value passed to Polymer's html function: ${value}`);\n  }\n}\n\n/**\n * A template literal tag that creates an HTML <template> element from the\n * contents of the string.\n *\n * This allows you to write a Polymer Template in JavaScript.\n *\n * Templates can be composed by interpolating `HTMLTemplateElement`s in\n * expressions in the JavaScript template literal. The nested template's\n * `innerHTML` is included in the containing template.  The only other\n * values allowed in expressions are those returned from `htmlLiteral`\n * which ensures only literal values from JS source ever reach the HTML, to\n * guard against XSS risks.\n *\n * All other values are disallowed in expressions to help prevent XSS\n * attacks; however, `htmlLiteral` can be used to compose static\n * string values into templates. This is useful to compose strings into\n * places that do not accept html, like the css text of a `style`\n * element.\n *\n * Example:\n *\n *     static get template() {\n *       return html`\n *         <style>:host{ content:\"...\" }</style>\n *         <div class=\"shadowed\">${this.partialTemplate}</div>\n *         ${super.template}\n *       `;\n *     }\n *     static get partialTemplate() { return html`<span>Partial!</span>`; }\n *\n * @param {!ITemplateArray} strings Constant parts of tagged template literal\n * @param {...*} values Variable parts of tagged template literal\n * @return {!HTMLTemplateElement} Constructed HTMLTemplateElement\n */\nexport const html = function html(strings, ...values) {\n  assertValidTemplateStringParameters(strings, values);\n  const template =\n      /** @type {!HTMLTemplateElement} */ (document.createElement('template'));\n  let value = values.reduce(\n      (acc, v, idx) => acc + htmlValue(v) + strings[idx + 1], strings[0]);\n  if (policy) {\n    value = policy.createHTML(value);\n  }\n  template.innerHTML = value;\n  return template;\n};\n\n/**\n * @param {!ITemplateArray} strings Constant parts of tagged template literal\n * @param {!Array<*>} values Array of values from quasis\n */\nconst assertValidTemplateStringParameters = (strings, values) => {\n  // Note: if/when https://github.com/tc39/proposal-array-is-template-object\n  // is standardized, use that instead when available, as it can perform an\n  // unforgable check (though of course, the function itself can be forged).\n  if (!Array.isArray(strings) || !Array.isArray(strings.raw) ||\n      (values.length !== strings.length - 1)) {\n    // This is either caused by a browser bug, a compiler bug, or someone\n    // calling the html template tag function as a regular function.\n    //\n    throw new TypeError('Invalid call to the html template tag');\n  }\n};\n\n/**\n * An html literal tag that can be used with `html` to compose.\n * a literal string.\n *\n * Example:\n *\n *     static get template() {\n *       return html`\n *         <style>\n *           :host { display: block; }\n *           ${this.styleTemplate()}\n *         </style>\n *         <div class=\"shadowed\">${staticValue}</div>\n *         ${super.template}\n *       `;\n *     }\n *     static get styleTemplate() {\n *        return htmlLiteral`.shadowed { background: gray; }`;\n *     }\n *\n * @param {!ITemplateArray} strings Constant parts of tagged template literal\n * @param {...*} values Variable parts of tagged template literal\n * @return {!LiteralString} Constructed literal string\n */\nexport const htmlLiteral = function(strings, ...values) {\n  return new LiteralString(strings, values);\n};\n"
  },
  {
    "path": "lib/utils/mixin.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n\nexport {dedupingMixin};\n\n\n/**\n * Wraps an ES6 class expression mixin such that the mixin is only applied\n * if it has not already been applied its base argument. Also memoizes mixin\n * applications.\n */\ndeclare function dedupingMixin<T>(mixin: T): T;\n"
  },
  {
    "path": "lib/utils/mixin.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport './boot.js';\n\n// unique global id for deduping mixins.\nlet dedupeId = 0;\n\n/**\n * @constructor\n * @extends {Function}\n * @private\n */\nfunction MixinFunction(){}\n/** @type {(WeakMap | undefined)} */\nMixinFunction.prototype.__mixinApplications;\n/** @type {(Object | undefined)} */\nMixinFunction.prototype.__mixinSet;\n\n/* eslint-disable valid-jsdoc */\n/**\n * Wraps an ES6 class expression mixin such that the mixin is only applied\n * if it has not already been applied its base argument. Also memoizes mixin\n * applications.\n *\n * @template T\n * @param {T} mixin ES6 class expression mixin to wrap\n * @return {T}\n * @suppress {invalidCasts}\n */\nexport const dedupingMixin = function(mixin) {\n  let mixinApplications = /** @type {!MixinFunction} */(mixin).__mixinApplications;\n  if (!mixinApplications) {\n    mixinApplications = new WeakMap();\n    /** @type {!MixinFunction} */(mixin).__mixinApplications = mixinApplications;\n  }\n  // maintain a unique id for each mixin\n  let mixinDedupeId = dedupeId++;\n  function dedupingMixin(base) {\n    let baseSet = /** @type {!MixinFunction} */(base).__mixinSet;\n    if (baseSet && baseSet[mixinDedupeId]) {\n      return base;\n    }\n    let map = mixinApplications;\n    let extended = map.get(base);\n    if (!extended) {\n      extended = /** @type {!Function} */(mixin)(base);\n      map.set(base, extended);\n      // copy inherited mixin set from the extended class, or the base class\n      // NOTE: we avoid use of Set here because some browser (IE11)\n      // cannot extend a base Set via the constructor.\n      let mixinSet = Object.create(/** @type {!MixinFunction} */(extended).__mixinSet || baseSet || null);\n      mixinSet[mixinDedupeId] = true;\n      /** @type {!MixinFunction} */(extended).__mixinSet = mixinSet;\n    }\n    return extended;\n  }\n\n  return dedupingMixin;\n};\n/* eslint-enable valid-jsdoc */\n"
  },
  {
    "path": "lib/utils/path.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n// tslint:disable:no-any describes the API as best we are able today\n\nexport {isPath};\n\n\n/**\n * Returns true if the given string is a structured data path (has dots).\n *\n * Example:\n *\n * ```\n * isPath('foo.bar.baz') // true\n * isPath('foo')         // false\n * ```\n *\n * @returns True if the string contained one or more dots\n */\ndeclare function isPath(path: string): boolean;\n\nexport {root};\n\n\n/**\n * Returns the root property name for the given path.\n *\n * Example:\n *\n * ```\n * root('foo.bar.baz') // 'foo'\n * root('foo')         // 'foo'\n * ```\n *\n * @returns Root property name\n */\ndeclare function root(path: string): string;\n\nexport {isAncestor};\n\n\n/**\n * Given `base` is `foo.bar`, `foo` is an ancestor, `foo.bar` is not\n * Returns true if the given path is an ancestor of the base path.\n *\n * Example:\n *\n * ```\n * isAncestor('foo.bar', 'foo')         // true\n * isAncestor('foo.bar', 'foo.bar')     // false\n * isAncestor('foo.bar', 'foo.bar.baz') // false\n * ```\n *\n * @returns True if `path` is an ancestor of `base`.\n */\ndeclare function isAncestor(base: string, path: string): boolean;\n\nexport {isDescendant};\n\n\n/**\n * Given `base` is `foo.bar`, `foo.bar.baz` is an descendant\n *\n * Example:\n *\n * ```\n * isDescendant('foo.bar', 'foo.bar.baz') // true\n * isDescendant('foo.bar', 'foo.bar')     // false\n * isDescendant('foo.bar', 'foo')         // false\n * ```\n *\n * @returns True if `path` is a descendant of `base`.\n */\ndeclare function isDescendant(base: string, path: string): boolean;\n\nexport {translate};\n\n\n/**\n * Replaces a previous base path with a new base path, preserving the\n * remainder of the path.\n *\n * User must ensure `path` has a prefix of `base`.\n *\n * Example:\n *\n * ```\n * translate('foo.bar', 'zot', 'foo.bar.baz') // 'zot.baz'\n * ```\n *\n * @returns Translated string\n */\ndeclare function translate(base: string, newBase: string, path: string): string;\n\nexport {matches};\n\n\n/**\n * @returns True if `path` is equal to `base`\n */\ndeclare function matches(base: string, path: string): boolean;\n\nexport {normalize};\n\n\n/**\n * Converts array-based paths to flattened path.  String-based paths\n * are returned as-is.\n *\n * Example:\n *\n * ```\n * normalize(['foo.bar', 0, 'baz'])  // 'foo.bar.0.baz'\n * normalize('foo.bar.0.baz')        // 'foo.bar.0.baz'\n * ```\n *\n * @returns Flattened path\n */\ndeclare function normalize(path: string|Array<string|number>): string;\n\nexport {split};\n\n\n/**\n * Splits a path into an array of property names. Accepts either arrays\n * of path parts or strings.\n *\n * Example:\n *\n * ```\n * split(['foo.bar', 0, 'baz'])  // ['foo', 'bar', '0', 'baz']\n * split('foo.bar.0.baz')        // ['foo', 'bar', '0', 'baz']\n * ```\n *\n * @returns Array of path parts\n */\ndeclare function split(path: string|Array<string|number>): string[];\n\nexport {get};\n\n\n/**\n * Reads a value from a path.  If any sub-property in the path is `undefined`,\n * this method returns `undefined` (will never throw.\n *\n * @returns Value at path, or `undefined` if the path could not be\n *  fully dereferenced.\n */\ndeclare function get(root: object|null, path: string|Array<string|number>, info?: object|null): any;\n\nexport {set};\n\n\n/**\n * Sets a value to a path.  If any sub-property in the path is `undefined`,\n * this method will no-op.\n *\n * @returns The normalized version of the input path\n */\ndeclare function set(root: object|null, path: string|Array<string|number>, value: any): string|undefined;\n"
  },
  {
    "path": "lib/utils/path.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport './boot.js';\n\n/**\n * Module with utilities for manipulating structured data path strings.\n *\n * @summary Module with utilities for manipulating structured data path strings.\n */\n\n/**\n * Returns true if the given string is a structured data path (has dots).\n *\n * Example:\n *\n * ```\n * isPath('foo.bar.baz') // true\n * isPath('foo')         // false\n * ```\n *\n * @param {string} path Path string\n * @return {boolean} True if the string contained one or more dots\n */\nexport function isPath(path) {\n  return path.indexOf('.') >= 0;\n}\n\n/**\n * Returns the root property name for the given path.\n *\n * Example:\n *\n * ```\n * root('foo.bar.baz') // 'foo'\n * root('foo')         // 'foo'\n * ```\n *\n * @param {string} path Path string\n * @return {string} Root property name\n */\nexport function root(path) {\n  let dotIndex = path.indexOf('.');\n  if (dotIndex === -1) {\n    return path;\n  }\n  return path.slice(0, dotIndex);\n}\n\n/**\n * Given `base` is `foo.bar`, `foo` is an ancestor, `foo.bar` is not\n * Returns true if the given path is an ancestor of the base path.\n *\n * Example:\n *\n * ```\n * isAncestor('foo.bar', 'foo')         // true\n * isAncestor('foo.bar', 'foo.bar')     // false\n * isAncestor('foo.bar', 'foo.bar.baz') // false\n * ```\n *\n * @param {string} base Path string to test against.\n * @param {string} path Path string to test.\n * @return {boolean} True if `path` is an ancestor of `base`.\n */\nexport function isAncestor(base, path) {\n  //     base.startsWith(path + '.');\n  return base.indexOf(path + '.') === 0;\n}\n\n/**\n * Given `base` is `foo.bar`, `foo.bar.baz` is an descendant\n *\n * Example:\n *\n * ```\n * isDescendant('foo.bar', 'foo.bar.baz') // true\n * isDescendant('foo.bar', 'foo.bar')     // false\n * isDescendant('foo.bar', 'foo')         // false\n * ```\n *\n * @param {string} base Path string to test against.\n * @param {string} path Path string to test.\n * @return {boolean} True if `path` is a descendant of `base`.\n */\nexport function isDescendant(base, path) {\n  //     path.startsWith(base + '.');\n  return path.indexOf(base + '.') === 0;\n}\n\n/**\n * Replaces a previous base path with a new base path, preserving the\n * remainder of the path.\n *\n * User must ensure `path` has a prefix of `base`.\n *\n * Example:\n *\n * ```\n * translate('foo.bar', 'zot', 'foo.bar.baz') // 'zot.baz'\n * ```\n *\n * @param {string} base Current base string to remove\n * @param {string} newBase New base string to replace with\n * @param {string} path Path to translate\n * @return {string} Translated string\n */\nexport function translate(base, newBase, path) {\n  return newBase + path.slice(base.length);\n}\n\n/**\n * @param {string} base Path string to test against\n * @param {string} path Path string to test\n * @return {boolean} True if `path` is equal to `base`\n */\nexport function matches(base, path) {\n  return (base === path) ||\n         isAncestor(base, path) ||\n         isDescendant(base, path);\n}\n\n/**\n * Converts array-based paths to flattened path.  String-based paths\n * are returned as-is.\n *\n * Example:\n *\n * ```\n * normalize(['foo.bar', 0, 'baz'])  // 'foo.bar.0.baz'\n * normalize('foo.bar.0.baz')        // 'foo.bar.0.baz'\n * ```\n *\n * @param {string | !Array<string|number>} path Input path\n * @return {string} Flattened path\n */\nexport function normalize(path) {\n  if (Array.isArray(path)) {\n    let parts = [];\n    for (let i=0; i<path.length; i++) {\n      let args = path[i].toString().split('.');\n      for (let j=0; j<args.length; j++) {\n        parts.push(args[j]);\n      }\n    }\n    return parts.join('.');\n  } else {\n    return path;\n  }\n}\n\n/**\n * Splits a path into an array of property names. Accepts either arrays\n * of path parts or strings.\n *\n * Example:\n *\n * ```\n * split(['foo.bar', 0, 'baz'])  // ['foo', 'bar', '0', 'baz']\n * split('foo.bar.0.baz')        // ['foo', 'bar', '0', 'baz']\n * ```\n *\n * @param {string | !Array<string|number>} path Input path\n * @return {!Array<string>} Array of path parts\n * @suppress {checkTypes}\n */\nexport function split(path) {\n  if (Array.isArray(path)) {\n    return normalize(path).split('.');\n  }\n  return path.toString().split('.');\n}\n\n/**\n * Reads a value from a path.  If any sub-property in the path is `undefined`,\n * this method returns `undefined` (will never throw.\n *\n * @param {Object} root Object from which to dereference path from\n * @param {string | !Array<string|number>} path Path to read\n * @param {Object=} info If an object is provided to `info`, the normalized\n *  (flattened) path will be set to `info.path`.\n * @return {*} Value at path, or `undefined` if the path could not be\n *  fully dereferenced.\n */\nexport function get(root, path, info) {\n  let prop = root;\n  let parts = split(path);\n  // Loop over path parts[0..n-1] and dereference\n  for (let i=0; i<parts.length; i++) {\n    if (!prop) {\n      return;\n    }\n    let part = parts[i];\n    prop = prop[part];\n  }\n  if (info) {\n    info.path = parts.join('.');\n  }\n  return prop;\n}\n\n/**\n * Sets a value to a path.  If any sub-property in the path is `undefined`,\n * this method will no-op.\n *\n * @param {Object} root Object from which to dereference path from\n * @param {string | !Array<string|number>} path Path to set\n * @param {*} value Value to set to path\n * @return {string | undefined} The normalized version of the input path\n */\nexport function set(root, path, value) {\n  let prop = root;\n  let parts = split(path);\n  let last = parts[parts.length-1];\n  if (parts.length > 1) {\n    // Loop over path parts[0..n-2] and dereference\n    for (let i=0; i<parts.length-1; i++) {\n      let part = parts[i];\n      prop = prop[part];\n      if (!prop) {\n        return;\n      }\n    }\n    // Set value to object at end of path\n    prop[last] = value;\n  } else {\n    // Simple property set\n    prop[path] = value;\n  }\n  return parts.join('.');\n}\n\n/**\n * Returns true if the given string is a structured data path (has dots).\n *\n * This function is deprecated.  Use `isPath` instead.\n *\n * Example:\n *\n * ```\n * isDeep('foo.bar.baz') // true\n * isDeep('foo')         // false\n * ```\n *\n * @deprecated\n * @param {string} path Path string\n * @return {boolean} True if the string contained one or more dots\n */\nexport const isDeep = isPath;\n"
  },
  {
    "path": "lib/utils/render-status.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n// tslint:disable:no-any describes the API as best we are able today\n\nexport {flush};\n\n\n/**\n * Flushes all `beforeNextRender` tasks, followed by all `afterNextRender`\n * tasks.\n */\ndeclare function flush(): void;\n\nexport {beforeNextRender};\n\n\n/**\n * Enqueues a callback which will be run before the next render, at\n * `requestAnimationFrame` timing.\n *\n * This method is useful for enqueuing work that requires DOM measurement,\n * since measurement may not be reliable in custom element callbacks before\n * the first render, as well as for batching measurement tasks in general.\n *\n * Tasks in this queue may be flushed by calling `flush()`.\n */\ndeclare function beforeNextRender(context: any, callback: (...p0: any[]) => void, args?: any[]): void;\n\nexport {afterNextRender};\n\n\n/**\n * Enqueues a callback which will be run after the next render, equivalent\n * to one task (`setTimeout`) after the next `requestAnimationFrame`.\n *\n * This method is useful for tuning the first-render performance of an\n * element or application by deferring non-critical work until after the\n * first paint.  Typical non-render-critical work may include adding UI\n * event listeners and aria attributes.\n */\ndeclare function afterNextRender(context: any, callback: (...p0: any[]) => void, args?: any[]): void;\n"
  },
  {
    "path": "lib/utils/render-status.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n/**\n * Module for scheduling flushable pre-render and post-render tasks.\n *\n * @summary Module for scheduling flushable pre-render and post-render tasks.\n */\n\nimport './boot.js';\n\nlet scheduled = false;\nlet beforeRenderQueue = [];\nlet afterRenderQueue = [];\n\nfunction schedule() {\n  scheduled = true;\n  // before next render\n  requestAnimationFrame(function() {\n    scheduled = false;\n    flushQueue(beforeRenderQueue);\n    // after the render\n    setTimeout(function() {\n      runQueue(afterRenderQueue);\n    });\n  });\n}\n\nfunction flushQueue(queue) {\n  while (queue.length) {\n    callMethod(queue.shift());\n  }\n}\n\nfunction runQueue(queue) {\n  for (let i=0, l=queue.length; i < l; i++) {\n    callMethod(queue.shift());\n  }\n}\n\nfunction callMethod(info) {\n  const context = info[0];\n  const callback = info[1];\n  const args = info[2];\n  try {\n    callback.apply(context, args);\n  } catch(e) {\n    setTimeout(() => {\n      throw e;\n    });\n  }\n}\n\n/**\n * Flushes all `beforeNextRender` tasks, followed by all `afterNextRender`\n * tasks.\n *\n * @return {void}\n */\nexport function flush() {\n  while (beforeRenderQueue.length || afterRenderQueue.length) {\n    flushQueue(beforeRenderQueue);\n    flushQueue(afterRenderQueue);\n  }\n  scheduled = false;\n}\n\n\n/**\n * Enqueues a callback which will be run before the next render, at\n * `requestAnimationFrame` timing.\n *\n * This method is useful for enqueuing work that requires DOM measurement,\n * since measurement may not be reliable in custom element callbacks before\n * the first render, as well as for batching measurement tasks in general.\n *\n * Tasks in this queue may be flushed by calling `flush()`.\n *\n * @param {*} context Context object the callback function will be bound to\n * @param {function(...*):void} callback Callback function\n * @param {!Array=} args An array of arguments to call the callback function with\n * @return {void}\n */\nexport function beforeNextRender(context, callback, args) {\n  if (!scheduled) {\n    schedule();\n  }\n  beforeRenderQueue.push([context, callback, args]);\n}\n\n/**\n * Enqueues a callback which will be run after the next render, equivalent\n * to one task (`setTimeout`) after the next `requestAnimationFrame`.\n *\n * This method is useful for tuning the first-render performance of an\n * element or application by deferring non-critical work until after the\n * first paint.  Typical non-render-critical work may include adding UI\n * event listeners and aria attributes.\n *\n * @param {*} context Context object the callback function will be bound to\n * @param {function(...*):void} callback Callback function\n * @param {!Array=} args An array of arguments to call the callback function with\n * @return {void}\n */\nexport function afterNextRender(context, callback, args) {\n  if (!scheduled) {\n    schedule();\n  }\n  afterRenderQueue.push([context, callback, args]);\n}\n\n"
  },
  {
    "path": "lib/utils/resolve-url.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n\nexport {resolveUrl};\n\n\n/**\n * Resolves the given URL against the provided `baseUri'.\n *\n * Note that this function performs no resolution for URLs that start\n * with `/` (absolute URLs) or `#` (hash identifiers).  For general purpose\n * URL resolution, use `window.URL`.\n *\n * @returns resolved URL\n */\ndeclare function resolveUrl(url: string, baseURI?: string|null): string;\n\nexport {resolveCss};\n\n\n/**\n * Resolves any relative URL's in the given CSS text against the provided\n * `ownerDocument`'s `baseURI`.\n *\n * @returns Processed CSS text with resolved URL's\n */\ndeclare function resolveCss(cssText: string, baseURI: string): string;\n\nexport {pathFromUrl};\n\n\n/**\n * Returns a path from a given `url`. The path includes the trailing\n * `/` from the url.\n *\n * @returns resolved path\n */\ndeclare function pathFromUrl(url: string): string;\n"
  },
  {
    "path": "lib/utils/resolve-url.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport './boot.js';\n\nlet CSS_URL_RX = /(url\\()([^)]*)(\\))/g;\nlet ABS_URL = /(^\\/[^\\/])|(^#)|(^[\\w-\\d]*:)/;\nlet workingURL;\nlet resolveDoc;\n/**\n * Resolves the given URL against the provided `baseUri'.\n *\n * Note that this function performs no resolution for URLs that start\n * with `/` (absolute URLs) or `#` (hash identifiers).  For general purpose\n * URL resolution, use `window.URL`.\n *\n * @param {string} url Input URL to resolve\n * @param {?string=} baseURI Base URI to resolve the URL against\n * @return {string} resolved URL\n */\nexport function resolveUrl(url, baseURI) {\n  if (url && ABS_URL.test(url)) {\n    return url;\n  }\n  if (url === '//') {\n    return url;\n  }\n  // Lazy feature detection.\n  if (workingURL === undefined) {\n    workingURL = false;\n    try {\n      const u = new URL('b', 'http://a');\n      u.pathname = 'c%20d';\n      workingURL = (u.href === 'http://a/c%20d');\n    } catch (e) {\n      // silently fail\n    }\n  }\n  if (!baseURI) {\n    baseURI = document.baseURI || window.location.href;\n  }\n  if (workingURL) {\n    try {\n      return (new URL(url, baseURI)).href;\n    } catch (e) {\n      // Bad url or baseURI structure. Do not attempt to resolve.\n      return url;\n    }\n  }\n  // Fallback to creating an anchor into a disconnected document.\n  if (!resolveDoc) {\n    resolveDoc = document.implementation.createHTMLDocument('temp');\n    resolveDoc.base = resolveDoc.createElement('base');\n    resolveDoc.head.appendChild(resolveDoc.base);\n    resolveDoc.anchor = resolveDoc.createElement('a');\n    resolveDoc.body.appendChild(resolveDoc.anchor);\n  }\n  resolveDoc.base.href = baseURI;\n  resolveDoc.anchor.href = url;\n  return resolveDoc.anchor.href || url;\n\n}\n\n/**\n * Resolves any relative URL's in the given CSS text against the provided\n * `ownerDocument`'s `baseURI`.\n *\n * @param {string} cssText CSS text to process\n * @param {string} baseURI Base URI to resolve the URL against\n * @return {string} Processed CSS text with resolved URL's\n */\nexport function resolveCss(cssText, baseURI) {\n  return cssText.replace(CSS_URL_RX, function(m, pre, url, post) {\n    return pre + '\\'' +\n      resolveUrl(url.replace(/[\"']/g, ''), baseURI) +\n      '\\'' + post;\n  });\n}\n\n/**\n * Returns a path from a given `url`. The path includes the trailing\n * `/` from the url.\n *\n * @param {string} url Input URL to transform\n * @return {string} resolved path\n */\nexport function pathFromUrl(url) {\n  return url.substring(0, url.lastIndexOf('/') + 1);\n}\n"
  },
  {
    "path": "lib/utils/scope-subtree.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n\nexport {scopeSubtree};\n\n\n/**\n * Ensure that elements in a ShadowDOM container are scoped correctly.\n * This function is only needed when ShadyDOM is used and unpatched DOM APIs are used in third party code.\n * This can happen in noPatch mode or when specialized APIs like ranges or tables are used to mutate DOM.\n *\n * @returns Returns a new MutationObserver on `container` if `shouldObserve` is true.\n */\ndeclare function scopeSubtree(container: Element, shouldObserve?: boolean): MutationObserver|null;\n"
  },
  {
    "path": "lib/utils/scope-subtree.js",
    "content": "/**\n@license\nCopyright (c) 2019 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\nimport './boot.js';\nimport {wrap} from './wrap.js';\n\nconst ShadyDOM = window.ShadyDOM;\nconst ShadyCSS = window.ShadyCSS;\n\n/**\n * Return true if node scope is correct.\n *\n * @param {!Element} node Node to check scope\n * @param {!Node} scope Scope reference\n * @return {boolean} True if node is in scope\n */\nfunction sameScope(node, scope) {\n  return wrap(node).getRootNode() === scope;\n}\n\n/**\n * Ensure that elements in a ShadowDOM container are scoped correctly.\n * This function is only needed when ShadyDOM is used and unpatched DOM APIs are used in third party code.\n * This can happen in noPatch mode or when specialized APIs like ranges or tables are used to mutate DOM.\n *\n * @param  {!Element} container Container element to scope\n * @param  {boolean=} shouldObserve if true, start a mutation observer for added nodes to the container\n * @return {?MutationObserver} Returns a new MutationObserver on `container` if `shouldObserve` is true.\n */\nexport function scopeSubtree(container, shouldObserve = false) {\n  // If using native ShadowDOM, abort\n  if (!ShadyDOM || !ShadyCSS) {\n    return null;\n  }\n  // ShadyCSS handles DOM mutations when ShadyDOM does not handle scoping itself\n  if (!ShadyDOM['handlesDynamicScoping']) {\n    return null;\n  }\n  const ScopingShim = ShadyCSS['ScopingShim'];\n  // if ScopingShim is not available, abort\n  if (!ScopingShim) {\n    return null;\n  }\n  // capture correct scope for container\n  const containerScope = ScopingShim['scopeForNode'](container);\n  const root = wrap(container).getRootNode();\n\n  const scopify = (node) => {\n    if (!sameScope(node, root)) {\n      return;\n    }\n    // NOTE: native qSA does not honor scoped DOM, but it is faster, and the same behavior as Polymer v1\n    const elements = Array.from(ShadyDOM['nativeMethods']['querySelectorAll'].call(node, '*'));\n    elements.push(node);\n    for (let i = 0; i < elements.length; i++) {\n      const el = elements[i];\n      if (!sameScope(el, root)) {\n        continue;\n      }\n      const currentScope = ScopingShim['currentScopeForNode'](el);\n      if (currentScope !== containerScope) {\n        if (currentScope !== '') {\n          ScopingShim['unscopeNode'](el, currentScope);\n        }\n        ScopingShim['scopeNode'](el, containerScope);\n      }\n    }\n  };\n\n  // scope everything in container\n  scopify(container);\n\n  if (shouldObserve) {\n    const mo = new MutationObserver((mxns) => {\n      for (let i = 0; i < mxns.length; i++) {\n        const mxn = mxns[i];\n        for (let j = 0; j < mxn.addedNodes.length; j++) {\n          const addedNode = mxn.addedNodes[j];\n          if (addedNode.nodeType === Node.ELEMENT_NODE) {\n            scopify(addedNode);\n          }\n        }\n      }\n    });\n    mo.observe(container, {childList: true, subtree: true});\n    return mo;\n  } else {\n    return null;\n  }\n}"
  },
  {
    "path": "lib/utils/settings.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n// tslint:disable:no-any describes the API as best we are able today\n\nimport {pathFromUrl} from './resolve-url.js';\n\nexport {setRootPath};\n\n\n/**\n * Sets the global rootPath property used by `ElementMixin` and\n * available via `rootPath`.\n */\ndeclare function setRootPath(path: string): void;\n\n\nexport type SanitizeDOMValueFunction =\n    (value: unknown, name: string, type: 'property'|'attribute',\n     node: Node|null|undefined) => unknown;\n\nexport {setSanitizeDOMValue};\n\n\n/**\n * Sets the global sanitizeDOMValue available via this module's exported\n * `sanitizeDOMValue` variable.\n */\ndeclare function setSanitizeDOMValue(newSanitizeDOMValue: SanitizeDOMValueFunction|undefined): void;\n\nexport {getSanitizeDOMValue};\n\n\n/**\n * Gets sanitizeDOMValue, for environments that don't well support `export let`.\n *\n * @returns sanitizeDOMValue\n */\ndeclare function getSanitizeDOMValue(): SanitizeDOMValueFunction|undefined;\n\nexport {setPassiveTouchGestures};\n\n\n/**\n * Sets `passiveTouchGestures` globally for all elements using Polymer Gestures.\n */\ndeclare function setPassiveTouchGestures(usePassive: boolean): void;\n\nexport {setStrictTemplatePolicy};\n\n\n/**\n * Sets `strictTemplatePolicy` globally for all elements\n */\ndeclare function setStrictTemplatePolicy(useStrictPolicy: boolean): void;\n\nexport {setAllowTemplateFromDomModule};\n\n\n/**\n * Sets `lookupTemplateFromDomModule` globally for all elements\n */\ndeclare function setAllowTemplateFromDomModule(allowDomModule: boolean): void;\n\nexport {setLegacyOptimizations};\n\n\n/**\n * Sets `legacyOptimizations` globally for all elements to enable optimizations\n * when only legacy based elements are used.\n */\ndeclare function setLegacyOptimizations(useLegacyOptimizations: boolean): void;\n\nexport {setLegacyWarnings};\n\n\n/**\n * Sets `legacyWarnings` globally for all elements to migration warnings.\n */\ndeclare function setLegacyWarnings(useLegacyWarnings: boolean): void;\n\nexport {setSyncInitialRender};\n\n\n/**\n * Sets `syncInitialRender` globally for all elements to enable synchronous\n * initial rendering.\n */\ndeclare function setSyncInitialRender(useSyncInitialRender: boolean): void;\n\nexport {setLegacyUndefined};\n\n\n/**\n * Sets `legacyUndefined` globally for all elements to enable legacy\n * multi-property behavior for undefined values.\n */\ndeclare function setLegacyUndefined(useLegacyUndefined: boolean): void;\n\nexport {setOrderedComputed};\n\n\n/**\n * Sets `orderedComputed` globally for all elements to enable ordered computed\n * property computation.\n */\ndeclare function setOrderedComputed(useOrderedComputed: boolean): void;\n\nexport {setCancelSyntheticClickEvents};\n\n\n/**\n * Sets `setCancelSyntheticEvents` globally for all elements to cancel synthetic click events.\n */\ndeclare function setCancelSyntheticClickEvents(useCancelSyntheticClickEvents: boolean): void;\n\nexport {setRemoveNestedTemplates};\n\n\n/**\n * Sets `removeNestedTemplates` globally, to eliminate nested templates\n * inside `dom-if` and `dom-repeat` as part of template parsing.\n */\ndeclare function setRemoveNestedTemplates(useRemoveNestedTemplates: boolean): void;\n\nexport {setFastDomIf};\n\n\n/**\n * Sets `fastDomIf` globally, to put `dom-if` in a performance-optimized mode.\n */\ndeclare function setFastDomIf(useFastDomIf: boolean): void;\n\nexport {setSuppressTemplateNotifications};\n\n\n/**\n * Sets `suppressTemplateNotifications` globally, to disable `dom-change` and\n * `rendered-item-count` events from `dom-if` and `dom-repeat`.\n */\ndeclare function setSuppressTemplateNotifications(suppress: boolean): void;\n\nexport {setLegacyNoObservedAttributes};\n\n\n/**\n * Sets `legacyNoObservedAttributes` globally, to disable `observedAttributes`.\n */\ndeclare function setLegacyNoObservedAttributes(noObservedAttributes: boolean): void;\n\nexport {setUseAdoptedStyleSheetsWithBuiltCSS};\n\n\n/**\n * Sets `useAdoptedStyleSheetsWithBuiltCSS` globally.\n */\ndeclare function setUseAdoptedStyleSheetsWithBuiltCSS(value: boolean): void;\n\nexport const useShadow: boolean;\nexport const useNativeCSSProperties: boolean;\nexport const useNativeCustomElements: boolean;\nexport const supportsAdoptingStyleSheets: boolean;\nexport let legacyOptimizations: boolean;\n"
  },
  {
    "path": "lib/utils/settings.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport './boot.js';\nimport { pathFromUrl } from './resolve-url.js';\nexport const useShadow = !(window.ShadyDOM) || !(window.ShadyDOM.inUse);\nexport const useNativeCSSProperties = Boolean(!window.ShadyCSS || window.ShadyCSS.nativeCss);\nexport const useNativeCustomElements = !(window.customElements.polyfillWrapFlushCallback);\nexport const supportsAdoptingStyleSheets = useShadow &&\n    ('adoptedStyleSheets' in Document.prototype) &&\n    ('replaceSync' in CSSStyleSheet.prototype) &&\n    // Since spec may change, feature detect exact API we need\n    (() => {\n      try {\n        const sheet = new CSSStyleSheet();\n        sheet.replaceSync('');\n        const host = document.createElement('div');\n        host.attachShadow({mode: 'open'});\n        host.shadowRoot.adoptedStyleSheets = [sheet];\n        return (host.shadowRoot.adoptedStyleSheets[0] === sheet);\n      } catch(e) {\n        return false;\n      }\n    })();\n\n/**\n * Globally settable property that is automatically assigned to\n * `ElementMixin` instances, useful for binding in templates to\n * make URL's relative to an application's root.  Defaults to the main\n * document URL, but can be overridden by users.  It may be useful to set\n * `rootPath` to provide a stable application mount path when\n * using client side routing.\n */\nexport let rootPath = window.Polymer && window.Polymer.rootPath ||\n  pathFromUrl(document.baseURI || window.location.href);\n\n/**\n * Sets the global rootPath property used by `ElementMixin` and\n * available via `rootPath`.\n *\n * @param {string} path The new root path\n * @return {void}\n */\nexport const setRootPath = function(path) {\n  rootPath = path;\n};\n\n/**\n * A global callback used to sanitize any value before inserting it into the DOM.\n * The callback signature is:\n *\n *  function sanitizeDOMValue(value, name, type, node) { ... }\n *\n * Where:\n *\n * `value` is the value to sanitize.\n * `name` is the name of an attribute or property (for example, href).\n * `type` indicates where the value is being inserted: one of property, attribute, or text.\n * `node` is the node where the value is being inserted.\n *\n * @type {(function(*,string,string,?Node):*)|undefined}\n */\nexport let sanitizeDOMValue =\n  window.Polymer && window.Polymer.sanitizeDOMValue || undefined;\n\n/**\n * Sets the global sanitizeDOMValue available via this module's exported\n * `sanitizeDOMValue` variable.\n *\n * @param {(function(*,string,string,?Node):*)|undefined} newSanitizeDOMValue the global sanitizeDOMValue callback\n * @return {void}\n */\nexport const setSanitizeDOMValue = function(newSanitizeDOMValue) {\n  sanitizeDOMValue = newSanitizeDOMValue;\n};\n\n/**\n * Gets sanitizeDOMValue, for environments that don't well support `export let`.\n *\n * @return {(function(*,string,string,?Node):*)|undefined} sanitizeDOMValue\n */\nexport const getSanitizeDOMValue = function() {\n  return sanitizeDOMValue;\n};\n\n/**\n * Globally settable property to make Polymer Gestures use passive TouchEvent listeners when recognizing gestures.\n * When set to `true`, gestures made from touch will not be able to prevent scrolling, allowing for smoother\n * scrolling performance.\n * Defaults to `false` for backwards compatibility.\n */\nexport let passiveTouchGestures =\n  window.Polymer && window.Polymer.setPassiveTouchGestures || false;\n\n/**\n * Sets `passiveTouchGestures` globally for all elements using Polymer Gestures.\n *\n * @param {boolean} usePassive enable or disable passive touch gestures globally\n * @return {void}\n */\nexport const setPassiveTouchGestures = function(usePassive) {\n  passiveTouchGestures = usePassive;\n};\n\n/**\n * Setting to ensure Polymer template evaluation only occurs based on tempates\n * defined in trusted script.  When true, `<dom-module>` re-registration is\n * disallowed, `<dom-bind>` is disabled, and `<dom-if>`/`<dom-repeat>`\n * templates will only evaluate in the context of a trusted element template.\n */\nexport let strictTemplatePolicy =\n  window.Polymer && window.Polymer.strictTemplatePolicy || false;\n\n/**\n * Sets `strictTemplatePolicy` globally for all elements\n *\n * @param {boolean} useStrictPolicy enable or disable strict template policy\n *   globally\n * @return {void}\n */\nexport const setStrictTemplatePolicy = function(useStrictPolicy) {\n  strictTemplatePolicy = useStrictPolicy;\n};\n\n/**\n * Setting to enable dom-module lookup from Polymer.Element.  By default,\n * templates must be defined in script using the `static get template()`\n * getter and the `html` tag function.  To enable legacy loading of templates\n * via dom-module, set this flag to true.\n */\nexport let allowTemplateFromDomModule =\n  window.Polymer && window.Polymer.allowTemplateFromDomModule || false;\n\n/**\n * Sets `lookupTemplateFromDomModule` globally for all elements\n *\n * @param {boolean} allowDomModule enable or disable template lookup\n *   globally\n * @return {void}\n */\nexport const setAllowTemplateFromDomModule = function(allowDomModule) {\n  allowTemplateFromDomModule = allowDomModule;\n};\n\n/**\n * Setting to skip processing style includes and re-writing urls in css styles.\n * Normally \"included\" styles are pulled into the element and all urls in styles\n * are re-written to be relative to the containing script url.\n * If no includes or relative urls are used in styles, these steps can be\n * skipped as an optimization.\n */\nexport let legacyOptimizations =\n  window.Polymer && window.Polymer.legacyOptimizations || false;\n\n/**\n * Sets `legacyOptimizations` globally for all elements to enable optimizations\n * when only legacy based elements are used.\n *\n * @param {boolean} useLegacyOptimizations enable or disable legacy optimizations\n * includes and url rewriting\n * @return {void}\n */\nexport const setLegacyOptimizations = function(useLegacyOptimizations) {\n  legacyOptimizations = useLegacyOptimizations;\n};\n\n/**\n * Setting to add warnings useful when migrating from Polymer 1.x to 2.x.\n */\nexport let legacyWarnings =\n  window.Polymer && window.Polymer.legacyWarnings || false;\n\n/**\n * Sets `legacyWarnings` globally for all elements to migration warnings.\n *\n * @param {boolean} useLegacyWarnings enable or disable warnings\n * @return {void}\n */\nexport const setLegacyWarnings = function(useLegacyWarnings) {\n  legacyWarnings = useLegacyWarnings;\n};\n\n/**\n * Setting to perform initial rendering synchronously when running under ShadyDOM.\n * This matches the behavior of Polymer 1.\n */\nexport let syncInitialRender =\n  window.Polymer && window.Polymer.syncInitialRender || false;\n\n/**\n * Sets `syncInitialRender` globally for all elements to enable synchronous\n * initial rendering.\n *\n * @param {boolean} useSyncInitialRender enable or disable synchronous initial\n * rendering globally.\n * @return {void}\n */\nexport const setSyncInitialRender = function(useSyncInitialRender) {\n  syncInitialRender = useSyncInitialRender;\n};\n\n/**\n * Setting to retain the legacy Polymer 1 behavior for multi-property\n * observers around undefined values. Observers and computed property methods\n * are not called until no argument is undefined.\n */\nexport let legacyUndefined =\n  window.Polymer && window.Polymer.legacyUndefined || false;\n\n/**\n * Sets `legacyUndefined` globally for all elements to enable legacy\n * multi-property behavior for undefined values.\n *\n * @param {boolean} useLegacyUndefined enable or disable legacy\n * multi-property behavior for undefined.\n * @return {void}\n */\nexport const setLegacyUndefined = function(useLegacyUndefined) {\n  legacyUndefined = useLegacyUndefined;\n};\n\n/**\n * Setting to ensure computed properties are computed in order to ensure\n * re-computation never occurs in a given turn.\n */\nexport let orderedComputed =\n  window.Polymer && window.Polymer.orderedComputed || false;\n\n/**\n * Sets `orderedComputed` globally for all elements to enable ordered computed\n * property computation.\n *\n * @param {boolean} useOrderedComputed enable or disable ordered computed effects\n * @return {void}\n */\nexport const setOrderedComputed = function(useOrderedComputed) {\n  orderedComputed = useOrderedComputed;\n};\n\n/**\n * Setting to cancel synthetic click events fired by older mobile browsers. Modern browsers\n * no longer fire synthetic click events, and the cancellation behavior can interfere\n * when programmatically clicking on elements.\n */\nexport let cancelSyntheticClickEvents = true;\n\n/**\n * Sets `setCancelSyntheticEvents` globally for all elements to cancel synthetic click events.\n *\n * @param {boolean} useCancelSyntheticClickEvents enable or disable cancelling synthetic\n * events\n * @return {void}\n */\nexport const setCancelSyntheticClickEvents = function(useCancelSyntheticClickEvents) {\n  cancelSyntheticClickEvents = useCancelSyntheticClickEvents;\n};\n\n/**\n * Setting to remove nested templates inside `dom-if` and `dom-repeat` as\n * part of element template parsing.  This is a performance optimization that\n * eliminates most of the tax of needing two elements due to the loss of\n * type-extended templates as a result of the V1 specification changes.\n */\nexport let removeNestedTemplates =\n  window.Polymer && window.Polymer.removeNestedTemplates || false;\n\n/**\n * Sets `removeNestedTemplates` globally, to eliminate nested templates\n * inside `dom-if` and `dom-repeat` as part of template parsing.\n *\n * @param {boolean} useRemoveNestedTemplates enable or disable removing nested\n *   templates during parsing\n * @return {void}\n */\nexport const setRemoveNestedTemplates = function(useRemoveNestedTemplates) {\n  removeNestedTemplates = useRemoveNestedTemplates;\n};\n\n/**\n * Setting to place `dom-if` elements in a performance-optimized mode that takes\n * advantage of lighter-weight host runtime template stamping to eliminate the\n * need for an intermediate Templatizer `TemplateInstance` to mange the nodes\n * stamped by `dom-if`.  Under this setting, any Templatizer-provided API's\n * such as `modelForElement` will not be available for nodes stamped by\n * `dom-if`.\n */\nexport let fastDomIf = window.Polymer && window.Polymer.fastDomIf || false;\n\n/**\n * Sets `fastDomIf` globally, to put `dom-if` in a performance-optimized mode.\n *\n * @param {boolean} useFastDomIf enable or disable `dom-if` fast-mode\n * @return {void}\n */\nexport const setFastDomIf = function(useFastDomIf) {\n  fastDomIf = useFastDomIf;\n};\n\n/**\n * Setting to disable `dom-change` and `rendered-item-count` events from\n * `dom-if` and `dom-repeat`. Users can opt back into `dom-change` events by\n * setting the `notify-dom-change` attribute (`notifyDomChange: true` property)\n * to `dom-if`/`don-repeat` instances.\n */\nexport let suppressTemplateNotifications =\n  window.Polymer && window.Polymer.suppressTemplateNotifications || false;\n\n/**\n * Sets `suppressTemplateNotifications` globally, to disable `dom-change` and\n * `rendered-item-count` events from `dom-if` and `dom-repeat`.\n *\n * @param {boolean} suppress enable or disable `suppressTemplateNotifications`\n * @return {void}\n */\nexport const setSuppressTemplateNotifications = function(suppress) {\n  suppressTemplateNotifications = suppress;\n};\n\n/**\n * Setting to disable use of dynamic attributes. This is an optimization\n * to avoid setting `observedAttributes`. Instead attributes are read\n * once at create time and set/removeAttribute are patched.\n */\nexport let legacyNoObservedAttributes =\n  window.Polymer && window.Polymer.legacyNoObservedAttributes || false;\n\n/**\n * Sets `legacyNoObservedAttributes` globally, to disable `observedAttributes`.\n *\n * @param {boolean} noObservedAttributes enable or disable `legacyNoObservedAttributes`\n * @return {void}\n */\nexport const setLegacyNoObservedAttributes = function(noObservedAttributes) {\n  legacyNoObservedAttributes = noObservedAttributes;\n};\n\n/**\n * Setting to enable use of `adoptedStyleSheets` for sharing style sheets\n * between component instances' shadow roots, if the app uses built Shady CSS\n * styles.\n */\nexport let useAdoptedStyleSheetsWithBuiltCSS =\n  window.Polymer && window.Polymer.useAdoptedStyleSheetsWithBuiltCSS || false;\n\n/**\n * Sets `useAdoptedStyleSheetsWithBuiltCSS` globally.\n *\n * @param {boolean} value enable or disable `useAdoptedStyleSheetsWithBuiltCSS`\n * @return {void}\n */\nexport const setUseAdoptedStyleSheetsWithBuiltCSS = function(value) {\n  useAdoptedStyleSheetsWithBuiltCSS = value;\n};\n"
  },
  {
    "path": "lib/utils/style-gather.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n\nimport {DomModule} from '../elements/dom-module.js';\n\nimport {resolveCss} from './resolve-url.js';\n\nexport {stylesFromModules};\n\n\n/**\n * Returns a list of <style> elements in a space-separated list of `dom-module`s.\n *\n * @returns Array of contained <style> elements\n */\ndeclare function stylesFromModules(moduleIds: string): HTMLStyleElement[];\n\nexport {stylesFromModule};\n\n\n/**\n * Returns a list of <style> elements in a given `dom-module`.\n * Styles in a `dom-module` can come either from `<style>`s within the\n * first `<template>`, or else from one or more\n * `<link rel=\"import\" type=\"css\">` links outside the template.\n *\n * @returns Array of contained styles.\n */\ndeclare function stylesFromModule(moduleId: string): HTMLStyleElement[];\n\nexport {stylesFromTemplate};\n\n\n/**\n * Returns the `<style>` elements within a given template.\n *\n * @returns Array of styles\n */\ndeclare function stylesFromTemplate(template: HTMLTemplateElement, baseURI?: string): HTMLStyleElement[];\n\nexport {stylesFromModuleImports};\n\n\n/**\n * Returns a list of <style> elements  from stylesheets loaded via `<link rel=\"import\" type=\"css\">` links within the specified `dom-module`.\n *\n * @returns Array of contained styles.\n */\ndeclare function stylesFromModuleImports(moduleId: string): HTMLStyleElement[];\n\nexport {cssFromModules};\n\n\n/**\n * Returns CSS text of styles in a space-separated list of `dom-module`s.\n * Note: This method is deprecated, use `stylesFromModules` instead.\n *\n * @returns Concatenated CSS content from specified `dom-module`s\n */\ndeclare function cssFromModules(moduleIds: string): string;\n\nexport {cssFromModule};\n\n\n/**\n * Returns CSS text of styles in a given `dom-module`.  CSS in a `dom-module`\n * can come either from `<style>`s within the first `<template>`, or else\n * from one or more `<link rel=\"import\" type=\"css\">` links outside the\n * template.\n *\n * Any `<styles>` processed are removed from their original location.\n * Note: This method is deprecated, use `styleFromModule` instead.\n *\n * @returns Concatenated CSS content from specified `dom-module`\n */\ndeclare function cssFromModule(moduleId: string): string;\n\nexport {cssFromTemplate};\n\n\n/**\n * Returns CSS text of `<styles>` within a given template.\n *\n * Any `<styles>` processed are removed from their original location.\n * Note: This method is deprecated, use `styleFromTemplate` instead.\n *\n * @returns Concatenated CSS content from specified template\n */\ndeclare function cssFromTemplate(template: HTMLTemplateElement, baseURI: string): string;\n\nexport {cssFromModuleImports};\n\n\n/**\n * Returns CSS text from stylesheets loaded via `<link rel=\"import\" type=\"css\">`\n * links within the specified `dom-module`.\n *\n * Note: This method is deprecated, use `stylesFromModuleImports` instead.\n *\n * @returns Concatenated CSS content from links in specified `dom-module`\n */\ndeclare function cssFromModuleImports(moduleId: string): string;\n"
  },
  {
    "path": "lib/utils/style-gather.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n/**\n * Module with utilities for collection CSS text from `<templates>`, external\n * stylesheets, and `dom-module`s.\n *\n * @summary Module with utilities for collection CSS text from various sources.\n */\n\nimport { DomModule } from '../elements/dom-module.js';\nimport { resolveCss } from './resolve-url.js';\n\nconst MODULE_STYLE_LINK_SELECTOR = 'link[rel=import][type~=css]';\nconst INCLUDE_ATTR = 'include';\nconst SHADY_UNSCOPED_ATTR = 'shady-unscoped';\n\n/**\n * @param {string} moduleId .\n * @return {?DomModule} .\n */\nfunction importModule(moduleId) {\n  return /** @type {?DomModule} */(DomModule.import(moduleId));\n}\n\nfunction styleForImport(importDoc) {\n  // NOTE: polyfill affordance.\n  // under the HTMLImports polyfill, there will be no 'body',\n  // but the import pseudo-doc can be used directly.\n  let container = importDoc.body ? importDoc.body : importDoc;\n  const importCss = resolveCss(container.textContent,\n    importDoc.baseURI);\n  const style = document.createElement('style');\n  style.textContent = importCss;\n  return style;\n}\n\n/** @typedef {{assetpath: string}} */\nlet templateWithAssetPath; // eslint-disable-line no-unused-vars\n\n\n/**\n * Returns a list of <style> elements in a space-separated list of `dom-module`s.\n *\n * @function\n * @param {string} moduleIds List of dom-module id's within which to\n * search for css.\n * @return {!Array<!HTMLStyleElement>} Array of contained <style> elements\n */\nexport function stylesFromModules(moduleIds) {\n const modules = moduleIds.trim().split(/\\s+/);\n const styles = [];\n for (let i=0; i < modules.length; i++) {\n   styles.push(...stylesFromModule(modules[i]));\n }\n return styles;\n}\n\n/**\n * Returns a list of <style> elements in a given `dom-module`.\n * Styles in a `dom-module` can come either from `<style>`s within the\n * first `<template>`, or else from one or more\n * `<link rel=\"import\" type=\"css\">` links outside the template.\n *\n * @param {string} moduleId dom-module id to gather styles from\n * @return {!Array<!HTMLStyleElement>} Array of contained styles.\n */\nexport function stylesFromModule(moduleId) {\n  const m = importModule(moduleId);\n\n  if (!m) {\n    console.warn('Could not find style data in module named', moduleId);\n    return [];\n  }\n\n  if (m._styles === undefined) {\n    const styles = [];\n    // module imports: <link rel=\"import\" type=\"css\">\n    styles.push(..._stylesFromModuleImports(m));\n    // include css from the first template in the module\n    const template = /** @type {?HTMLTemplateElement} */(\n        m.querySelector('template'));\n    if (template) {\n      styles.push(...stylesFromTemplate(template,\n        /** @type {templateWithAssetPath} */(m).assetpath));\n    }\n\n    m._styles = styles;\n  }\n\n  return m._styles;\n}\n\n/**\n * Returns the `<style>` elements within a given template.\n *\n * @param {!HTMLTemplateElement} template Template to gather styles from\n * @param {string=} baseURI baseURI for style content\n * @return {!Array<!HTMLStyleElement>} Array of styles\n */\nexport function stylesFromTemplate(template, baseURI) {\n  if (!template._styles) {\n    const styles = [];\n    // if element is a template, get content from its .content\n    const e$ = template.content.querySelectorAll('style');\n    for (let i=0; i < e$.length; i++) {\n      let e = e$[i];\n      // support style sharing by allowing styles to \"include\"\n      // other dom-modules that contain styling\n      let include = e.getAttribute(INCLUDE_ATTR);\n      if (include) {\n        styles.push(...stylesFromModules(include).filter(function(item, index, self) {\n          return self.indexOf(item) === index;\n        }));\n      }\n      if (baseURI) {\n        e.textContent =\n            resolveCss(e.textContent, /** @type {string} */ (baseURI));\n      }\n      styles.push(e);\n    }\n    template._styles = styles;\n  }\n  return template._styles;\n}\n\n/**\n * Returns a list of <style> elements  from stylesheets loaded via `<link rel=\"import\" type=\"css\">` links within the specified `dom-module`.\n *\n * @param {string} moduleId Id of `dom-module` to gather CSS from\n * @return {!Array<!HTMLStyleElement>} Array of contained styles.\n */\nexport function stylesFromModuleImports(moduleId) {\n let m = importModule(moduleId);\n return m ? _stylesFromModuleImports(m) : [];\n}\n\n/**\n * @param {!HTMLElement} module dom-module element that could contain `<link rel=\"import\" type=\"css\">` styles\n * @return {!Array<!HTMLStyleElement>} Array of contained styles\n */\nfunction _stylesFromModuleImports(module) {\n  const styles = [];\n  const p$ = module.querySelectorAll(MODULE_STYLE_LINK_SELECTOR);\n  for (let i=0; i < p$.length; i++) {\n    let p = p$[i];\n    if (p.import) {\n      const importDoc = p.import;\n      const unscoped = p.hasAttribute(SHADY_UNSCOPED_ATTR);\n      if (unscoped && !importDoc._unscopedStyle) {\n        const style = styleForImport(importDoc);\n        style.setAttribute(SHADY_UNSCOPED_ATTR, '');\n        importDoc._unscopedStyle = style;\n      } else if (!importDoc._style) {\n        importDoc._style = styleForImport(importDoc);\n      }\n      styles.push(unscoped ? importDoc._unscopedStyle : importDoc._style);\n    }\n  }\n  return styles;\n}\n\n/**\n *\n * Returns CSS text of styles in a space-separated list of `dom-module`s.\n * Note: This method is deprecated, use `stylesFromModules` instead.\n *\n * @deprecated\n * @param {string} moduleIds List of dom-module id's within which to\n * search for css.\n * @return {string} Concatenated CSS content from specified `dom-module`s\n */\nexport function cssFromModules(moduleIds) {\n let modules = moduleIds.trim().split(/\\s+/);\n let cssText = '';\n for (let i=0; i < modules.length; i++) {\n   cssText += cssFromModule(modules[i]);\n }\n return cssText;\n}\n\n/**\n * Returns CSS text of styles in a given `dom-module`.  CSS in a `dom-module`\n * can come either from `<style>`s within the first `<template>`, or else\n * from one or more `<link rel=\"import\" type=\"css\">` links outside the\n * template.\n *\n * Any `<styles>` processed are removed from their original location.\n * Note: This method is deprecated, use `styleFromModule` instead.\n *\n * @deprecated\n * @param {string} moduleId dom-module id to gather styles from\n * @return {string} Concatenated CSS content from specified `dom-module`\n */\nexport function cssFromModule(moduleId) {\n  let m = importModule(moduleId);\n  if (m && m._cssText === undefined) {\n    // module imports: <link rel=\"import\" type=\"css\">\n    let cssText = _cssFromModuleImports(m);\n    // include css from the first template in the module\n    let t = /** @type {?HTMLTemplateElement} */(m.querySelector('template'));\n    if (t) {\n      cssText += cssFromTemplate(t,\n        /** @type {templateWithAssetPath} */(m).assetpath);\n    }\n    m._cssText = cssText || null;\n  }\n  if (!m) {\n    console.warn('Could not find style data in module named', moduleId);\n  }\n  return m && m._cssText || '';\n}\n\n/**\n * Returns CSS text of `<styles>` within a given template.\n *\n * Any `<styles>` processed are removed from their original location.\n * Note: This method is deprecated, use `styleFromTemplate` instead.\n *\n * @deprecated\n * @param {!HTMLTemplateElement} template Template to gather styles from\n * @param {string} baseURI Base URI to resolve the URL against\n * @return {string} Concatenated CSS content from specified template\n */\nexport function cssFromTemplate(template, baseURI) {\n  let cssText = '';\n  const e$ = stylesFromTemplate(template, baseURI);\n  // if element is a template, get content from its .content\n  for (let i=0; i < e$.length; i++) {\n    let e = e$[i];\n    if (e.parentNode) {\n      e.parentNode.removeChild(e);\n    }\n    cssText += e.textContent;\n  }\n  return cssText;\n}\n\n/**\n * Returns CSS text from stylesheets loaded via `<link rel=\"import\" type=\"css\">`\n * links within the specified `dom-module`.\n *\n * Note: This method is deprecated, use `stylesFromModuleImports` instead.\n *\n * @deprecated\n *\n * @param {string} moduleId Id of `dom-module` to gather CSS from\n * @return {string} Concatenated CSS content from links in specified `dom-module`\n */\nexport function cssFromModuleImports(moduleId) {\n  let m = importModule(moduleId);\n  return m ? _cssFromModuleImports(m) : '';\n}\n\n/**\n * @deprecated\n * @param {!HTMLElement} module dom-module element that could contain `<link rel=\"import\" type=\"css\">` styles\n * @return {string} Concatenated CSS content from links in the dom-module\n */\nfunction _cssFromModuleImports(module) {\n  let cssText = '';\n  let styles = _stylesFromModuleImports(module);\n  for (let i=0; i < styles.length; i++) {\n    cssText += styles[i].textContent;\n  }\n  return cssText;\n}\n"
  },
  {
    "path": "lib/utils/telemetry.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n\nimport {PolymerElementConstructor} from '../../interfaces';\n\nexport {PolymerElementConstructor} from '../../interfaces';\n\n/** Array of Polymer element classes that have been finalized. */\nexport const registrations: PolymerElementConstructor[];\n\nexport {incrementInstanceCount};\n\ndeclare function incrementInstanceCount(): void;\n\nexport {register};\n\n\n/**\n * Registers a class prototype for telemetry purposes.\n */\ndeclare function register(prototype: PolymerElementConstructor): void;\n\nexport {dumpRegistrations};\n\n\n/**\n * Logs all elements registered with an `is` to the console.\n */\ndeclare function dumpRegistrations(): void;\n"
  },
  {
    "path": "lib/utils/telemetry.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n/**\n * Total number of Polymer element instances created.\n * @type {number}\n */\nexport let instanceCount = 0;\n\nexport function incrementInstanceCount() {\n  instanceCount++;\n}\n\n/**\n * Array of Polymer element classes that have been finalized.\n * @type {!Array<!PolymerElementConstructor>}\n */\nexport const registrations = [];\n\n/**\n * @param {!PolymerElementConstructor} prototype Element prototype to log\n * @private\n */\nfunction _regLog(prototype) {\n  console.log('[' + /** @type {?} */(prototype).is + ']: registered');\n}\n\n/**\n * Registers a class prototype for telemetry purposes.\n * @param {!PolymerElementConstructor} prototype Element prototype to register\n * @protected\n */\nexport function register(prototype) {\n  registrations.push(prototype);\n}\n\n/**\n * Logs all elements registered with an `is` to the console.\n * @public\n */\nexport function dumpRegistrations() {\n  registrations.forEach(_regLog);\n}"
  },
  {
    "path": "lib/utils/templatize.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n// tslint:disable:no-any describes the API as best we are able today\n\nimport {PropertyEffects} from '../mixins/property-effects.js';\n\nimport {MutableData} from '../mixins/mutable-data.js';\n\nexport {showHideChildren};\n\ndeclare function showHideChildren(): void;\n\ndeclare class TemplateInstanceBase extends\n  PropertyEffects(\n  HTMLElement) {\n  root: StampedTemplate;\n  children: any;\n\n  /**\n   * Find the parent model of this template instance.  The parent model\n   * is either another templatize instance that had option `parentModel: true`,\n   * or else the host element.\n   */\n  readonly parentModel: PropertyEffects;\n  _methodHost: PropertyEffects;\n\n  /**\n   * Override point for adding custom or simulated event handling.\n   *\n   * @param node Node to add event listener to\n   * @param eventName Name of event\n   * @param handler Listener function to add\n   */\n  _addEventListenerToNode(node: Node, eventName: string, handler: (p0: Event) => void): void;\n\n  /**\n   * Overrides default property-effects implementation to intercept\n   * textContent bindings while children are \"hidden\" and cache in\n   * private storage for later retrieval.\n   *\n   * @param node The node to set a property on\n   * @param prop The property to set\n   * @param value The value to set\n   */\n  _setUnmanagedPropertyToNode(node: Node, prop: string, value: any): void;\n\n  /**\n   * Forwards a host property to this instance.  This method should be\n   * called on instances from the `options.forwardHostProp` callback\n   * to propagate changes of host properties to each instance.\n   *\n   * Note this method enqueues the change, which are flushed as a batch.\n   *\n   * @param prop Property or path name\n   * @param value Value of the property to forward\n   */\n  forwardHostProp(prop: string, value: any): void;\n\n  /**\n   * Shows or hides the template instance top level child elements. For\n   * text nodes, `textContent` is removed while \"hidden\" and replaced when\n   * \"shown.\"\n   *\n   * @param hide Set to true to hide the children;\n   * set to false to show them.\n   */\n  _showHideChildren(hide: boolean): void;\n\n  /**\n   * Stub of HTMLElement's `dispatchEvent`, so that effects that may\n   * dispatch events safely no-op.\n   *\n   * @param event Event to dispatch\n   * @returns Always true.\n   */\n  dispatchEvent(event: Event|null): boolean;\n}\n\ndeclare class templatizerBase extends TemplateInstanceBase {\n}\n\nexport {templatize};\n\n\n/**\n * Returns an anonymous `PropertyEffects` class bound to the\n * `<template>` provided.  Instancing the class will result in the\n * template being stamped into a document fragment stored as the instance's\n * `root` property, after which it can be appended to the DOM.\n *\n * Templates may utilize all Polymer data-binding features as well as\n * declarative event listeners.  Event listeners and inline computing\n * functions in the template will be called on the host of the template.\n *\n * The constructor returned takes a single argument dictionary of initial\n * property values to propagate into template bindings.  Additionally\n * host properties can be forwarded in, and instance properties can be\n * notified out by providing optional callbacks in the `options` dictionary.\n *\n * Valid configuration in `options` are as follows:\n *\n * - `forwardHostProp(property, value)`: Called when a property referenced\n *   in the template changed on the template's host. As this library does\n *   not retain references to templates instanced by the user, it is the\n *   templatize owner's responsibility to forward host property changes into\n *   user-stamped instances.  The `instance.forwardHostProp(property, value)`\n *    method on the generated class should be called to forward host\n *   properties into the template to prevent unnecessary property-changed\n *   notifications. Any properties referenced in the template that are not\n *   defined in `instanceProps` will be notified up to the template's host\n *   automatically.\n * - `instanceProps`: Dictionary of property names that will be added\n *   to the instance by the templatize owner.  These properties shadow any\n *   host properties, and changes within the template to these properties\n *   will result in `notifyInstanceProp` being called.\n * - `mutableData`: When `true`, the generated class will skip strict\n *   dirty-checking for objects and arrays (always consider them to be\n *   \"dirty\").\n * - `notifyInstanceProp(instance, property, value)`: Called when\n *   an instance property changes.  Users may choose to call `notifyPath`\n *   on e.g. the owner to notify the change.\n * - `parentModel`: When `true`, events handled by declarative event listeners\n *   (`on-event=\"handler\"`) will be decorated with a `model` property pointing\n *   to the template instance that stamped it.  It will also be returned\n *   from `instance.parentModel` in cases where template instance nesting\n *   causes an inner model to shadow an outer model.\n *\n * All callbacks are called bound to the `owner`. Any context\n * needed for the callbacks (such as references to `instances` stamped)\n * should be stored on the `owner` such that they can be retrieved via\n * `this`.\n *\n * When `options.forwardHostProp` is declared as an option, any properties\n * referenced in the template will be automatically forwarded from the host of\n * the `<template>` to instances, with the exception of any properties listed in\n * the `options.instanceProps` object.  `instanceProps` are assumed to be\n * managed by the owner of the instances, either passed into the constructor\n * or set after the fact.  Note, any properties passed into the constructor will\n * always be set to the instance (regardless of whether they would normally\n * be forwarded from the host).\n *\n * Note that `templatize()` can be run only once for a given `<template>`.\n * Further calls will result in an error. Also, there is a special\n * behavior if the template was duplicated through a mechanism such as\n * `<dom-repeat>` or `<test-fixture>`. In this case, all calls to\n * `templatize()` return the same class for all duplicates of a template.\n * The class returned from `templatize()` is generated only once using\n * the `options` from the first call. This means that any `options`\n * provided to subsequent calls will be ignored. Therefore, it is very\n * important not to close over any variables inside the callbacks. Also,\n * arrow functions must be avoided because they bind the outer `this`.\n * Inside the callbacks, any contextual information can be accessed\n * through `this`, which points to the `owner`.\n *\n * @returns Generated class bound\n *   to the template provided\n */\ndeclare function templatize(template: HTMLTemplateElement, owner?: PropertyEffects|null, options?: object|null): {new(p0?: object|null): TemplateInstanceBase};\n\ndeclare class baseClass extends TemplateInstanceBase {\n}\n\nexport {modelForElement};\n\n\n/**\n * Returns the template \"model\" associated with a given element, which\n * serves as the binding scope for the template instance the element is\n * contained in. A template model is an instance of\n * `TemplateInstanceBase`, and should be used to manipulate data\n * associated with this template instance.\n *\n * Example:\n *\n *   let model = modelForElement(el);\n *   if (model.index < 10) {\n *     model.set('item.checked', true);\n *   }\n *\n * @returns Template instance representing the\n *   binding scope for the element\n */\ndeclare function modelForElement(template: HTMLElement|null, node?: Node|null): TemplateInstanceBase|null;\n\nexport {TemplateInstanceBase};\n\nimport {StampedTemplate} from '../../interfaces';\n"
  },
  {
    "path": "lib/utils/templatize.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n/**\n * Module for preparing and stamping instances of templates that utilize\n * Polymer's data-binding and declarative event listener features.\n *\n * Example:\n *\n *     // Get a template from somewhere, e.g. light DOM\n *     let template = this.querySelector('template');\n *     // Prepare the template\n *     let TemplateClass = Templatize.templatize(template);\n *     // Instance the template with an initial data model\n *     let instance = new TemplateClass({myProp: 'initial'});\n *     // Insert the instance's DOM somewhere, e.g. element's shadow DOM\n *     this.shadowRoot.appendChild(instance.root);\n *     // Changing a property on the instance will propagate to bindings\n *     // in the template\n *     instance.myProp = 'new value';\n *\n * The `options` dictionary passed to `templatize` allows for customizing\n * features of the generated template class, including how outer-scope host\n * properties should be forwarded into template instances, how any instance\n * properties added into the template's scope should be notified out to\n * the host, and whether the instance should be decorated as a \"parent model\"\n * of any event handlers.\n *\n *     // Customize property forwarding and event model decoration\n *     let TemplateClass = Templatize.templatize(template, this, {\n *       parentModel: true,\n *       forwardHostProp(property, value) {...},\n *       instanceProps: {...},\n *       notifyInstanceProp(instance, property, value) {...},\n *     });\n *\n * @summary Module for preparing and stamping instances of templates\n *   utilizing Polymer templating features.\n */\n\nimport './boot.js';\n\nimport { PropertyEffects } from '../mixins/property-effects.js';\nimport { MutableData } from '../mixins/mutable-data.js';\nimport { strictTemplatePolicy, legacyWarnings } from './settings.js';\nimport { wrap } from './wrap.js';\n\n// Base class for HTMLTemplateElement extension that has property effects\n// machinery for propagating host properties to children. This is an ES5\n// class only because Babel (incorrectly) requires super() in the class\n// constructor even though no `this` is used and it returns an instance.\nlet newInstance = null;\n\n/**\n * @constructor\n * @extends {HTMLTemplateElement}\n * @private\n */\nfunction HTMLTemplateElementExtension() { return newInstance; }\nHTMLTemplateElementExtension.prototype = Object.create(HTMLTemplateElement.prototype, {\n  constructor: {\n    value: HTMLTemplateElementExtension,\n    writable: true\n  }\n});\n\n/**\n * @constructor\n * @implements {Polymer_PropertyEffects}\n * @extends {HTMLTemplateElementExtension}\n * @private\n */\nconst DataTemplate = PropertyEffects(HTMLTemplateElementExtension);\n\n/**\n * @constructor\n * @implements {Polymer_MutableData}\n * @extends {DataTemplate}\n * @private\n */\nconst MutableDataTemplate = MutableData(DataTemplate);\n\n// Applies a DataTemplate subclass to a <template> instance\nfunction upgradeTemplate(template, constructor) {\n  newInstance = template;\n  Object.setPrototypeOf(template, constructor.prototype);\n  new constructor();\n  newInstance = null;\n}\n\n/**\n * Base class for TemplateInstance.\n * @constructor\n * @extends {HTMLElement}\n * @implements {Polymer_PropertyEffects}\n * @private\n */\nconst templateInstanceBase = PropertyEffects(class {});\n\nexport function showHideChildren(hide, children) {\n  for (let i=0; i<children.length; i++) {\n    let n = children[i];\n    // Ignore non-changes\n    if (Boolean(hide) != Boolean(n.__hideTemplateChildren__)) {\n      // clear and restore text\n      if (n.nodeType === Node.TEXT_NODE) {\n        if (hide) {\n          n.__polymerTextContent__ = n.textContent;\n          n.textContent = '';\n        } else {\n          n.textContent = n.__polymerTextContent__;\n        }\n      // remove and replace slot\n      } else if (n.localName === 'slot') {\n        if (hide) {\n          n.__polymerReplaced__ = document.createComment('hidden-slot');\n          wrap(wrap(n).parentNode).replaceChild(n.__polymerReplaced__, n);\n        } else {\n          const replace = n.__polymerReplaced__;\n          if (replace) {\n            wrap(wrap(replace).parentNode).replaceChild(n, replace);\n          }\n        }\n      }\n      // hide and show nodes\n      else if (n.style) {\n        if (hide) {\n          n.__polymerDisplay__ = n.style.display;\n          n.style.display = 'none';\n        } else {\n          n.style.display = n.__polymerDisplay__;\n        }\n      }\n    }\n    n.__hideTemplateChildren__ = hide;\n    if (n._showHideChildren) {\n      n._showHideChildren(hide);\n    }\n  }\n}\n\n/**\n * @polymer\n * @customElement\n * @appliesMixin PropertyEffects\n * @unrestricted\n */\nclass TemplateInstanceBase extends templateInstanceBase {\n  constructor(props) {\n    super();\n    this._configureProperties(props);\n    /** @type {!StampedTemplate} */\n    this.root = this._stampTemplate(this.__dataHost);\n    // Save list of stamped children\n    let children = [];\n    /** @suppress {invalidCasts} */\n    this.children = /** @type {!NodeList} */ (children);\n    // Polymer 1.x did not use `Polymer.dom` here so not bothering.\n    for (let n = this.root.firstChild; n; n=n.nextSibling) {\n      children.push(n);\n      n.__templatizeInstance = this;\n    }\n    if (this.__templatizeOwner &&\n      this.__templatizeOwner.__hideTemplateChildren__) {\n      this._showHideChildren(true);\n    }\n    // Flush props only when props are passed if instance props exist\n    // or when there isn't instance props.\n    let options = this.__templatizeOptions;\n    if ((props && options.instanceProps) || !options.instanceProps) {\n      this._enableProperties();\n    }\n  }\n  /**\n   * Configure the given `props` by calling `_setPendingProperty`. Also\n   * sets any properties stored in `__hostProps`.\n   * @private\n   * @param {Object} props Object of property name-value pairs to set.\n   * @return {void}\n   */\n  _configureProperties(props) {\n    let options = this.__templatizeOptions;\n    if (options.forwardHostProp) {\n      for (let hprop in this.__hostProps) {\n        this._setPendingProperty(hprop, this.__dataHost['_host_' + hprop]);\n      }\n    }\n    // Any instance props passed in the constructor will overwrite host props;\n    // normally this would be a user error but we don't specifically filter them\n    for (let iprop in props) {\n      this._setPendingProperty(iprop, props[iprop]);\n    }\n  }\n  /**\n   * Forwards a host property to this instance.  This method should be\n   * called on instances from the `options.forwardHostProp` callback\n   * to propagate changes of host properties to each instance.\n   *\n   * Note this method enqueues the change, which are flushed as a batch.\n   *\n   * @param {string} prop Property or path name\n   * @param {*} value Value of the property to forward\n   * @return {void}\n   */\n  forwardHostProp(prop, value) {\n    if (this._setPendingPropertyOrPath(prop, value, false, true)) {\n      this.__dataHost._enqueueClient(this);\n    }\n  }\n\n  /**\n   * Override point for adding custom or simulated event handling.\n   *\n   * @override\n   * @param {!Node} node Node to add event listener to\n   * @param {string} eventName Name of event\n   * @param {function(!Event):void} handler Listener function to add\n   * @return {void}\n   */\n  _addEventListenerToNode(node, eventName, handler) {\n    if (this._methodHost && this.__templatizeOptions.parentModel) {\n      // If this instance should be considered a parent model, decorate\n      // events this template instance as `model`\n      this._methodHost._addEventListenerToNode(node, eventName, (e) => {\n        e.model = this;\n        handler(e);\n      });\n    } else {\n      // Otherwise delegate to the template's host (which could be)\n      // another template instance\n      let templateHost = this.__dataHost.__dataHost;\n      if (templateHost) {\n        templateHost._addEventListenerToNode(node, eventName, handler);\n      }\n    }\n  }\n  /**\n   * Shows or hides the template instance top level child elements. For\n   * text nodes, `textContent` is removed while \"hidden\" and replaced when\n   * \"shown.\"\n   * @param {boolean} hide Set to true to hide the children;\n   * set to false to show them.\n   * @return {void}\n   * @protected\n   */\n  _showHideChildren(hide) {\n    showHideChildren(hide, this.children);\n  }\n  /**\n   * Overrides default property-effects implementation to intercept\n   * textContent bindings while children are \"hidden\" and cache in\n   * private storage for later retrieval.\n   *\n   * @override\n   * @param {!Node} node The node to set a property on\n   * @param {string} prop The property to set\n   * @param {*} value The value to set\n   * @return {void}\n   * @protected\n   */\n  _setUnmanagedPropertyToNode(node, prop, value) {\n    if (node.__hideTemplateChildren__ &&\n        node.nodeType == Node.TEXT_NODE && prop == 'textContent') {\n      node.__polymerTextContent__ = value;\n    } else {\n      super._setUnmanagedPropertyToNode(node, prop, value);\n    }\n  }\n  /**\n   * Find the parent model of this template instance.  The parent model\n   * is either another templatize instance that had option `parentModel: true`,\n   * or else the host element.\n   *\n   * @return {!Polymer_PropertyEffects} The parent model of this instance\n   */\n  get parentModel() {\n    let model = this.__parentModel;\n    if (!model) {\n      let options;\n      model = this;\n      do {\n        // A template instance's `__dataHost` is a <template>\n        // `model.__dataHost.__dataHost` is the template's host\n        model = model.__dataHost.__dataHost;\n      } while ((options = model.__templatizeOptions) && !options.parentModel);\n      this.__parentModel = model;\n    }\n    return model;\n  }\n\n  /**\n   * Stub of HTMLElement's `dispatchEvent`, so that effects that may\n   * dispatch events safely no-op.\n   *\n   * @param {Event} event Event to dispatch\n   * @return {boolean} Always true.\n   * @override\n   */\n   dispatchEvent(event) { // eslint-disable-line no-unused-vars\n     return true;\n  }\n}\n\n/** @type {!DataTemplate} */\nTemplateInstanceBase.prototype.__dataHost;\n/** @type {!TemplatizeOptions} */\nTemplateInstanceBase.prototype.__templatizeOptions;\n/** @type {!Polymer_PropertyEffects} */\nTemplateInstanceBase.prototype._methodHost;\n/** @type {!Object} */\nTemplateInstanceBase.prototype.__templatizeOwner;\n/** @type {!Object} */\nTemplateInstanceBase.prototype.__hostProps;\n\n/**\n * @constructor\n * @extends {TemplateInstanceBase}\n * @implements {Polymer_MutableData}\n * @private\n */\nconst MutableTemplateInstanceBase = MutableData(\n    // This cast shouldn't be neccessary, but Closure doesn't understand that\n    // TemplateInstanceBase is a constructor function.\n    /** @type {function(new:TemplateInstanceBase)} */ (TemplateInstanceBase));\n\nfunction findMethodHost(template) {\n  // Technically this should be the owner of the outermost template.\n  // In shadow dom, this is always getRootNode().host, but we can\n  // approximate this via cooperation with our dataHost always setting\n  // `_methodHost` as long as there were bindings (or id's) on this\n  // instance causing it to get a dataHost.\n  let templateHost = template.__dataHost;\n  return templateHost && templateHost._methodHost || templateHost;\n}\n\n/* eslint-disable valid-jsdoc */\n/**\n * @suppress {missingProperties} class.prototype is not defined for some reason\n */\nfunction createTemplatizerClass(template, templateInfo, options) {\n  /**\n   * @constructor\n   * @extends {TemplateInstanceBase}\n   */\n  let templatizerBase = options.mutableData ?\n    MutableTemplateInstanceBase : TemplateInstanceBase;\n\n  // Affordance for global mixins onto TemplatizeInstance\n  if (templatize.mixin) {\n    templatizerBase = templatize.mixin(templatizerBase);\n  }\n\n  /**\n   * Anonymous class created by the templatize\n   * @constructor\n   * @private\n   */\n  let klass = class extends templatizerBase { };\n  /** @override */\n  klass.prototype.__templatizeOptions = options;\n  klass.prototype._bindTemplate(template);\n  addNotifyEffects(klass, template, templateInfo, options);\n  return klass;\n}\n\n/**\n * Adds propagate effects from the template to the template instance for\n * properties that the host binds to the template using the `_host_` prefix.\n *\n * @suppress {missingProperties} class.prototype is not defined for some reason\n */\nfunction addPropagateEffects(target, templateInfo, options, methodHost) {\n  let userForwardHostProp = options.forwardHostProp;\n  if (userForwardHostProp && templateInfo.hasHostProps) {\n    // Under the `removeNestedTemplates` optimization, a custom element like\n    // `dom-if` or `dom-repeat` can itself be treated as the \"template\"; this\n    // flag is used to switch between upgrading a `<template>` to be a property\n    // effects client vs. adding the effects directly to the custom element\n    const isTemplate = target.localName == 'template';\n    // Provide data API and property effects on memoized template class\n    let klass = templateInfo.templatizeTemplateClass;\n    if (!klass) {\n      if (isTemplate) {\n        /**\n         * @constructor\n         * @extends {DataTemplate}\n         */\n        let templatizedBase =\n            options.mutableData ? MutableDataTemplate : DataTemplate;\n\n        // NOTE: due to https://github.com/google/closure-compiler/issues/2928,\n        // combining the next two lines into one assignment causes a spurious\n        // type error.\n        /** @private */\n        class TemplatizedTemplate extends templatizedBase {}\n        klass = templateInfo.templatizeTemplateClass = TemplatizedTemplate;\n      } else {\n        /**\n         * @constructor\n         * @extends {PolymerElement}\n         */\n        const templatizedBase = target.constructor;\n\n        // Create a cached subclass of the base custom element class onto which\n        // to put the template-specific propagate effects\n        // NOTE: due to https://github.com/google/closure-compiler/issues/2928,\n        // combining the next two lines into one assignment causes a spurious\n        // type error.\n        /** @private */\n        class TemplatizedTemplateExtension extends templatizedBase {}\n        klass = templateInfo.templatizeTemplateClass =\n            TemplatizedTemplateExtension;\n      }\n      // Add template - >instances effects\n      // and host <- template effects\n      let hostProps = templateInfo.hostProps;\n      for (let prop in hostProps) {\n        klass.prototype._addPropertyEffect('_host_' + prop,\n          klass.prototype.PROPERTY_EFFECT_TYPES.PROPAGATE,\n          {fn: createForwardHostPropEffect(prop, userForwardHostProp)});\n        klass.prototype._createNotifyingProperty('_host_' + prop);\n      }\n      if (legacyWarnings && methodHost) {\n        warnOnUndeclaredProperties(templateInfo, options, methodHost);\n      }\n    }\n    // Mix any pre-bound data into __data; no need to flush this to\n    // instances since they pull from the template at instance-time\n    if (target.__dataProto) {\n      // Note, generally `__dataProto` could be chained, but it's guaranteed\n      // to not be since this is a vanilla template we just added effects to\n      Object.assign(target.__data, target.__dataProto);\n    }\n    if (isTemplate) {\n      upgradeTemplate(target, klass);\n      // Clear any pending data for performance\n      target.__dataTemp = {};\n      target.__dataPending = null;\n      target.__dataOld = null;\n      target._enableProperties();\n    } else {\n      // Swizzle the cached subclass prototype onto the custom element\n      Object.setPrototypeOf(target, klass.prototype);\n      // Check for any pre-bound instance host properties, and do the\n      // instance property delete/assign dance for those (directly into data;\n      // not need to go through accessor since they are pulled at instance time)\n      const hostProps = templateInfo.hostProps;\n      for (let prop in hostProps) {\n        prop = '_host_' + prop;\n        if (prop in target) {\n          const val = target[prop];\n          delete target[prop];\n          target.__data[prop] = val;\n        }\n      }\n    }\n  }\n}\n/* eslint-enable valid-jsdoc */\n\nfunction createForwardHostPropEffect(hostProp, userForwardHostProp) {\n  return function forwardHostProp(template, prop, props) {\n    userForwardHostProp.call(template.__templatizeOwner,\n      prop.substring('_host_'.length), props[prop]);\n  };\n}\n\nfunction addNotifyEffects(klass, template, templateInfo, options) {\n  let hostProps = templateInfo.hostProps || {};\n  for (let iprop in options.instanceProps) {\n    delete hostProps[iprop];\n    let userNotifyInstanceProp = options.notifyInstanceProp;\n    if (userNotifyInstanceProp) {\n      klass.prototype._addPropertyEffect(iprop,\n        klass.prototype.PROPERTY_EFFECT_TYPES.NOTIFY,\n        {fn: createNotifyInstancePropEffect(iprop, userNotifyInstanceProp)});\n    }\n  }\n  if (options.forwardHostProp && template.__dataHost) {\n    for (let hprop in hostProps) {\n      // As we're iterating hostProps in this function, note whether\n      // there were any, for an optimization in addPropagateEffects\n      if (!templateInfo.hasHostProps) {\n        templateInfo.hasHostProps = true;\n      }\n      klass.prototype._addPropertyEffect(hprop,\n        klass.prototype.PROPERTY_EFFECT_TYPES.NOTIFY,\n        {fn: createNotifyHostPropEffect()});\n    }\n  }\n}\n\nfunction createNotifyInstancePropEffect(instProp, userNotifyInstanceProp) {\n  return function notifyInstanceProp(inst, prop, props) {\n    userNotifyInstanceProp.call(inst.__templatizeOwner,\n      inst, prop, props[prop]);\n  };\n}\n\nfunction createNotifyHostPropEffect() {\n  return function notifyHostProp(inst, prop, props) {\n    inst.__dataHost._setPendingPropertyOrPath('_host_' + prop, props[prop], true, true);\n  };\n}\n\n\n/**\n * Returns an anonymous `PropertyEffects` class bound to the\n * `<template>` provided.  Instancing the class will result in the\n * template being stamped into a document fragment stored as the instance's\n * `root` property, after which it can be appended to the DOM.\n *\n * Templates may utilize all Polymer data-binding features as well as\n * declarative event listeners.  Event listeners and inline computing\n * functions in the template will be called on the host of the template.\n *\n * The constructor returned takes a single argument dictionary of initial\n * property values to propagate into template bindings.  Additionally\n * host properties can be forwarded in, and instance properties can be\n * notified out by providing optional callbacks in the `options` dictionary.\n *\n * Valid configuration in `options` are as follows:\n *\n * - `forwardHostProp(property, value)`: Called when a property referenced\n *   in the template changed on the template's host. As this library does\n *   not retain references to templates instanced by the user, it is the\n *   templatize owner's responsibility to forward host property changes into\n *   user-stamped instances.  The `instance.forwardHostProp(property, value)`\n *    method on the generated class should be called to forward host\n *   properties into the template to prevent unnecessary property-changed\n *   notifications. Any properties referenced in the template that are not\n *   defined in `instanceProps` will be notified up to the template's host\n *   automatically.\n * - `instanceProps`: Dictionary of property names that will be added\n *   to the instance by the templatize owner.  These properties shadow any\n *   host properties, and changes within the template to these properties\n *   will result in `notifyInstanceProp` being called.\n * - `mutableData`: When `true`, the generated class will skip strict\n *   dirty-checking for objects and arrays (always consider them to be\n *   \"dirty\").\n * - `notifyInstanceProp(instance, property, value)`: Called when\n *   an instance property changes.  Users may choose to call `notifyPath`\n *   on e.g. the owner to notify the change.\n * - `parentModel`: When `true`, events handled by declarative event listeners\n *   (`on-event=\"handler\"`) will be decorated with a `model` property pointing\n *   to the template instance that stamped it.  It will also be returned\n *   from `instance.parentModel` in cases where template instance nesting\n *   causes an inner model to shadow an outer model.\n *\n * All callbacks are called bound to the `owner`. Any context\n * needed for the callbacks (such as references to `instances` stamped)\n * should be stored on the `owner` such that they can be retrieved via\n * `this`.\n *\n * When `options.forwardHostProp` is declared as an option, any properties\n * referenced in the template will be automatically forwarded from the host of\n * the `<template>` to instances, with the exception of any properties listed in\n * the `options.instanceProps` object.  `instanceProps` are assumed to be\n * managed by the owner of the instances, either passed into the constructor\n * or set after the fact.  Note, any properties passed into the constructor will\n * always be set to the instance (regardless of whether they would normally\n * be forwarded from the host).\n *\n * Note that `templatize()` can be run only once for a given `<template>`.\n * Further calls will result in an error. Also, there is a special\n * behavior if the template was duplicated through a mechanism such as\n * `<dom-repeat>` or `<test-fixture>`. In this case, all calls to\n * `templatize()` return the same class for all duplicates of a template.\n * The class returned from `templatize()` is generated only once using\n * the `options` from the first call. This means that any `options`\n * provided to subsequent calls will be ignored. Therefore, it is very\n * important not to close over any variables inside the callbacks. Also,\n * arrow functions must be avoided because they bind the outer `this`.\n * Inside the callbacks, any contextual information can be accessed\n * through `this`, which points to the `owner`.\n *\n * @param {!HTMLTemplateElement} template Template to templatize\n * @param {Polymer_PropertyEffects=} owner Owner of the template instances;\n *   any optional callbacks will be bound to this owner.\n * @param {Object=} options Options dictionary (see summary for details)\n * @return {function(new:TemplateInstanceBase, Object=)} Generated class bound\n *   to the template provided\n * @suppress {invalidCasts}\n */\nexport function templatize(template, owner, options) {\n  // Under strictTemplatePolicy, the templatized element must be owned\n  // by a (trusted) Polymer element, indicated by existence of _methodHost;\n  // e.g. for dom-if & dom-repeat in main document, _methodHost is null\n  if (strictTemplatePolicy && !findMethodHost(template)) {\n    throw new Error('strictTemplatePolicy: template owner not trusted');\n  }\n  options = /** @type {!TemplatizeOptions} */(options || {});\n  if (template.__templatizeOwner) {\n    throw new Error('A <template> can only be templatized once');\n  }\n  template.__templatizeOwner = owner;\n  const ctor = owner ? owner.constructor : TemplateInstanceBase;\n  let templateInfo = ctor._parseTemplate(template);\n  // Get memoized base class for the prototypical template, which\n  // includes property effects for binding template & forwarding\n  /**\n   * @constructor\n   * @extends {TemplateInstanceBase}\n   */\n  let baseClass = templateInfo.templatizeInstanceClass;\n  if (!baseClass) {\n    baseClass = createTemplatizerClass(template, templateInfo, options);\n    templateInfo.templatizeInstanceClass = baseClass;\n  }\n  const methodHost = findMethodHost(template);\n  // Host property forwarding must be installed onto template instance\n  addPropagateEffects(template, templateInfo, options, methodHost);\n  // Subclass base class and add reference for this specific template\n  /** @private */\n  let klass = class TemplateInstance extends baseClass {};\n  /** @override */\n  klass.prototype._methodHost = methodHost;\n  /** @override */\n  klass.prototype.__dataHost = /** @type {!DataTemplate} */ (template);\n  /** @override */\n  klass.prototype.__templatizeOwner = /** @type {!Object} */ (owner);\n  /** @override */\n  klass.prototype.__hostProps = templateInfo.hostProps;\n  klass = /** @type {function(new:TemplateInstanceBase)} */(klass); //eslint-disable-line no-self-assign\n  return klass;\n}\n\nfunction warnOnUndeclaredProperties(templateInfo, options, methodHost) {\n  const declaredProps = methodHost.constructor._properties;\n  const {propertyEffects} = templateInfo;\n  const {instanceProps} = options;\n  for (let prop in propertyEffects) {\n    // Ensure properties with template effects are declared on the outermost\n    // host (`methodHost`), unless they are instance props or static functions\n    if (!declaredProps[prop] && !(instanceProps && instanceProps[prop])) {\n      const effects = propertyEffects[prop];\n      for (let i=0; i<effects.length; i++) {\n        const {part} = effects[i].info;\n        if (!(part.signature && part.signature.static)) {\n          console.warn(`Property '${prop}' used in template but not ` +\n            `declared in 'properties'; attribute will not be observed.`);\n          break;\n        }\n      }\n    }\n  }\n}\n\n/**\n * Returns the template \"model\" associated with a given element, which\n * serves as the binding scope for the template instance the element is\n * contained in. A template model is an instance of\n * `TemplateInstanceBase`, and should be used to manipulate data\n * associated with this template instance.\n *\n * Example:\n *\n *   let model = modelForElement(el);\n *   if (model.index < 10) {\n *     model.set('item.checked', true);\n *   }\n *\n * @param {HTMLElement} template The model will be returned for\n *   elements stamped from this template (accepts either an HTMLTemplateElement)\n *   or a `<dom-if>`/`<dom-repeat>` element when using `removeNestedTemplates`\n *   optimization.\n * @param {Node=} node Node for which to return a template model.\n * @return {TemplateInstanceBase} Template instance representing the\n *   binding scope for the element\n */\nexport function modelForElement(template, node) {\n  let model;\n  while (node) {\n    // An element with a __templatizeInstance marks the top boundary\n    // of a scope; walk up until we find one, and then ensure that\n    // its __dataHost matches `this`, meaning this dom-repeat stamped it\n    if ((model = node.__dataHost ? node : node.__templatizeInstance)) {\n      // Found an element stamped by another template; keep walking up\n      // from its __dataHost\n      if (model.__dataHost != template) {\n        node = model.__dataHost;\n      } else {\n        return model;\n      }\n    } else {\n      // Still in a template scope, keep going up until\n      // a __templatizeInstance is found\n      node = wrap(node).parentNode;\n    }\n  }\n  return null;\n}\n\nexport { TemplateInstanceBase };\n"
  },
  {
    "path": "lib/utils/unresolved.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n\n\nexport {};\n"
  },
  {
    "path": "lib/utils/unresolved.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\nfunction resolve() {\n  document.body.removeAttribute('unresolved');\n}\n\nif (document.readyState === 'interactive' || document.readyState === 'complete') {\n  resolve();\n} else {\n  window.addEventListener('DOMContentLoaded', resolve);\n}\n\nexport {};\n"
  },
  {
    "path": "lib/utils/wrap.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n\nexport const wrap: <T extends Node>(node: T) => T;\n"
  },
  {
    "path": "lib/utils/wrap.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n/* eslint-disable valid-jsdoc */\n/**\n * Node wrapper to ensure ShadowDOM safe operation regardless of polyfill\n * presence or mode. Note that with the introduction of `ShadyDOM.noPatch`,\n * a node wrapper must be used to access ShadowDOM API.\n * This is similar to using `Polymer.dom` but relies exclusively\n * on the presence of the ShadyDOM polyfill rather than requiring the loading\n * of legacy (Polymer.dom) API.\n * @type {function(Node):Node}\n */\nexport const wrap = (window['ShadyDOM'] && window['ShadyDOM']['noPatch'] && window['ShadyDOM']['wrap']) ?\n  window['ShadyDOM']['wrap'] :\n  (window['ShadyDOM'] ? (n) => ShadyDOM['patch'](n) : (n) => n);\n\n"
  },
  {
    "path": "manifest.json",
    "content": "{\n  \"files\": {\n    \"polymer.html\": {\n      \"convertedUrl\": \"polymer-legacy.js\",\n      \"exports\": {\n        \"Polymer.Base\": \"Base\",\n        \"Polymer.html\": \"html\"\n      }\n    },\n    \"lib/legacy/legacy-element-mixin.html\": {\n      \"convertedUrl\": \"lib/legacy/legacy-element-mixin.js\",\n      \"exports\": {\n        \"Polymer.LegacyElementMixin\": \"LegacyElementMixin\"\n      }\n    },\n    \"lib/mixins/element-mixin.html\": {\n      \"convertedUrl\": \"lib/mixins/element-mixin.js\",\n      \"exports\": {\n        \"Polymer.ElementMixin\": \"ElementMixin\",\n        \"Polymer.telemetry.instanceCount\": \"instanceCount\",\n        \"Polymer.telemetry.registrations\": \"registrations\",\n        \"Polymer.telemetry._regLog\": \"_regLog\",\n        \"Polymer.telemetry.register\": \"register\",\n        \"Polymer.telemetry.dumpRegistrations\": \"dumpRegistrations\",\n        \"Polymer.telemetry\": \"*\",\n        \"Polymer.updateStyles\": \"updateStyles\"\n      }\n    },\n    \"lib/utils/boot.html\": {\n      \"convertedUrl\": \"lib/utils/boot.js\",\n      \"exports\": {}\n    },\n    \"lib/utils/settings.html\": {\n      \"convertedUrl\": \"lib/utils/settings.js\",\n      \"exports\": {\n        \"Polymer.Settings.useShadow\": \"useShadow\",\n        \"Polymer.Settings.useNativeCSSProperties\": \"useNativeCSSProperties\",\n        \"Polymer.Settings.useNativeCustomElements\": \"useNativeCustomElements\",\n        \"Polymer.rootPath\": \"rootPath\",\n        \"Polymer.setRootPath\": \"setRootPath\",\n        \"Polymer.sanitizeDOMValue\": \"sanitizeDOMValue\",\n        \"Polymer.setSanitizeDOMValue\": \"setSanitizeDOMValue\",\n        \"Polymer.passiveTouchGestures\": \"passiveTouchGestures\",\n        \"Polymer.setPassiveTouchGestures\": \"setPassiveTouchGestures\"\n      }\n    },\n    \"lib/utils/resolve-url.html\": {\n      \"convertedUrl\": \"lib/utils/resolve-url.js\",\n      \"exports\": {\n        \"Polymer.ResolveUrl.resolveCss\": \"resolveCss\",\n        \"Polymer.ResolveUrl.resolveUrl\": \"resolveUrl\",\n        \"Polymer.ResolveUrl.pathFromUrl\": \"pathFromUrl\",\n        \"Polymer.ResolveUrl\": \"*\"\n      }\n    },\n    \"lib/utils/mixin.html\": {\n      \"convertedUrl\": \"lib/utils/mixin.js\",\n      \"exports\": {\n        \"Polymer.dedupingMixin\": \"dedupingMixin\"\n      }\n    },\n    \"lib/utils/style-gather.html\": {\n      \"convertedUrl\": \"lib/utils/style-gather.js\",\n      \"exports\": {\n        \"Polymer.StyleGather.stylesFromModules\": \"stylesFromModules\",\n        \"Polymer.StyleGather.stylesFromModule\": \"stylesFromModule\",\n        \"Polymer.StyleGather.stylesFromTemplate\": \"stylesFromTemplate\",\n        \"Polymer.StyleGather.stylesFromModuleImports\": \"stylesFromModuleImports\",\n        \"Polymer.StyleGather._stylesFromModuleImports\": \"_stylesFromModuleImports\",\n        \"Polymer.StyleGather.cssFromModules\": \"cssFromModules\",\n        \"Polymer.StyleGather.cssFromModule\": \"cssFromModule\",\n        \"Polymer.StyleGather.cssFromTemplate\": \"cssFromTemplate\",\n        \"Polymer.StyleGather.cssFromModuleImports\": \"cssFromModuleImports\",\n        \"Polymer.StyleGather._cssFromModuleImports\": \"_cssFromModuleImports\",\n        \"Polymer.StyleGather\": \"*\"\n      }\n    },\n    \"lib/elements/dom-module.html\": {\n      \"convertedUrl\": \"lib/elements/dom-module.js\",\n      \"exports\": {\n        \"Polymer.DomModule\": \"DomModule\"\n      }\n    },\n    \"lib/mixins/property-effects.html\": {\n      \"convertedUrl\": \"lib/mixins/property-effects.js\",\n      \"exports\": {\n        \"Polymer.PropertyEffects\": \"PropertyEffects\"\n      }\n    },\n    \"lib/utils/path.html\": {\n      \"convertedUrl\": \"lib/utils/path.js\",\n      \"exports\": {\n        \"Path.isDeep\": \"isDeep\",\n        \"Polymer.Path.isPath\": \"isPath\",\n        \"Polymer.Path.root\": \"root\",\n        \"Polymer.Path.isAncestor\": \"isAncestor\",\n        \"Polymer.Path.isDescendant\": \"isDescendant\",\n        \"Polymer.Path.translate\": \"translate\",\n        \"Polymer.Path.matches\": \"matches\",\n        \"Polymer.Path.normalize\": \"normalize\",\n        \"Polymer.Path.split\": \"split\",\n        \"Polymer.Path.get\": \"get\",\n        \"Polymer.Path.set\": \"set\",\n        \"Polymer.Path\": \"*\"\n      }\n    },\n    \"lib/utils/case-map.html\": {\n      \"convertedUrl\": \"lib/utils/case-map.js\",\n      \"exports\": {\n        \"Polymer.CaseMap.dashToCamelCase\": \"dashToCamelCase\",\n        \"Polymer.CaseMap.camelToDashCase\": \"camelToDashCase\",\n        \"Polymer.CaseMap\": \"*\"\n      }\n    },\n    \"lib/mixins/property-accessors.html\": {\n      \"convertedUrl\": \"lib/mixins/property-accessors.js\",\n      \"exports\": {\n        \"Polymer.PropertyAccessors\": \"PropertyAccessors\"\n      }\n    },\n    \"lib/mixins/properties-changed.html\": {\n      \"convertedUrl\": \"lib/mixins/properties-changed.js\",\n      \"exports\": {\n        \"Polymer.PropertiesChanged\": \"PropertiesChanged\"\n      }\n    },\n    \"lib/utils/async.html\": {\n      \"convertedUrl\": \"lib/utils/async.js\",\n      \"exports\": {\n        \"Polymer.Async.timeOut\": \"timeOut\",\n        \"Polymer.Async.animationFrame\": \"animationFrame\",\n        \"Polymer.Async.idlePeriod\": \"idlePeriod\",\n        \"Polymer.Async.microTask\": \"microTask\",\n        \"Polymer.Async\": \"*\"\n      }\n    },\n    \"lib/mixins/template-stamp.html\": {\n      \"convertedUrl\": \"lib/mixins/template-stamp.js\",\n      \"exports\": {\n        \"Polymer.TemplateStamp\": \"TemplateStamp\"\n      }\n    },\n    \"lib/mixins/properties-mixin.html\": {\n      \"convertedUrl\": \"lib/mixins/properties-mixin.js\",\n      \"exports\": {\n        \"Polymer.PropertiesMixin\": \"PropertiesMixin\"\n      }\n    },\n    \"lib/mixins/gesture-event-listeners.html\": {\n      \"convertedUrl\": \"lib/mixins/gesture-event-listeners.js\",\n      \"exports\": {\n        \"Polymer.GestureEventListeners\": \"GestureEventListeners\"\n      }\n    },\n    \"lib/utils/gestures.html\": {\n      \"convertedUrl\": \"lib/utils/gestures.js\",\n      \"exports\": {\n        \"Gestures.findOriginalTarget\": \"findOriginalTarget\",\n        \"Gestures.add\": \"add\",\n        \"Gestures.remove\": \"remove\",\n        \"Polymer.Gestures.gestures\": \"gestures\",\n        \"Polymer.Gestures.recognizers\": \"recognizers\",\n        \"Polymer.Gestures.deepTargetFind\": \"deepTargetFind\",\n        \"Polymer.Gestures._findOriginalTarget\": \"_findOriginalTarget\",\n        \"Polymer.Gestures._handleNative\": \"_handleNative\",\n        \"Polymer.Gestures._handleTouchAction\": \"_handleTouchAction\",\n        \"Polymer.Gestures.addListener\": \"addListener\",\n        \"Polymer.Gestures.removeListener\": \"removeListener\",\n        \"Polymer.Gestures._add\": \"_add\",\n        \"Polymer.Gestures._remove\": \"_remove\",\n        \"Polymer.Gestures.register\": \"register\",\n        \"Polymer.Gestures._findRecognizerByEvent\": \"_findRecognizerByEvent\",\n        \"Polymer.Gestures.setTouchAction\": \"setTouchAction\",\n        \"Polymer.Gestures._fire\": \"_fire\",\n        \"Polymer.Gestures.prevent\": \"prevent\",\n        \"Polymer.Gestures.resetMouseCanceller\": \"resetMouseCanceller\",\n        \"Polymer.Gestures\": \"*\"\n      }\n    },\n    \"lib/utils/debounce.html\": {\n      \"convertedUrl\": \"lib/utils/debounce.js\",\n      \"exports\": {\n        \"Polymer.Debouncer\": \"Debouncer\"\n      }\n    },\n    \"lib/mixins/dir-mixin.html\": {\n      \"convertedUrl\": \"lib/mixins/dir-mixin.js\",\n      \"exports\": {\n        \"Polymer.DirMixin\": \"DirMixin\"\n      }\n    },\n    \"lib/utils/render-status.html\": {\n      \"convertedUrl\": \"lib/utils/render-status.js\",\n      \"exports\": {\n        \"Polymer.RenderStatus.beforeNextRender\": \"beforeNextRender\",\n        \"Polymer.RenderStatus.afterNextRender\": \"afterNextRender\",\n        \"Polymer.RenderStatus.flush\": \"flush\",\n        \"Polymer.RenderStatus\": \"*\"\n      }\n    },\n    \"lib/utils/unresolved.html\": {\n      \"convertedUrl\": \"lib/utils/unresolved.js\",\n      \"exports\": {}\n    },\n    \"lib/legacy/polymer.dom.html\": {\n      \"convertedUrl\": \"lib/legacy/polymer.dom.js\",\n      \"exports\": {\n        \"Polymer.DomApi\": \"DomApi\",\n        \"Polymer.dom\": \"dom\",\n        \"Polymer.dom.matchesSelector\": \"matchesSelector\",\n        \"Polymer.dom.flush\": \"flush\",\n        \"Polymer.dom.addDebouncer\": \"addDebouncer\"\n      }\n    },\n    \"lib/utils/flattened-nodes-observer.html\": {\n      \"convertedUrl\": \"lib/utils/flattened-nodes-observer.js\",\n      \"exports\": {\n        \"Polymer.FlattenedNodesObserver\": \"FlattenedNodesObserver\"\n      }\n    },\n    \"lib/utils/array-splice.html\": {\n      \"convertedUrl\": \"lib/utils/array-splice.js\",\n      \"exports\": {\n        \"Polymer.ArraySplice.calculateSplices\": \"calculateSplices\",\n        \"Polymer.ArraySplice\": \"*\"\n      }\n    },\n    \"lib/utils/flush.html\": {\n      \"convertedUrl\": \"lib/utils/flush.js\",\n      \"exports\": {\n        \"Polymer.enqueueDebouncer\": \"enqueueDebouncer\",\n        \"Polymer.flush\": \"flush\"\n      }\n    },\n    \"lib/legacy/polymer-fn.html\": {\n      \"convertedUrl\": \"lib/legacy/polymer-fn.js\",\n      \"exports\": {\n        \"Polymer\": \"Polymer\"\n      }\n    },\n    \"lib/legacy/class.html\": {\n      \"convertedUrl\": \"lib/legacy/class.js\",\n      \"exports\": {\n        \"Polymer.Class\": \"Class\",\n        \"Polymer.mixinBehaviors\": \"mixinBehaviors\"\n      }\n    },\n    \"lib/legacy/templatizer-behavior.html\": {\n      \"convertedUrl\": \"lib/legacy/templatizer-behavior.js\",\n      \"exports\": {\n        \"Polymer.Templatizer\": \"Templatizer\"\n      }\n    },\n    \"lib/utils/templatize.html\": {\n      \"convertedUrl\": \"lib/utils/templatize.js\",\n      \"exports\": {\n        \"Polymer.Templatize.templatize\": \"templatize\",\n        \"Polymer.Templatize.modelForElement\": \"modelForElement\",\n        \"Polymer.Templatize\": \"*\",\n        \"Polymer.TemplateInstanceBase\": \"TemplateInstanceBase\"\n      }\n    },\n    \"lib/mixins/mutable-data.html\": {\n      \"convertedUrl\": \"lib/mixins/mutable-data.js\",\n      \"exports\": {\n        \"Polymer.MutableData\": \"MutableData\",\n        \"Polymer.OptionalMutableData\": \"OptionalMutableData\"\n      }\n    },\n    \"lib/elements/dom-bind.html\": {\n      \"convertedUrl\": \"lib/elements/dom-bind.js\",\n      \"exports\": {\n        \"Polymer.DomBind\": \"DomBind\"\n      }\n    },\n    \"lib/elements/dom-repeat.html\": {\n      \"convertedUrl\": \"lib/elements/dom-repeat.js\",\n      \"exports\": {\n        \"Polymer.DomRepeat\": \"DomRepeat\"\n      }\n    },\n    \"polymer-element.html\": {\n      \"convertedUrl\": \"polymer-element.js\",\n      \"exports\": {\n        \"Polymer.Element\": \"PolymerElement\",\n        \"Polymer.html\": \"html\"\n      }\n    },\n    \"lib/utils/html-tag.html\": {\n      \"convertedUrl\": \"lib/utils/html-tag.js\",\n      \"exports\": {\n        \"Polymer.html\": \"html\",\n        \"Polymer.htmlLiteral\": \"htmlLiteral\"\n      }\n    },\n    \"lib/elements/dom-if.html\": {\n      \"convertedUrl\": \"lib/elements/dom-if.js\",\n      \"exports\": {\n        \"Polymer.DomIf\": \"DomIf\"\n      }\n    },\n    \"lib/elements/array-selector.html\": {\n      \"convertedUrl\": \"lib/elements/array-selector.js\",\n      \"exports\": {\n        \"Polymer.ArraySelectorMixin\": \"ArraySelectorMixin\",\n        \"Polymer.ArraySelector\": \"ArraySelector\"\n      }\n    },\n    \"lib/elements/custom-style.html\": {\n      \"convertedUrl\": \"lib/elements/custom-style.js\",\n      \"exports\": {\n        \"Polymer.CustomStyle\": \"CustomStyle\"\n      }\n    },\n    \"lib/legacy/mutable-data-behavior.html\": {\n      \"convertedUrl\": \"lib/legacy/mutable-data-behavior.js\",\n      \"exports\": {\n        \"Polymer.MutableDataBehavior\": \"MutableDataBehavior\",\n        \"Polymer.OptionalMutableDataBehavior\": \"OptionalMutableDataBehavior\"\n      }\n    },\n    \"index.html\": {\n      \"convertedUrl\": \"index.html\",\n      \"exports\": {}\n    },\n    \"externs/polymer-internal-types.html\": {\n      \"convertedUrl\": \"externs/polymer-internal-types.html\",\n      \"exports\": {}\n    },\n    \"test/runner.html\": {\n      \"convertedUrl\": \"test/runner.html\",\n      \"exports\": {}\n    },\n    \"test/smoke/alacarte-property-accessors.html\": {\n      \"convertedUrl\": \"test/smoke/alacarte-property-accessors.html\",\n      \"exports\": {}\n    },\n    \"test/smoke/alacarte-property-effects-ordering.html\": {\n      \"convertedUrl\": \"test/smoke/alacarte-property-effects-ordering.html\",\n      \"exports\": {}\n    },\n    \"test/smoke/alacarte-property-effects.html\": {\n      \"convertedUrl\": \"test/smoke/alacarte-property-effects.html\",\n      \"exports\": {}\n    },\n    \"test/smoke/alacarte-template-stamp.html\": {\n      \"convertedUrl\": \"test/smoke/alacarte-template-stamp.html\",\n      \"exports\": {}\n    },\n    \"test/smoke/behavior-mixin.html\": {\n      \"convertedUrl\": \"test/smoke/behavior-mixin.html\",\n      \"exports\": {}\n    },\n    \"test/smoke/data-table.html\": {\n      \"convertedUrl\": \"test/smoke/data-table.html\",\n      \"exports\": {}\n    },\n    \"test/smoke/dirty-check.html\": {\n      \"convertedUrl\": \"test/smoke/dirty-check.html\",\n      \"exports\": {}\n    },\n    \"test/smoke/disable-upgrade.html\": {\n      \"convertedUrl\": \"test/smoke/disable-upgrade.html\",\n      \"exports\": {}\n    },\n    \"lib/mixins/disable-upgrade-mixin.html\": {\n      \"convertedUrl\": \"lib/mixins/disable-upgrade-mixin.js\",\n      \"exports\": {\n        \"Polymer.DisableUpgradeMixin\": \"DisableUpgradeMixin\"\n      }\n    },\n    \"test/smoke/disabled-attr-gestures.html\": {\n      \"convertedUrl\": \"test/smoke/disabled-attr-gestures.html\",\n      \"exports\": {}\n    },\n    \"test/smoke/dom-if.html\": {\n      \"convertedUrl\": \"test/smoke/dom-if.html\",\n      \"exports\": {}\n    },\n    \"test/smoke/gestures.html\": {\n      \"convertedUrl\": \"test/smoke/gestures.html\",\n      \"exports\": {}\n    },\n    \"test/smoke/html-tag.html\": {\n      \"convertedUrl\": \"test/smoke/html-tag.html\",\n      \"exports\": {}\n    },\n    \"test/smoke/label-click.html\": {\n      \"convertedUrl\": \"test/smoke/label-click.html\",\n      \"exports\": {}\n    },\n    \"test/smoke/ordering-test.html\": {\n      \"convertedUrl\": \"test/smoke/ordering-test.html\",\n      \"exports\": {}\n    },\n    \"test/smoke/passive-gestures.html\": {\n      \"convertedUrl\": \"test/smoke/passive-gestures.html\",\n      \"exports\": {}\n    },\n    \"test/smoke/style-props/test.html\": {\n      \"convertedUrl\": \"test/smoke/style-props/test.html\",\n      \"exports\": {}\n    },\n    \"test/smoke/style-props/src/scopes.html\": {\n      \"convertedUrl\": \"test/smoke/style-props/src/scopes.js\",\n      \"exports\": {}\n    },\n    \"test/smoke/style-props/src/settings.html\": {\n      \"convertedUrl\": \"test/smoke/style-props/src/settings.js\",\n      \"exports\": {}\n    },\n    \"test/smoke/style-props/src/elements.html\": {\n      \"convertedUrl\": \"test/smoke/style-props/src/elements.js\",\n      \"exports\": {}\n    },\n    \"test/smoke/style-props/src/elements-defaults.html\": {\n      \"convertedUrl\": \"test/smoke/style-props/src/elements-defaults.js\",\n      \"exports\": {}\n    },\n    \"test/unit/array-selector.html\": {\n      \"convertedUrl\": \"test/unit/array-selector.html\",\n      \"exports\": {}\n    },\n    \"test/unit/array-selector-elements.html\": {\n      \"convertedUrl\": \"test/unit/array-selector-elements.js\",\n      \"exports\": {}\n    },\n    \"test/unit/async.html\": {\n      \"convertedUrl\": \"test/unit/async.html\",\n      \"exports\": {}\n    },\n    \"test/unit/attributes.html\": {\n      \"convertedUrl\": \"test/unit/attributes.html\",\n      \"exports\": {}\n    },\n    \"test/unit/attributes-elements.html\": {\n      \"convertedUrl\": \"test/unit/attributes-elements.js\",\n      \"exports\": {}\n    },\n    \"test/unit/behaviors.html\": {\n      \"convertedUrl\": \"test/unit/behaviors.html\",\n      \"exports\": {}\n    },\n    \"test/unit/case-map.html\": {\n      \"convertedUrl\": \"test/unit/case-map.html\",\n      \"exports\": {}\n    },\n    \"test/unit/configure.html\": {\n      \"convertedUrl\": \"test/unit/configure.html\",\n      \"exports\": {}\n    },\n    \"test/unit/css-parse.html\": {\n      \"convertedUrl\": \"test/unit/css-parse.html\",\n      \"exports\": {}\n    },\n    \"test/unit/custom-style-async-import.html\": {\n      \"convertedUrl\": \"test/unit/custom-style-async-import.html\",\n      \"exports\": {}\n    },\n    \"test/unit/custom-style-async.html\": {\n      \"convertedUrl\": \"test/unit/custom-style-async.html\",\n      \"exports\": {}\n    },\n    \"test/unit/custom-style-late.html\": {\n      \"convertedUrl\": \"test/unit/custom-style-late.html\",\n      \"exports\": {}\n    },\n    \"test/unit/custom-style-scope-cache.html\": {\n      \"convertedUrl\": \"test/unit/custom-style-scope-cache.html\",\n      \"exports\": {}\n    },\n    \"test/unit/custom-style.html\": {\n      \"convertedUrl\": \"test/unit/custom-style.html\",\n      \"exports\": {}\n    },\n    \"test/unit/custom-style-import.html\": {\n      \"convertedUrl\": \"test/unit/custom-style-import.js\",\n      \"exports\": {}\n    },\n    \"test/unit/sub/style-import.html\": {\n      \"convertedUrl\": \"test/unit/sub/style-import.js\",\n      \"exports\": {}\n    },\n    \"test/unit/debounce.html\": {\n      \"convertedUrl\": \"test/unit/debounce.html\",\n      \"exports\": {}\n    },\n    \"test/unit/dir.html\": {\n      \"convertedUrl\": \"test/unit/dir.html\",\n      \"exports\": {}\n    },\n    \"test/unit/disable-upgrade.html\": {\n      \"convertedUrl\": \"test/unit/disable-upgrade.html\",\n      \"exports\": {}\n    },\n    \"test/unit/dom-bind.html\": {\n      \"convertedUrl\": \"test/unit/dom-bind.html\",\n      \"exports\": {}\n    },\n    \"test/unit/dom-bind-elements1.html\": {\n      \"convertedUrl\": \"test/unit/dom-bind-elements1.js\",\n      \"exports\": {}\n    },\n    \"test/unit/dom-bind-elements2.html\": {\n      \"convertedUrl\": \"test/unit/dom-bind-elements2.js\",\n      \"exports\": {}\n    },\n    \"test/unit/dom-if.html\": {\n      \"convertedUrl\": \"test/unit/dom-if.html\",\n      \"exports\": {}\n    },\n    \"test/unit/dom-if-elements.html\": {\n      \"convertedUrl\": \"test/unit/dom-if-elements.js\",\n      \"exports\": {}\n    },\n    \"test/unit/dom-repeat.html\": {\n      \"convertedUrl\": \"test/unit/dom-repeat.html\",\n      \"exports\": {}\n    },\n    \"test/unit/dom-repeat-elements.html\": {\n      \"convertedUrl\": \"test/unit/dom-repeat-elements.js\",\n      \"exports\": {}\n    },\n    \"test/unit/dynamic-import.html\": {\n      \"convertedUrl\": \"test/unit/dynamic-import.html\",\n      \"exports\": {}\n    },\n    \"test/unit/dynamic-imports/dynamic-element.html\": {\n      \"convertedUrl\": \"test/unit/dynamic-imports/dynamic-element.js\",\n      \"exports\": {}\n    },\n    \"test/unit/events.html\": {\n      \"convertedUrl\": \"test/unit/events.html\",\n      \"exports\": {}\n    },\n    \"test/unit/events-elements.html\": {\n      \"convertedUrl\": \"test/unit/events-elements.js\",\n      \"exports\": {}\n    },\n    \"test/unit/flattened-nodes-observer.html\": {\n      \"convertedUrl\": \"test/unit/flattened-nodes-observer.html\",\n      \"exports\": {}\n    },\n    \"test/unit/gestures.html\": {\n      \"convertedUrl\": \"test/unit/gestures.html\",\n      \"exports\": {}\n    },\n    \"test/unit/gestures-elements.html\": {\n      \"convertedUrl\": \"test/unit/gestures-elements.js\",\n      \"exports\": {}\n    },\n    \"test/unit/globals.html\": {\n      \"convertedUrl\": \"test/unit/globals.html\",\n      \"exports\": {}\n    },\n    \"test/unit/html-tag.html\": {\n      \"convertedUrl\": \"test/unit/html-tag.html\",\n      \"exports\": {}\n    },\n    \"test/unit/importHref.html\": {\n      \"convertedUrl\": \"test/unit/importHref.html\",\n      \"exports\": {}\n    },\n    \"test/unit/inheritance.html\": {\n      \"convertedUrl\": \"test/unit/inheritance.html\",\n      \"exports\": {}\n    },\n    \"test/unit/logging.html\": {\n      \"convertedUrl\": \"test/unit/logging.html\",\n      \"exports\": {}\n    },\n    \"test/unit/mixin-behaviors.html\": {\n      \"convertedUrl\": \"test/unit/mixin-behaviors.html\",\n      \"exports\": {}\n    },\n    \"test/unit/mixin-utils.html\": {\n      \"convertedUrl\": \"test/unit/mixin-utils.html\",\n      \"exports\": {}\n    },\n    \"test/unit/multi-style.html\": {\n      \"convertedUrl\": \"test/unit/multi-style.html\",\n      \"exports\": {}\n    },\n    \"test/unit/path-effects.html\": {\n      \"convertedUrl\": \"test/unit/path-effects.html\",\n      \"exports\": {}\n    },\n    \"test/unit/path-effects-elements.html\": {\n      \"convertedUrl\": \"test/unit/path-effects-elements.js\",\n      \"exports\": {}\n    },\n    \"test/unit/path.html\": {\n      \"convertedUrl\": \"test/unit/path.html\",\n      \"exports\": {}\n    },\n    \"test/unit/polymer-dom-observeNodes.html\": {\n      \"convertedUrl\": \"test/unit/polymer-dom-observeNodes.html\",\n      \"exports\": {}\n    },\n    \"test/unit/polymer-dom.html\": {\n      \"convertedUrl\": \"test/unit/polymer-dom.html\",\n      \"exports\": {}\n    },\n    \"test/unit/polymer-element-with-apply.html\": {\n      \"convertedUrl\": \"test/unit/polymer-element-with-apply.html\",\n      \"exports\": {}\n    },\n    \"test/unit/polymer-element-with-apply-import.html\": {\n      \"convertedUrl\": \"test/unit/polymer-element-with-apply-import.js\",\n      \"exports\": {}\n    },\n    \"test/unit/polymer.element.html\": {\n      \"convertedUrl\": \"test/unit/polymer.element.html\",\n      \"exports\": {}\n    },\n    \"test/unit/polymer.legacyelement.html\": {\n      \"convertedUrl\": \"test/unit/polymer.legacyelement.html\",\n      \"exports\": {}\n    },\n    \"test/unit/polymer.properties-mixin-with-property-accessors.html\": {\n      \"convertedUrl\": \"test/unit/polymer.properties-mixin-with-property-accessors.html\",\n      \"exports\": {}\n    },\n    \"test/unit/polymer.properties-mixin.html\": {\n      \"convertedUrl\": \"test/unit/polymer.properties-mixin.html\",\n      \"exports\": {}\n    },\n    \"test/unit/properties-changed.html\": {\n      \"convertedUrl\": \"test/unit/properties-changed.html\",\n      \"exports\": {}\n    },\n    \"test/unit/property-accessors.html\": {\n      \"convertedUrl\": \"test/unit/property-accessors.html\",\n      \"exports\": {}\n    },\n    \"test/unit/property-effects-template.html\": {\n      \"convertedUrl\": \"test/unit/property-effects-template.html\",\n      \"exports\": {}\n    },\n    \"test/unit/property-effects.html\": {\n      \"convertedUrl\": \"test/unit/property-effects.html\",\n      \"exports\": {}\n    },\n    \"test/unit/property-effects-elements.html\": {\n      \"convertedUrl\": \"test/unit/property-effects-elements.js\",\n      \"exports\": {}\n    },\n    \"test/unit/ready-attached-order-class.html\": {\n      \"convertedUrl\": \"test/unit/ready-attached-order-class.html\",\n      \"exports\": {}\n    },\n    \"test/unit/ready-attached-order.html\": {\n      \"convertedUrl\": \"test/unit/ready-attached-order.html\",\n      \"exports\": {}\n    },\n    \"test/unit/render-status.html\": {\n      \"convertedUrl\": \"test/unit/render-status.html\",\n      \"exports\": {}\n    },\n    \"test/unit/resolveurl.html\": {\n      \"convertedUrl\": \"test/unit/resolveurl.html\",\n      \"exports\": {}\n    },\n    \"test/unit/sub/resolveurl-elements.html\": {\n      \"convertedUrl\": \"test/unit/sub/resolveurl-elements.js\",\n      \"exports\": {}\n    },\n    \"test/unit/shady-content.html\": {\n      \"convertedUrl\": \"test/unit/shady-content.html\",\n      \"exports\": {}\n    },\n    \"test/unit/shady-dynamic.html\": {\n      \"convertedUrl\": \"test/unit/shady-dynamic.html\",\n      \"exports\": {}\n    },\n    \"test/unit/shady-events.html\": {\n      \"convertedUrl\": \"test/unit/shady-events.html\",\n      \"exports\": {}\n    },\n    \"test/unit/shady-unscoped-style.html\": {\n      \"convertedUrl\": \"test/unit/shady-unscoped-style.html\",\n      \"exports\": {}\n    },\n    \"test/unit/shady-unscoped-style-import.html\": {\n      \"convertedUrl\": \"test/unit/shady-unscoped-style-import.js\",\n      \"exports\": {}\n    },\n    \"test/unit/shady-unscoped-style-import-css.html\": {\n      \"convertedUrl\": \"test/unit/shady-unscoped-style-import-css.js\",\n      \"exports\": {}\n    },\n    \"test/unit/shady.html\": {\n      \"convertedUrl\": \"test/unit/shady.html\",\n      \"exports\": {}\n    },\n    \"test/unit/styling-cross-scope-apply.html\": {\n      \"convertedUrl\": \"test/unit/styling-cross-scope-apply.html\",\n      \"exports\": {}\n    },\n    \"test/unit/styling-cross-scope-unknown-host.html\": {\n      \"convertedUrl\": \"test/unit/styling-cross-scope-unknown-host.html\",\n      \"exports\": {}\n    },\n    \"test/unit/styling-cross-scope-var.html\": {\n      \"convertedUrl\": \"test/unit/styling-cross-scope-var.html\",\n      \"exports\": {}\n    },\n    \"test/unit/styling-import.html\": {\n      \"convertedUrl\": \"test/unit/styling-import.html\",\n      \"exports\": {}\n    },\n    \"test/unit/styling-import-shared-styles.html\": {\n      \"convertedUrl\": \"test/unit/styling-import-shared-styles.js\",\n      \"exports\": {}\n    },\n    \"test/unit/styling-only-with-template.html\": {\n      \"convertedUrl\": \"test/unit/styling-only-with-template.html\",\n      \"exports\": {}\n    },\n    \"test/unit/styling-scoped.html\": {\n      \"convertedUrl\": \"test/unit/styling-scoped.html\",\n      \"exports\": {}\n    },\n    \"test/unit/template-stamp.html\": {\n      \"convertedUrl\": \"test/unit/template-stamp.html\",\n      \"exports\": {}\n    },\n    \"test/unit/template-whitespace.html\": {\n      \"convertedUrl\": \"test/unit/template-whitespace.html\",\n      \"exports\": {}\n    },\n    \"test/unit/templatize.html\": {\n      \"convertedUrl\": \"test/unit/templatize.html\",\n      \"exports\": {}\n    },\n    \"test/unit/templatize-elements.html\": {\n      \"convertedUrl\": \"test/unit/templatize-elements.js\",\n      \"exports\": {}\n    },\n    \"test/unit/dynamic-imports/async-import.html\": {\n      \"convertedUrl\": \"test/unit/dynamic-imports/async-import.html\",\n      \"exports\": {}\n    },\n    \"test/unit/dynamic-imports/async.html\": {\n      \"convertedUrl\": \"test/unit/dynamic-imports/async.html\",\n      \"exports\": {}\n    },\n    \"test/unit/dynamic-imports/outer-element.html\": {\n      \"convertedUrl\": \"test/unit/dynamic-imports/outer-element.html\",\n      \"exports\": {}\n    },\n    \"test/unit/dynamic-imports/inner-element.html\": {\n      \"convertedUrl\": \"test/unit/dynamic-imports/inner-element.js\",\n      \"exports\": {}\n    },\n    \"test/unit/sub/x-sub.html\": {\n      \"convertedUrl\": \"test/unit/sub/x-sub.html\",\n      \"exports\": {}\n    },\n    \"test/unit/sub/x-test.html\": {\n      \"convertedUrl\": \"test/unit/sub/x-test.html\",\n      \"exports\": {}\n    }\n  }\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"@polymer/polymer\",\n  \"version\": \"3.5.2\",\n  \"description\": \"The Polymer library makes it easy to create your own web components. Give your element some markup and properties, and then use it on a site. Polymer provides features like dynamic templates and data binding to reduce the amount of boilerplate you need to write\",\n  \"main\": \"polymer-element.js\",\n  \"module\": \"polymer-element.js\",\n  \"directories\": {\n    \"doc\": \"docs\",\n    \"test\": \"test\"\n  },\n  \"devDependencies\": {\n    \"@polymer/gen-closure-declarations\": \"^0.5.0\",\n    \"@polymer/iron-component-page\": \"^3.0.0-pre.12\",\n    \"@polymer/test-fixture\": \"^3.0.0-pre.12\",\n    \"@webcomponents/webcomponentsjs\": \"^2.2.10\",\n    \"babel-eslint\": \"^7.2.3\",\n    \"babel-preset-minify\": \"^0.2.0\",\n    \"del\": \"^3.0.0\",\n    \"dom5\": \"^3.0.1\",\n    \"eslint-plugin-html\": \"^4.0.6\",\n    \"fs-extra\": \"^5.0.0\",\n    \"google-closure-compiler\": \"^20180204.0.0\",\n    \"gulp\": \"^4.0.2\",\n    \"gulp-babel\": \"^6.1.2\",\n    \"gulp-eslint\": \"^4.0.0\",\n    \"gulp-if\": \"^2.0.1\",\n    \"gulp-replace\": \"^0.6.1\",\n    \"gulp-size\": \"^3.0.0\",\n    \"gulp-vulcanize\": \"^7.0.0\",\n    \"lazypipe\": \"^1.0.2\",\n    \"merge-stream\": \"^1.0.1\",\n    \"parse5\": \"^4.0.0\",\n    \"polymer-build\": \"^3.1.4\",\n    \"polymer-cli\": \"^1.9.9\",\n    \"through2\": \"^2.0.0\",\n    \"typescript\": \"^2.9.2\",\n    \"wct-browser-legacy\": \"^1.0.2\"\n  },\n  \"scripts\": {\n    \"build\": \"gulp\",\n    \"test\": \"npm run lint && polymer test --npm --module-resolution=node\",\n    \"serve\": \"polymer serve --npm --module-resolution=node\",\n    \"lint\": \"gulp lint\",\n    \"generate-types\": \"gulp generate-externs\",\n    \"regen-package-lock\": \"rm -rf node_modules package-lock.json; npm install\",\n    \"prepare\": \"npm run generate-types\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/Polymer/polymer.git\"\n  },\n  \"author\": \"The Polymer Project Authors\",\n  \"license\": \"BSD-3-Clause\",\n  \"bugs\": {\n    \"url\": \"https://github.com/Polymer/polymer/issues\"\n  },\n  \"homepage\": \"https://github.com/Polymer/polymer\",\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"resolutions\": {\n    \"inherits\": \"2.0.3\",\n    \"samsam\": \"1.1.3\",\n    \"supports-color\": \"3.1.2\",\n    \"type-detect\": \"1.0.0\"\n  },\n  \"dependencies\": {\n    \"@webcomponents/shadycss\": \"^1.9.1\"\n  },\n  \"files\": [\n    \"externs\",\n    \"lib\",\n    \"*.d.ts\",\n    \"index.html\",\n    \"polymer-*.js\",\n    \"manifest.json\",\n    \"CHANGELOG.md\"\n  ]\n}\n"
  },
  {
    "path": "polymer-element.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n\nimport {ElementMixin} from './lib/mixins/element-mixin.js';\n\nexport {html} from './lib/utils/html-tag.js';\n\nexport {PolymerElement};\n\n/**\n * Base class that provides the core API for Polymer's meta-programming\n * features including template stamping, data-binding, attribute deserialization,\n * and property change observation.\n */\ndeclare class PolymerElement extends\n  ElementMixin(\n  HTMLElement) {\n}\n"
  },
  {
    "path": "polymer-element.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\nimport { ElementMixin, version } from './lib/mixins/element-mixin.js';\nexport { html } from './lib/utils/html-tag.js';\n\nexport { version };\n\n/**\n * Base class that provides the core API for Polymer's meta-programming\n * features including template stamping, data-binding, attribute deserialization,\n * and property change observation.\n *\n * @customElement\n * @polymer\n * @constructor\n * @implements {Polymer_ElementMixin}\n * @extends HTMLElement\n * @appliesMixin ElementMixin\n * @summary Custom element base class that provides the core API for Polymer's\n *   key meta-programming features including template stamping, data-binding,\n *   attribute deserialization, and property change observation\n */\nexport const PolymerElement = ElementMixin(HTMLElement);\n"
  },
  {
    "path": "polymer-legacy.d.ts",
    "content": "// tslint:disable:variable-name Describing an API that's defined elsewhere.\n\nimport {LegacyElementMixin} from './lib/legacy/legacy-element-mixin.js';\n\nexport {Polymer} from './lib/legacy/polymer-fn.js';\n\nexport {html} from './lib/utils/html-tag.js';\n\nexport const Base: LegacyElementMixin;\n"
  },
  {
    "path": "polymer-legacy.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\nimport { LegacyElementMixin } from './lib/legacy/legacy-element-mixin.js';\nexport { Polymer } from  './lib/legacy/polymer-fn.js';\n/* template elements */\nimport './lib/legacy/templatizer-behavior.js';\nimport './lib/elements/dom-bind.js';\nimport './lib/elements/dom-repeat.js';\nimport './lib/elements/dom-if.js';\nimport './lib/elements/array-selector.js';\n/* custom-style */\nimport './lib/elements/custom-style.js';\n/* bc behaviors */\nimport './lib/legacy/mutable-data-behavior.js';\n/* import html-tag to export html */\nexport { html } from './lib/utils/html-tag.js';\n\n// bc\nexport const Base = LegacyElementMixin(HTMLElement).prototype;\n"
  },
  {
    "path": "test/.eslintignore",
    "content": "assets/*\ncompat/*\nsmoke/*\n"
  },
  {
    "path": "test/.eslintrc.json",
    "content": "{\n  \"env\": {\n    \"mocha\": true\n  },\n  \"rules\": {\n    \"no-var\": \"off\",\n    \"strict\": \"off\"\n  },\n  \"globals\": {\n    \"assert\": true,\n    \"sinon\": true,\n    \"WCT\": true,\n    \"fixture\": true\n  }\n}\n"
  },
  {
    "path": "test/perf/binding-expressions.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes\">\n  <script src=\"../../../../perf-tester/perf.js\"></script>\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n  <script type=\"module\" src=\"../../lib/mixins/strict-binding-parser.js\"></script>\n</head>\n\n<body>\n\n<!--   <template>\n    {{compute(alaksjflkasjflkasjflkasjlfkajslkfjaslkfjaaaaaaaaaaaaaaaaaaaaaaaa)]}\n  </template>\n -->    <!-- {{compute(tricky, 'literal\\,\\'zot\\'', this.has.long.log.lo)]} -->\n\n  <template>\n    <span>{{foo}}</span> <span>{{foo.bar}}</span> <span>{{foo.bar.zot}}</span>\n    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n    tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\n    quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\n    consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\n    cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\n    proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n    <span>{{compute(tricky, 'literal\\,\\'zot\\'')}}</span>\n    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n    tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\n    quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\n    consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\n    cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\n    proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n    <span>{{compute(tricky, 'literal\\,\\'zot\\'', this.has.a.bogus.ending.bracket)]}</span>\n    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n    tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\n    quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\n    consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\n    cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\n    proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n    <div class$=\"{{compute(a, b, c,d,e,f,g,h,i)}}\">\n      Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n      tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\n      quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\n      consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\n      cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\n      proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n      <span>{{bindings.and.stuff}}</span>\n      <div id=\"zot\"><span>[[computeFn(a, 'b', c, \"d\", 999)]]</span> literal <span>{{a.b}}</span> literally</div>\n      <div id=\"zot\"><span>[[computeFn(a, 'b', c, \"d\", 999)]]</span> literal <span>{{a.b}}</span> literally</div>\n      <div id=\"zot\"><span>[[computeFn(a, 'b', c, \"d\", 999)]]</span> literal <span>{{a.b}}</span> literally</div>\n      <div id=\"zot\"><span>[[computeFn(a, 'b', c, \"d\", 999)]]</span> literal <span>{{a.b}}</span> literally</div>\n      <div id=\"zot\"><span>[[computeFn(a, 'b', c, \"d\", 999)]]</span> literal <span>{{a.b}}</span> literally</div>\n      <div id=\"zot\"><span>[[computeFn(a, 'b', c, \"d\", 999)]]</span> literal <span>{{a.b}}</span> literally</div>\n      <div id=\"zot\"><span>[[computeFn(a, 'b', c, \"d\", 999)]]</span> literal <span>{{a.b}}</span> literally</div>\n    </div>\n  </template>\n\n  <script type=\"module\">\nimport { StrictBindingParser } from '../../lib/mixins/strict-binding-parser.js';\nimport { PolymerElement } from '../../polymer-element.js';\nvar COUNT = 1000;\nvar templates = [];\nvar template = document.querySelector('template');\nfor (var i=0; i<COUNT; i++) {\n  templates[i] = template.cloneNode(true);\n}\nconsole.perf();\nfor (var i=0; i<COUNT; i++) {\n  const klass = class Foo extends StrictBindingParser(PolymerElement) {\n    static get _template() { return templates[i]; }\n  };\n  customElements.define('foo-' + i, klass);\n  new klass();\n}\nconsole.perfEnd();\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/perf/perf-tests.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js\"></script>\n  <script src=\"../../../../perf-tester/perf-tester.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n  <style>\n    summary {\n      font-family: sans-serif;\n      font-size: 1.5em;\n    }\n  </style>\n\n</head>\n<body>\n  <summary>Perf is go.</summary>\n  <perf-tester runs=\"25\"></perf-tester>\n\n  <script type=\"module\">\ndocument.querySelector('perf-tester').tests = [\n  'binding-expressions.html'\n];\n</script>\n\n</body>\n"
  },
  {
    "path": "test/runner.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script>\n    WCT = {\n      mochaOptions: {\n        timeout: 60000\n      }\n    }\n  </script>\n  <script src=\"unit/wct-browser-config.js\"></script>\n  <script src=\"../node_modules/wct-browser-legacy/browser.js\"></script>\n</head>\n<body>\n  <script>\n    'use strict';\n\n    let suites = [\n      'unit/globals.html',\n      'unit/property-accessors.html',\n      'unit/template-stamp.html',\n      'unit/strict-template-policy.html',\n      'unit/property-effects.html',\n      'unit/property-effects.html?legacyUndefined=true',\n      'unit/property-effects.html?orderedComputed=true',\n      'unit/property-effects-template.html',\n      'unit/path-effects.html',\n      'unit/path-effects.html?orderedComputed=true',\n      'unit/shady.html',\n      'unit/shady-events.html',\n      'unit/shady-content.html',\n      'unit/shady-dynamic.html',\n      'unit/shady-dynamic.html?syncInitialRender=true',\n      'unit/styling-scoped.html',\n      'unit/styling-cross-scope-var.html',\n      'unit/styling-cross-scope-apply.html',\n      'unit/styling-cross-scope-unknown-host.html',\n      'unit/styling-only-with-template.html',\n      'unit/styling-build-adopted-stylesheets.html',\n      'unit/custom-style.html',\n      'unit/custom-style-late.html',\n      'unit/custom-style-async.html',\n      'unit/custom-style-scope-cache.html',\n      'unit/events.html',\n      'unit/template-whitespace.html',\n      'unit/resolveurl.html',\n      'unit/case-map.html',\n      'unit/configure.html',\n      'unit/ready-attached-order.html',\n      'unit/ready-attached-order-class.html',\n      'unit/attributes.html',\n      'unit/async.html',\n      'unit/behaviors.html',\n      'unit/behaviors.html?legacyOptimizations=true',\n      'unit/polymer.element.html',\n      'unit/polymer.properties-mixin.html',\n      'unit/polymer.properties-mixin-with-property-accessors.html',\n      'unit/polymer.legacyelement.html',\n      'unit/debounce.html',\n      'unit/inheritance.html',\n      'unit/path.html',\n      'unit/templatize.html',\n      'unit/dom-repeat.html',\n      'unit/dom-repeat.html?removeNestedTemplates=true',\n      'unit/dom-if.html',\n      'unit/dom-if.html?removeNestedTemplates=true',\n      'unit/dom-if.html?fastDomIf=true',\n      'unit/dom-if.html?removeNestedTemplates=true&fastDomIf=true',\n      'unit/dom-bind.html',\n      'unit/array-selector.html',\n      'unit/polymer-dom.html',\n      // Forced to `noPatch` here to workaround\n      // https://github.com/webcomponents/polyfills/issues/250.\n      'unit/polymer-dom-nopatch.html?wc-noPatch=true',\n      'unit/polymer-dom-observeNodes.html',\n      'unit/flattened-nodes-observer.html',\n      // TODO: substitute for equivalent es6 import tests\n      // 'unit/importHref.html',\n      // 'unit/dynamic-import.html',\n      'unit/gestures.html',\n      'unit/logging.html',\n      'unit/mixin-utils.html',\n      'unit/mixin-behaviors.html',\n      'unit/render-status.html',\n      'unit/dir.html',\n      'unit/disable-upgrade.html',\n      'unit/shady-unscoped-style.html',\n      'unit/html-tag.html',\n      'unit/legacy-data.html',\n      'unit/legacy-undefined.html',\n      'unit/legacy-noattributes.html',\n      // 'unit/multi-style.html'\n      'unit/class-properties.html',\n      'unit/styling-scoped-nopatch.html'\n    ];\n\n    function combinations(suites, flags) {\n      return flags.map((f) => {\n        return f ? suites.map(s => `${s}${s.match(/\\?/) ? '&' : '?'}${f}`) : suites;\n      }).reduce((arr, s) => arr.concat(s), []);\n    }\n\n    function addUrlOption(previous = '', next = '') {\n      return previous + (previous ? '&' : '') + next;\n    }\n\n    // test shadowdom/custom elements polyfills together\n    // preferring both if possible.\n    let flags = [''];\n    if (window.customElements) {\n      // NOTE: disabled because Native ShadowDOM and Polyfilled CustomElements is not an expected use-case.\n      // flags.push('wc-ce=true');\n    }\n    // if native is available, make sure to test polyfill\n    if (Element.prototype.attachShadow && Node.prototype.getRootNode) {\n      flags.push('wc-shadydom=true');\n    }\n    // Both sd and ce are supported, force both polyfills\n    if (flags.length === 2) {\n      // ce + sd becomes a single test iteration.\n      flags.push('wc-ce=true&wc-shadydom=true');\n    }\n\n    // economize testing by testing css shimming\n    // only against 1 environment (native or polyfill).\n    if (window.CSS && CSS.supports && CSS.supports('box-shadow', '0 0 0 var(--foo)')) {\n      // Note: Disabled to speed up testing, may be reenabled at a later date when the test timing is less of an issue.\n      // let last = flags.length === 1 ? '' : flags[flags.length - 1];\n      // flags.push(addUrlOption(last, 'wc-shimcssproperties=true'));\n    }\n    suites = combinations(suites, flags);\n    console.log('Testing suites:\\n\\t' + suites.join('\\n\\t'));\n\n    WCT.loadSuites(suites);\n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "test/smoke/alacarte-property-accessors.html",
    "content": "<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"width=device-width\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js\"></script>\n  <script type=\"module\" src=\"../../lib/mixins/property-accessors.js\"></script>\n</head>\n<body>\n\n<script type=\"module\">\nimport { PropertyAccessors } from '../../lib/mixins/property-accessors.js';\n\n// Apply mixins to base class\nclass MyElement extends PropertyAccessors(HTMLElement) {\n\n  // Declare observed attributes\n  static get observedAttributes() { return ['foo', 'bar']; }\n\n  // Enable accessors and flush any queued property changes\n  connectedCallback() {\n    this._enableProperties();\n  }\n\n  // React to changes\n  _propertiesChanged(currentProps, changedProps, oldProps) {\n    for (let p in changedProps) {\n      this.innerHTML += `${p}: ${changedProps[p]}<br>`;\n    }\n  }\n\n}\n\n// Generate property accessors for all observed attributes\nMyElement.createPropertiesForAttributes();\n\n// Register element\ncustomElements.define('my-element', MyElement);\n</script>\n\n<my-element foo=\"5\" bar=\"10\"></my-element>\n\n<script type=\"module\">\nimport '../../lib/mixins/property-accessors.js';\ndocument.querySelector('my-element').foo = 20;\n</script>\n\n</body>\n</html>"
  },
  {
    "path": "test/smoke/alacarte-property-effects-ordering.html",
    "content": "<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"width=device-width\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js\"></script>\n  <script type=\"module\" src=\"../../polymer-element.js\"></script>\n</head>\n<body>\n\n<template id=\"my-element-template\">\n  <style>\n     :host {\n       display: block;\n     }\n    #counter {\n      padding: 10px;\n      background: lightblue;\n    }\n  </style>\n  <!-- can use declarative event listeners -->\n  <button on-click=\"handleIncrement\">Increment!</button>\n  <span id=\"counter\">[[limited]]</span>\n  <x-a prop=\"[[limited]]\"></x-a>\n  <x-b></x-b>\n</template>\n\n<script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nimport { PropertyEffects } from '../../lib/mixins/property-effects.js';\n\ncustomElements.define('x-a', class extends PolymerElement {\n  static get observers() { return ['propChanged(prop)']; }\n  constructor() {\n    super();\n    this.prop = 99;\n  }\n  propChanged(prop) {\n    console.log(this.localName, 'propChanged', prop);\n    this.textContent = prop;\n  }\n  ready() {\n    super.ready();\n    console.log(this.localName, 'ready');\n  }\n});\n\ncustomElements.define('x-b', class extends PolymerElement {\n  static get observers() { return ['propChanged(prop)']; }\n  constructor() {\n    super();\n    this.prop = 77;\n  }\n  propChanged(prop) {\n    console.log(this.localName, 'propChanged', prop);\n    this.textContent = prop;\n  }\n  ready() {\n    super.ready();\n    console.log(this.localName, 'ready');\n  }\n});\n\nlet template = document.getElementById('my-element-template');\n\n// Apply mixins to base class\nlet MyBaseClass = PropertyEffects(HTMLElement);\n\nclass MyElement extends MyBaseClass {\n\n  // Declare observed attributes\n  static get observedAttributes() { return ['counter', 'limit']; }\n\n  constructor() {\n    super();\n    this.counter = 0;\n    this.limit = Infinity;\n  }\n\n  // Enable accessors and flush any queued property changes\n  connectedCallback() {\n    this._enableProperties();\n  }\n\n  // Called once by PropertyAccessors during first property flush\n  // Do one-time work like setting up Shadow DOM\n  ready() {\n    console.log(this.localName, 'before ready');\n    this.dom = this._stampTemplate(template);\n    super.ready();\n    console.log(this.localName, 'after ready');\n  }\n\n  _readyClients() {\n    this.attachShadow({mode: 'open'}).appendChild(this.dom);\n    super._readyClients();\n  }\n\n  computeLimited(counter, limit) {\n    return Math.min(counter, limit);\n  }\n\n  handleIncrement() {\n    this.counter++;\n  }\n\n}\n\n// Generate property accessors for all observed attributes\nMyElement.createComputedProperty('limited', 'computeLimited(counter, limit)');\nMyElement.bindTemplate(template);\n\n// Register element\ncustomElements.define('my-element', MyElement);\n</script>\n\n\n<my-element counter=\"10\" limit=\"20\"></my-element>\n\n</body>\n</html>"
  },
  {
    "path": "test/smoke/alacarte-property-effects.html",
    "content": "<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"width=device-width\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js\"></script>\n  <script type=\"module\" src=\"../../lib/mixins/property-effects.js\"></script>\n</head>\n<body>\n\n<template id=\"my-element-template\">\n  <style>\n     :host {\n       display: block;\n     }\n    #counter {\n      padding: 10px;\n      background: lightblue;\n    }\n  </style>\n  <!-- can use declarative event listeners -->\n  <button on-click=\"handleIncrement\">Increment!</button>\n  <span id=\"counter\">[[limited]]</span>\n</template>\n\n<script type=\"module\">\nimport { PropertyEffects } from '../../lib/mixins/property-effects.js';\n\nlet template = document.getElementById('my-element-template');\n\nclass MyElement extends PropertyEffects(HTMLElement) {\n\n  // Declare observed attributes\n  static get observedAttributes() { return ['counter', 'limit']; }\n\n  constructor() {\n    super();\n    this.counter = 0;\n    this.limit = Infinity;\n  }\n\n  // Enable accessors and flush any queued property changes\n  connectedCallback() {\n    this._enableProperties();\n  }\n\n  // Called once by PropertyAccessors during first property flush\n  // Do one-time work like setting up Shadow DOM\n  ready() {\n    this.dom = this._stampTemplate(template);\n    this.attachShadow({mode: 'open'}).appendChild(this.dom);\n    super.ready();\n  }\n\n  computeLimited(counter, limit) {\n    return Math.min(counter, limit);\n  }\n\n  handleIncrement() {\n    this.counter++;\n  }\n\n}\n\n// Generate property accessors for all observed attributes\nMyElement.createComputedProperty('limited', 'computeLimited(counter, limit)');\nMyElement.bindTemplate(template);\n\n// Register element\ncustomElements.define('my-element', MyElement);\n</script>\n\n\n<my-element counter=\"10\" limit=\"20\"></my-element>\n\n</body>\n</html>"
  },
  {
    "path": "test/smoke/alacarte-template-stamp.html",
    "content": "<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"width=device-width\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js\"></script>\n  <script type=\"module\" src=\"../../lib/mixins/property-accessors.js\"></script>\n  <script type=\"module\" src=\"../../lib/mixins/template-stamp.js\"></script>\n</head>\n<body>\n\n<template id=\"my-element-template\">\n  <style>\n     :host {\n       display: block;\n     }\n    #counter {\n      padding: 10px;\n      background: lightblue;\n    }\n  </style>\n  <!-- can use declarative event listeners -->\n  <button on-click=\"handleIncrement\">Increment!</button>\n  <span id=\"counter\"></span>\n</template>\n\n<script type=\"module\">\nimport { PropertyAccessors } from '../../lib/mixins/property-accessors.js';\nimport { TemplateStamp } from '../../lib/mixins/template-stamp.js';\n\n// Apply mixins to base class\nlet MyBaseClass =\n  TemplateStamp(\n    PropertyAccessors(\n      HTMLElement));\n\nclass MyElement extends MyBaseClass {\n\n  // Declare observed attributes\n  static get observedAttributes() { return ['counter', 'limit']; }\n\n  constructor() {\n    super();\n    this.counter = 0;\n    this.limit = Infinity;\n  }\n\n  // Enable accessors and flush any queued property changes\n  connectedCallback() {\n    this._enableProperties();\n  }\n\n  // Called once by PropertyAccessors during first property flush\n  // Do one-time work like setting up Shadow DOM\n  ready() {\n    let template = document.getElementById('my-element-template');\n    this.dom = this._stampTemplate(template);\n    this.attachShadow({mode: 'open'}).appendChild(this.dom);\n    super.ready();\n  }\n\n  // React to changes\n  _propertiesChanged(currentProps, changedProps, oldProps) {\n    // Can use this.$ to access id'ed nodes in template\n    this.dom.$.counter.textContent =\n      Math.min(currentProps.counter, currentProps.limit);\n  }\n\n  handleIncrement() {\n    this.counter++;\n  }\n\n}\n\n// Generate property accessors for all observed attributes\nMyElement.createPropertiesForAttributes();\n\n// Register element\ncustomElements.define('my-element', MyElement);\n</script>\n\n\n<my-element counter=\"10\" limit=\"20\"></my-element>\n\n</body>\n</html>"
  },
  {
    "path": "test/smoke/behavior-mixin.html",
    "content": " <!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->|\n<!DOCTYPE html>\n<html>\n<head>\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n</head>\n<body>\n\n<dom-module id=\"x-test\">\n  <template>\n    <div>behavior says: {{behaviorProp}}</div>\n    <div>element says: {{prop}}</div>\n  </template>\n</dom-module>\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nimport { DomModule } from '../../lib/elements/dom-module.js';\nimport { mixinBehaviors } from '../../lib/legacy/class.js';\n/** @polymerBehavior */\nvar MyBehavior = {\n  properties: {\n    behaviorProp: {\n      value: 'prop from behavior!',\n      observer: '_propChanged'\n    }\n  },\n  _propChanged: function(value) {\n    console.log(this.localName, '_propChanged', value);\n  },\n  ready: function() {\n    console.log(this.localName, 'MyBehavior.ready');\n  }\n}\n\n/** @polymerBehavior */\nvar MyBehavior2 = {\n  ready: function() {\n    console.log(this.localName, 'MyBehavior2.ready');\n  }\n}\n\nPolymer({\n  is: 'x-test',\n  behaviors: [MyBehavior],\n  properties: {\n    prop: {\n      value: 'prop from x-test'\n    }\n  },\n  ready: function() {\n    console.log(this.localName, 'x-test.ready');\n  }\n});\n\n// ***********\n\nvar XTest = customElements.get('x-test');\n\nclass XClass extends mixinBehaviors([MyBehavior, MyBehavior2], XTest) {\n  static get is() { return 'x-class'}\n\n  static get template() {\n    return DomModule.import('x-test', 'template');\n  }\n\n  static get config() {\n    return {\n      properties: {\n        prop: {\n          value: 'prop from x-class'\n        }\n      }\n    }\n  }\n  ready() {\n    super.ready();\n    console.log('x-class ready');\n  }\n}\n\ncustomElements.define(XClass.is, XClass);\n</script>\n\n<x-class></x-class>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/smoke/data-table.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <title>data-table</title>\n  <meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n</head>\n<body>\n\n  <script type=\"module\">\nwindow.emojiByType = {\n  a: '😎',\n  b: '💰',\n  c: '🚔',\n  d: '💕',\n  e: '👍',\n  f: '🍌'\n};\n</script>\n\n  <dom-module id=\"data-popup\">\n    <template strip-whitespace>\n      <style>\n        :host {\n          display: inline-block;\n          background: lightblue;\n          border-radius: 10px;\n          border-bottom-left-radius: 0;\n          border: 1px solid #aaa;\n          box-shadow: 3px 3px 5px #535353;\n          padding: 5px;\n          z-index: 1;\n        }\n      </style>\n      <slot></slot>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'data-popup'\n});\n</script>\n  </dom-module>\n\n  <dom-module id=\"data-cell\">\n    <template strip-whitespace>\n      <style>\n        :host {\n          flex: 1;\n          border: 2px solid #aaa;\n          padding: 5px;\n          position: relative;\n          background: #eee;\n        }\n        data-popup {\n          display: none;\n          position: absolute;\n          bottom: calc(100% - 15px);\n          left: calc(100% - 15px);\n        }\n        :host(:hover) data-popup {\n          display: inline-block;\n        }\n        :host([change=up]) {\n          background: #afa;\n        }\n        :host([change=down]) {\n          background: #faa;\n        }\n        .type {\n          display: inline-block;\n          border-radius: 100%;\n          box-sizing: border-box;\n          padding: 3px 0;\n          background: #aaa;\n          margin-right: 5px;\n          height: 30px;\n          width: 30px;\n          text-align: center;\n        }\n      </style>\n      <div class=\"type\">{{computeTypeIcon(type)}}</div>\n      {{toFixed(value)}}\n      <data-popup>{{value}}</data-popup>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'data-cell',\n  properties: {\n    type: {\n      type: String,\n      notify: true\n    },\n    value: {\n      type: Number,\n      notify: true\n    },\n    change: {\n      reflectToAttribute: true,\n      computed: 'computeChange(value)'\n    }\n  },\n  attached: function() {\n    this.fire('register-cell');\n  },\n  computeChange: function(value) {\n    var prev = this._prev;\n    this._prev = value;\n    return value > prev ? 'up' : (value < prev ? 'down' : 'none');\n  },\n  computeTypeIcon: function(type) {\n    return emojiByType[type];\n  },\n  toFixed: function(value) {\n    return Number(value).toFixed(2);\n  }\n});\n</script>\n  </dom-module>\n\n  <dom-module id=\"data-row\">\n    <template strip-whitespace>\n      <style>\n        :host {\n          display: flex;\n          flex-direction: row;\n        }\n        .title-cell {\n          flex: 1;\n        }\n        .title {\n          font-weight: bold;\n        }\n        .dominant {\n          font-size: 0.7em;\n        }\n      </style>\n      <div class=\"title-cell\">\n        <div class=\"title\">{{title}}</div>\n        <div class=\"dominant\">Dominant: {{computeDominant(cells.*)}}</div>\n      </div>\n      <template is=\"dom-repeat\" items=\"{{cells}}\" as=\"cell\">\n        <data-cell type=\"{{cell.type}}\" value=\"{{cell.value}}\"></data-cell>\n      </template>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'data-row',\n  properties: {\n    title: {\n      type: String,\n      notify: true\n    },\n    cells: {\n      type: Array,\n      notify: true\n    }\n  },\n  computeDominant: function(info) {\n    var types = this.types = info.base.reduce(function(map, i) {\n      return map[i.type] = (map[i.type] || 0) + 1, map;\n    }, {})\n    return emojiByType[Object.keys(types).sort(function(a, b) {\n      return types[b] - types[a];\n    })[0]];\n  }\n});\n</script>\n  </dom-module>\n\n  <dom-module id=\"data-table\">\n    <template strip-whitespace>\n      <style>\n        :host {\n          display: block;\n        }\n      </style>\n      Polymer: {{version}}<br>\n      <button on-tap=\"toggleRunning\">{{computeRunning(running)}}</button>\n      <input value-as-number=\"{{tables::input}}\" type=\"number\" style=\"width:35px;\" placeholder=\"tables\">\n      <input value-as-number=\"{{rows::input}}\" type=\"number\" style=\"width:35px;\" placeholder=\"rows\">\n      <input value-as-number=\"{{columns::input}}\" type=\"number\" style=\"width:35px;\" placeholder=\"columns\">\n      <br><br>\n      <select value=\"{{strategy::change}}\">\n        <option value=\"reset\">(Mutate in place x n), reset</option>\n        <option value=\"reset-each\">(Mutate in place, reset) x n</option>\n        <option value=\"path\">(Set path from top) x n</option>\n        <option value=\"path-leaf\">(Set path from leaf) x n</option>\n      </select>\n      n = <input value-as-number=\"{{mutations::input}}\" type=\"number\" style=\"width:35px;\">\n      <br><br>\n      <h3>FPS: {{fps}}</h3>\n      <h3>Op time: {{toFixed(optime, 2)}}</h3>\n      <div xhidden>\n        <template is=\"dom-repeat\" items=\"{{tableData}}\">\n          <h3>Table {{index}}:</h3>\n          <template is=\"dom-repeat\" items=\"{{data}}\" as=\"row\">\n            <data-row title=\"{{row.title}}\" cells=\"{{row.cells}}\"></data-row>\n          </template>\n        </template>\n      </div>\n    </template>\n    <script type=\"module\">\nimport { Polymer, version } from '../../lib/utils/boot.js';\nvar params = document.location.search.substring(1).split('&').map(p=>p.split('='))\n  .reduce((m, p)=>{return m[p[0]] = p[1], m;}, {});\nPolymer({\n  is: 'data-table',\n  properties: {\n    rows: {\n      type: Number,\n      value: Number(params.rows) || 6\n    },\n    columns: {\n      type: Number,\n      value: Number(params.columns) || 10\n    },\n    tables: {\n      type: Number,\n      value: Number(params.tables) || 2\n    },\n    mutations: {\n      type: Number,\n      value: Number(params.mutations) || 30\n    },\n    strategy: {\n      type: String,\n      value: params.strategy || 'reset'\n    },\n    running: {\n      type: Number,\n      value: params.running === 'false' ? false : true\n    },\n    tableData: {\n      computed: 'computeTableData(tables)'\n    },\n    optime: {\n      value: 0\n    }\n  },\n  observers: ['computeData(rows, columns)'],\n  created: function() {\n    this._fps = 0;\n    this.end = performance.now() + 1000;\n    var cells = this.cells = [];\n    this.addEventListener('register-cell', function(e) {\n      var cell = e.composedPath()[0];\n      cell.id = 'cell-' + cells.length;\n      cells.push(cell);\n    });\n  },\n  toggleRunning: function() {\n    this.running = !this.running;\n    if (this.running) {\n      this.go();\n    }\n  },\n  computeRunning: function(running) {\n    return running ? 'Pause' : 'Run';\n  },\n  computeData: function(rows, columns) {\n    var r = [];\n    for (var i=0; i<rows; i++) {\n      var c = [];\n      for (var j=0; j<columns; j++) {\n        c.push({\n          value: Math.random() * 10,\n          type: ['a','b','c','d','e','f'][Math.floor(Math.random()*6)]\n        });\n      }\n      r.push({\n        cells: c,\n        title: 'Row ' + i\n      })\n    }\n    this.data = r;\n  },\n  computeTableData: function(tables) {\n    return new Array(Number(tables));\n  },\n  toFixed: function(value, decimals) {\n    return value.toFixed(decimals);\n  },\n  ready: function() {\n    this.version = version || 'alacarte';\n    if (!this.setProperties) {\n      this.setProperties = function(props) {\n        for (var p in props) {\n          this.set(p, props[p]);\n        }\n      }\n    }\n    this.go();\n  },\n  go: function() {\n    var optime = 0;\n    for (var i=0; i<this.mutations; i++) {\n      var type = ['a','b','c','d','e','f'][Math.floor(Math.random()*6)];\n      var delta = (Math.random() > 0.5 ? -1 : 1) * (Math.random() * 5);\n      var row = Math.floor(Math.random() * this.rows);\n      var column = Math.floor(Math.random() * this.columns);\n      var d = this.data[row].cells[column];\n      if (this.strategy == 'reset' || this.strategy == 'reset-each') {\n        d.type = type;\n        d.value += delta;\n        if (this.strategy == 'reset-each') {\n          var start = performance.now();\n          this.set('data', this.data);\n          optime += (performance.now() - start);\n        }\n      } else if (this.strategy == 'path') {\n        var path = ['data', row, 'cells', column].join('.');\n        var props = {};\n        props[path + '.type'] = type;\n        props[path + '.value'] = d.value + delta;\n        var start = performance.now();\n        this.setProperties(props);\n        optime += (performance.now() - start);\n      } else if (this.strategy == 'path-leaf') {\n        var c = this.cells[Math.floor(this.cells.length * Math.random())];\n        var props = {\n          type: type,\n          value: c.value + delta\n        };\n        var start = performance.now();\n        c.setProperties(props);\n        optime += (performance.now() - start);\n      }\n    }\n    if (optime) {\n      this.optime = (this.optime * 9 + (optime / this.mutations)) / 10;\n      // this.optime = optime / this.mutations;\n    }\n    if (this.strategy == 'reset') {\n      var start = performance.now();\n      this.set('data', this.data);\n      this.optime = (this.optime * 9 + (performance.now() - start)) / 10;\n      // this.optime = performance.now() - start;\n    }\n    this._fps++;\n    if (performance.now() > this.end) {\n      this.fps = this._fps;\n      this._fps = 0;\n      this.end = performance.now() + 1000;\n    }\n    var self = this;\n    if (this.running) {\n      requestAnimationFrame(function() {\n        self.go();\n      });\n    }\n  }\n});\n</script>\n  </dom-module>\n\n  <data-table id=\"table\"></data-table>\n\n\n</body>\n</html>\n"
  },
  {
    "path": "test/smoke/dirty-check.html",
    "content": "<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<!DOCTYPE html>\n<html>\n<head>\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n</head>\n<body>\n\n<dom-module id=\"x-host\">\n  <template>\n    <h1>1 + [[foo]] = [[bar]]</h1>\n    <x-child id=\"child\" foo=\"[[foo]]\" bar=\"{{bar}}\"></x-child>\n  </template>\n\n  <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nclass XHost extends PolymerElement {\n  static get config() {\n    return {\n      properties: {\n        obj: {\n          observer: 'objChanged'\n        }\n      }\n    }\n  }\n  objChanged(val, old) {\n    console.log('new', val, 'old', old);\n  }\n  _shouldPropertyChange(prop, val, old) {\n    if (this.strict) {\n      return val !== old;\n    } else if (val instanceof Date) {\n      return !(old instanceof Date) || val.getTime() !== old.getTime();\n    } else {\n      return super._shouldPropertyChange(prop, val, old);\n    }\n  }\n}\ncustomElements.define('x-host', XHost);\n</script>\n</dom-module>\n\n<x-host id=\"host\"></x-host>\n\n<script type=\"module\">\nvar obj = {foo: true};\nhost.obj = obj;\nhost.obj = obj;\nconsole.log('strict on')\nhost.strict = true;\nhost.obj = obj;\nconsole.log('strict off')\nhost.strict = false;\nhost.obj = obj;\nhost.obj = new Date();\nhost.obj = new Date(host.obj.getTime());\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/smoke/disable-upgrade.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n  <script type=\"module\" src=\"../../lib/mixins/disable-upgrade-mixin.js\"></script>\n</head>\n<body>\n  <script type=\"module\">\nimport { DisableUpgradeMixin } from '../../lib/mixins/disable-upgrade-mixin.js';\nconst ogDefine = window.customElements.ogDefine = window.customElements.define;\nwindow.customElements.defineWithDisabled = function(name, constructor) {\n  return ogDefine.call(customElements, name,\n    DisableUpgradeMixin(constructor));\n}\nwindow.customElements.define = window.customElements.defineWithDisabled;\n</script>\n\n  <dom-module id=\"x-disabled\">\n\n    <template>\n      <style>\n        :host {\n          display: block;\n        }\n\n        h2 {\n          letter-spacing: 1em;\n        }\n      </style>\n      <h2>[[prop]]</h2>\n    </template>\n\n    <script type=\"module\">\nimport '../../lib/mixins/disable-upgrade-mixin.js';\nimport { PolymerElement } from '../../polymer-element.js';\nclass Disabled extends PolymerElement {\n  static get is() { return 'x-disabled'; }\n  static get properties() {\n    return {\n      prop: {\n        type: String\n      }\n    }\n  }\n  constructor() {\n    super();\n    this.prop = 'enabled!';\n  }\n}\ncustomElements.define(Disabled.is, Disabled);\n</script>\n\n  </dom-module>\n\n  <dom-module id=\"my-element\">\n\n    <template>\n      <style>\n        :host {\n          display: block;\n        }\n\n        button {\n          display: block;\n        }\n      </style>\n      <h3>x-disabled without disable-upgrade</h3>\n      <x-disabled>Disabled</x-disabled>\n      <h3>x-disabled with disable-upgrade</h3>\n      <x-disabled id=\"disabled\" disable-upgrade>Disabled</x-disabled>\n      <h3>x-disabled with disable-upgrade</h3>\n      <x-disabled disable-upgrade$=\"[[upgradeDisabled]]\">Disabled</x-disabled>\n      <button on-click=\"_enable\">Enable</button>\n    </template>\n\n    <script type=\"module\">\nimport '../../lib/mixins/disable-upgrade-mixin.js';\nimport { PolymerElement } from '../../polymer-element.js';\n\n\nclass MyElement extends PolymerElement {\n  static get is() { return 'my-element'; }\n  static get properties() {\n    return {\n      upgradeDisabled: {value: true}\n    }\n  }\n  _enable() {\n    this.$.disabled.removeAttribute('disable-upgrade');\n    this.upgradeDisabled = false;\n  }\n}\ncustomElements.define(MyElement.is, MyElement);\n</script>\n\n  </dom-module>\n\n  <my-element></my-element>\n\n</body>\n</html>"
  },
  {
    "path": "test/smoke/disabled-attr-gestures.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2018 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n</head>\n<body>\n  <dom-module id=\"x-disabled\">\n    <template>\n      <button id=\"disabledbutton\" on-tap=\"tap\" disabled>Disabled Button</button>\n      <div disabled>\n        <button id=\"nestedbutton\" on-tap=\"tap\">Nested Button</button>\n      </div>\n    </template>\n    <script type=\"module\">\nimport { GestureEventListeners } from '../../lib/mixins/gesture-event-listeners.js';\nimport { PolymerElement } from '../../polymer-element.js';\nclass XDisabled extends GestureEventListeners(PolymerElement) {\n  static get is() {return 'x-disabled';}\n  tap(e) {\n    console.log(`${e.composedPath()[0].id} tapped`);\n  }\n}\ncustomElements.define(XDisabled.is, XDisabled);\n</script>\n  </dom-module>\n  <x-disabled></x-disabled>\n</body>\n</html>"
  },
  {
    "path": "test/smoke/dom-if.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n</head>\n<body>\n\n\n  <dom-module id=\"my-element\">\n    \n    <template>\n      <style>\n        :host {\n          display: block;\n        }\n        .parent {\n          border: 1px solid red;\n          justify-content: space-between;\n          width: 300px;\n          display: flex;\n        }\n        .child {\n          border: 1px solid green;\n          width: 100px;\n        }\n      </style>\n      <div class='parent'>\n        <div class='child'>Child1</div>        \n        <template is='dom-if' if='1'>\n          <div class='child'>Child2</div>\n        </template>\n      </div>\n    </template>\n\n   \n    <!-- Uncomment for class syntax -->\n    <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nclass MyElement extends PolymerElement {\n  static get is() { return 'my-element'; }\n  static get properties() {\n    return {\n      prop: {\n        type: String\n      }\n    }\n  }\n  constructor() {\n    super();\n    this.prop = 'my-element'\n  }\n}\ncustomElements.define(MyElement.is, MyElement);\n</script>\n    \n  </dom-module>\n\n  <my-element></my-element>\n  \n</body>\n</html>"
  },
  {
    "path": "test/smoke/gestures.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<!--\n  Port of https://github.com/Polymer/polymer/issues/4211\n  Credit @MartinsThiago\n-->\n<html>\n<head>\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n  <link rel=\"import\" href=\"https://cdn.rawgit.com/PolymerElements/iron-selector/2.0-preview/iron-selector.html\">\n</head>\n<body>\n\n  <style>\n    html {font-family: sans}\n    div {padding: 5px}\n    .iron-selected {background: deepskyblue}\n  </style>\n\n  <button onclick=\"console.log('works!')\">First click me</button>\n\n  <br>\n\n  <iron-selector>\n    <div>Click on me \\o/ 1</div>\n    <div>Click on me \\o/ 2</div>\n    <div>Click on me \\o/ 3</div>\n    <div>Click on me \\o/ 4</div>\n    <div>Click on me \\o/ 5</div>\n  </iron-selector>\n\n  <button onclick=\"console.log('This is working after a few clicks')\">Click last</button>\n\n  <script type=\"module\">\nimport { version } from '../../lib/utils/boot.js';\nconsole.log(\"Using: \" + version);\nconsole.log(\"Ready to start bug demo\");\n</script>\n</body>\n</html>"
  },
  {
    "path": "test/smoke/html-tag.html",
    "content": "<!DOCTYPE html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js\"></script>\n  <script type=\"module\" src=\"../../polymer-element.js\"></script>\n</head>\n<body>\n  <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nimport { html } from '../../lib/utils/html-tag.js';\n\nclass SuperClass extends PolymerElement {\n  static get is() {return 'super-class';}\n  static get template() {\n    return html`\n      <style>#name {color: red}</style>\n      <h3 id=\"name\">${this.is}</h3>\n      <div>${this.headerTemplate}</div>\n      [[myProp.stuffThatGoesHere]]\n      <div>${this.footerTemplate}</div>\n    `;\n  }\n  static get headerTemplate() { return html`<h1>Header</h1>`; }\n  static get footerTemplate() { return html`<h1>Footer</h1>`; }\n}\ncustomElements.define(SuperClass.is, SuperClass);\nclass SubClass extends SuperClass {\n  static get is() {return 'sub-class';}\n  static get template() {\n    return html`\n      <style>.frame {font-style: italic}</style>\n      <div class=\"frame\">${super.template}</div>\n      <div>\\</div>\n    `;\n  }\n  constructor() {\n    super();\n    this.myProp = {stuffThatGoesHere: '!stuff that goes here!'};\n  }\n  static get headerTemplate() { return html`<h2>Sub-header</h2>`; }\n  static get footerTemplate() { return html`<h2>Sub-footer</h2>`; }\n}\ncustomElements.define(SubClass.is, SubClass);\n</script>\n  <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nclass XString extends PolymerElement {\n  static get is() {return 'x-string'};\n  static get template() {\n    return 'string template!';\n  }\n}\ncustomElements.define(XString.is, XString);\n</script>\n  <super-class></super-class>\n  <sub-class></sub-class>\n  <x-string></x-string>\n</body>\n"
  },
  {
    "path": "test/smoke/label-click.html",
    "content": "<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<!DOCTYPE html>\n<html>\n\n<head>\n  <meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"width=device-width\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n</head>\n\n<body>\n  <label id=\"label\" for=\"checkme\">Native checkbox</label>\n  <input type=\"checkbox\" id=\"checkme\">\n</body>\n\n</html>"
  },
  {
    "path": "test/smoke/ordering-test.html",
    "content": "<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"width=device-width\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n</head>\n<body>\n\n<script type=\"module\">\nimport { PolymerElement, html } from '../../polymer-element.js';\nclass XA extends PolymerElement {\n  static get template() {\n    return html`<x-b prop=\"[[prop]]\"></x-b>`;\n  }\n  static get observers() { return ['propChanged(prop)']}\n  propChanged() {\n    console.log(this.localName, 'propChanged', this.shadowRoot);\n  }\n  constructor() {\n    console.log('x-a', 'constructed');\n    super();\n    this.childList = [];\n    this.addEventListener('child-is-here', e => {\n      let target = e.composedPath()[0];\n      if (target !== this) {\n        this.childList.push(target);\n      }\n    });\n    this.prop = 'prop';\n  }\n  connectedCallback() {\n    console.group(this.localName, 'connected');\n    console.warn(this.localName, 'connected (user)', this.shadowRoot);\n    super.connectedCallback();\n    console.groupEnd(this.localName, 'connected');\n  }\n  _flushProperties() {\n    console.log(this.localName, 'flush');\n    super._flushProperties();\n  }\n  ready() {\n    console.group(this.localName, 'ready');\n    super.ready();\n    console.warn(this.localName, 'ready (user)', this.shadowRoot);\n    console.log(this.localName, 'childList', this.childList);\n    console.groupEnd(this.localName, 'ready');\n  }\n}\ncustomElements.define('x-a', XA);\n\nclass XB extends PolymerElement {\n  static get template() {\n    return `<x-c prop=\"[[prop]]\"></x-c>`;\n  }\n  static get observers() { return ['propChanged(prop)']}\n  propChanged() {\n    console.log(this.localName, 'propChanged', this.shadowRoot);\n  }\n  constructor() {\n    console.log('x-b', 'constructed');\n    super();\n    this.childList = [];\n    this.addEventListener('child-is-here', e => {\n      let target = e.composedPath()[0];\n      if (target !== this) {\n        this.childList.push(target);\n      }\n    });\n  }\n  connectedCallback() {\n    console.group(this.localName, 'connected');\n    console.warn(this.localName, 'connected (user)', this.shadowRoot);\n    super.connectedCallback();\n    console.groupEnd(this.localName, 'connected');\n  }\n  _flushProperties() {\n    console.log(this.localName, 'flush');\n    super._flushProperties();\n  }\n  ready() {\n    console.group(this.localName, 'ready');\n    this.dispatchEvent(new CustomEvent('child-is-here', {bubbles: true, composed: true}));\n    super.ready();\n    console.warn(this.localName, 'ready (user)', this.shadowRoot);\n    console.log(this.localName, 'childList', this.childList);\n    console.groupEnd(this.localName, 'ready');\n  }\n}\ncustomElements.define('x-b', XB);\n\nclass XC extends PolymerElement {\n  static get template() {\n    return html`<div></div>`;\n  }\n  static get observers() { return ['propChanged(prop)']}\n  propChanged() {\n    console.log(this.localName, 'propChanged', this.shadowRoot);\n  }\n  constructor() {\n    console.log('x-c', 'constructed');\n    super();\n    this.childList = [];\n  }\n  connectedCallback() {\n    console.group(this.localName, 'connected');\n    console.warn(this.localName, 'connected (user)', this.shadowRoot);\n    super.connectedCallback();\n    console.groupEnd(this.localName, 'connected');\n  }\n  _flushProperties() {\n    console.log(this.localName, 'flush');\n    super._flushProperties();\n  }\n  ready() {\n    console.group(this.localName, 'ready');\n    this.dispatchEvent(new CustomEvent('child-is-here', {bubbles: true, composed: true}));\n    super.ready();\n    console.warn(this.localName, 'ready (user)', this.shadowRoot);\n    console.groupEnd(this.localName, 'ready');\n  }\n}\ncustomElements.define('x-c', XC);\n</script>\n\n<x-a></x-a>\n\n</body>\n</html>"
  },
  {
    "path": "test/smoke/passive-gestures.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n  <script type=\"module\">\nimport { setPassiveTouchGestures } from '../../lib/utils/settings.js';\nsetPassiveTouchGestures(true);\n</script>\n  <style>\n    html, body {\n      margin: 0;\n      padding: 0;\n    }\n  </style>\n</head>\n<body>\n  <dom-module id=\"x-passive\">\n    <template>\n      <style>\n        :host {\n          display: block;\n          height: 2000px;\n          background-color: -webkit-gradient(linear, left top, left bottom, from(blue), to(red));\n          background-image: -webkit-linear-gradient(top, blue, red);\n          background-image: -moz-linear-gradient(top, blue, red);\n          background-image: linear-gradient(to bottom, blue, red);\n        }\n      </style>\n    </template>\n  </dom-module>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-passive',\n  listeners: {\n    'down': 'prevent',\n    'move': 'prevent',\n    'up': 'prevent',\n    'tap': 'allowed',\n    'click': 'allowed'\n  },\n  prevent(e) {\n    e.preventDefault();\n    console.log('prevented?: ' + e.type + ' ' + e.defaultPrevented);\n  },\n  allowed(e) {\n    console.log(e.type + ' allowed');\n  }\n});\n</script>\n  <x-passive></x-passive>\n</body>\n</html>\n"
  },
  {
    "path": "test/smoke/style-props/src/elements-defaults.js",
    "content": "const $_documentContainer = document.createElement('div');\n$_documentContainer.setAttribute('style', 'display: none;');\n\n$_documentContainer.innerHTML = `<style is=\"custom-style\">\n  html {\n    --x-s: {\n      display: inline-block;\n      margin: 16px;\n      border-radius: 4px;\n      padding: 2px;\n    };\n  }\n</style>`;\n\ndocument.head.appendChild($_documentContainer);\n"
  },
  {
    "path": "test/smoke/style-props/src/elements.js",
    "content": "import './elements-defaults.js';\nimport { Polymer } from '../../../../lib/legacy/polymer-fn.js';\nimport { html } from '../../../../lib/utils/html-tag.js';\nPolymer({\n  _template: html`\n    <style include=\"simple-layout-styles\">\n      :host {\n        transform: rotate(-45deg);\n        -webkit-transform: rotate(-45deg);\n        background-color: lightblue;\n        @apply(--x-s);\n      }\n\n      .container {\n        height: 100px;\n        width: 100px;\n      }\n\n      section {\n        box-sizing: border-box;\n        margin: 1px;\n        width: 48px;\n        height: 48px;\n        border: 1px solid black;\n        border-radius: 4px;\n      }\n\n      .header {\n        @apply(--s-header);\n      }\n\n      .a {\n        background-color: var(--a, #eee);\n      }\n\n      .b {\n        background-color: var(--b, #eee);\n      }\n\n      .c {\n        background-color: var(--c, #eee);\n      }\n\n      .d {\n        background: -webkit-linear-gradient(top right, #777, white);\n      }\n    </style>\n    <div class=\"header\">x-s</div>\n    <div class=\"container horizontal wrap layout\">\n      <section class=\"center-center horizontal layout a\">--a</section>\n      <section class=\"center-center horizontal layout b\">--b</section>\n      <section class=\"center-center horizontal layout c\">--c</section>\n      <section class=\"d\"></section>\n    </div>\n`,\n\n  is: 'x-s'\n});\nPolymer({\n  _template: html`\n    <style include=\"simple-layout-styles\">\n      :host {\n        background-color: goldenrod;\n        transform: var(--ss-transform);\n        -webkit-transform: var(--ss-transform);\n        @apply(--x-s);\n      }\n\n      .container {\n        height: 100px;\n        width: 50px;\n      }\n\n      section {\n        box-sizing: border-box;\n        width: 48px;\n        height: 48px;\n        margin: 1px;\n        border: 1px solid black;\n        border-radius: 4px;\n      }\n\n      .header {\n        @apply(--s-header);\n      }\n\n      .a {\n        background-color: var(--a, #eee);\n      }\n\n      .b {\n        background: -webkit-linear-gradient(top right, #777, white);\n      }\n\n    </style>\n    <div class=\"header\">x-ss</div>\n    <div class=\"container horizontal wrap layout\">\n      <section class=\"center-center horizontal layout a\">--a</section>\n      <section class=\"center-center horizontal layout b\"></section>\n    </div>\n`,\n\n  is: 'x-ss'\n});\n"
  },
  {
    "path": "test/smoke/style-props/src/scopes.js",
    "content": "import './settings.js';\nimport './elements.js';\nimport { Polymer } from '../../../../lib/legacy/polymer-fn.js';\nimport { html } from '../../../../lib/utils/html-tag.js';\nimport { dom } from '../../../../lib/legacy/polymer.dom.js';\n\nPolymer({\n  _template: html`\n    <style>\n\n      :host {\n        border: 2px solid #ddd;\n        background-color: #e5e5e5;\n        border-radius: 8px;\n        margin: 16px;\n        padding: 16px;\n        position: relative;\n        min-height: 240px;\n        --c: var(--cc);\n      }\n\n      .header {\n        @apply(--header);\n      }\n\n      x-setting.c {\n        @apply(--left-setting);\n      }\n\n      x-setting.cc {\n        position: absolute;\n        left: 56px;\n        top: 14px;\n      }\n\n    </style>\n    <div class=\"header\">x-view2</div>\n    <x-setting class=\"c\">--c</x-setting>\n    <x-setting class=\"cc\">--cc</x-setting>\n    <x-s></x-s>\n`,\n\n  is: 'x-view2'\n});\n\nPolymer({\n  _template: html`\n    <style include=\"simple-layout-styles\">\n\n      :host {\n        border: 2px solid #ddd;\n        background-color: #f1f1f1;\n        border-radius: 8px;\n        margin: 16px;\n        padding: 16px;\n        position: relative;\n        --b: steelblue;\n        --c: purple;\n      }\n\n      .header {\n        @apply(--header);\n      }\n\n      x-setting.b {\n        @apply(--left-setting);\n      }\n\n      x-setting.c {\n        position: absolute;\n        left: 64px;\n        top: 14px;\n      }\n\n    </style>\n    <div class=\"header\">x-view1</div>\n    <x-setting class=\"b\">--b</x-setting>\n    <x-setting class=\"c\">--c</x-setting>\n    <div class=\"horizontal layout center-center flex\">\n      <x-s></x-s>\n    </div>\n    <x-view2 class=\"horizontal layout center-center flex\"></x-view2>\n`,\n\n  is: 'x-view1'\n});\n\nPolymer({\n  _template: html`\n    <style include=\"simple-layout-styles\">\n\n      :host {\n        font-family: sans-serif;\n        display: block;\n        border: 2px solid #ddd;\n        background-color: #fafafa;\n        border-radius: 8px;\n        margin: 16px;\n        padding: 16px;\n        position: relative;\n        --a: red;\n        --cc: yellow;\n\n        --header: {\n          position: absolute;\n          top: 2px;\n          left: 2px;\n        };\n        --left-setting: {\n          position: absolute;\n          left: 4px;\n          top: 14px;\n        };\n        --s-header: {\n          font-size: 10px;\n          font-weight: bold;\n        };\n      }\n\n      .header {\n        @apply(--header);\n      }\n\n      x-setting.a {\n        @apply(--left-setting);\n      }\n\n      x-setting.cc {\n        position: absolute;\n        left: 64px;\n        top: 14px;\n      }\n\n      .container {\n        margin: 16px;\n        padding: 16px;\n      }\n\n      .ss-c {\n        margin: 12px;\n        --ss-transform: rotate(30deg);\n      }\n\n      @media(min-width: 800px) {\n        .ss-c {\n          --ss-transform: rotate(-30deg);\n        }\n      }\n\n    </style>\n    <div class=\"header\">x-app</div>\n    <x-setting class=\"a\">--a</x-setting>\n    <x-setting class=\"cc\">--cc</x-setting>\n\n    <div class=\"horizontal layout\">\n      <div class=\"container flex horizontal center-center layout\">\n        <x-s></x-s>\n      </div>\n\n      <x-view1 class=\"flex-2 horizontal center-center layout\"></x-view1>\n\n    </div>\n\n    <div class=\"container horizontal layout wrap\">\n      <template is=\"dom-repeat\" items=\"{{items}}\">\n        <div class=\"horizontal layout\">\n          <span>{{item.index}}</span>\n          <x-ss class=\"ss-c\"></x-ss>\n        </div>\n      </template>\n    </div>\n`,\n\n  is: 'x-app',\n\n  listeners: {\n    'setting-change': 'settingChange'\n  },\n\n  properties: {\n    items: {\n      value: function() {\n        var items = [];\n        for (var i = 0; i < 250; i++) {\n          items.push({index: i});\n        }\n        return items;\n      }\n    }\n  },\n\n  clickHandler: function() {\n    d = document.createElement('div');\n    d.innerHTML = 'Added!';\n    var children = dom(this.root).childNodes;\n    var ref = children[Math.floor(children.length * Math.random(children.length))];\n    var ref = children[0];\n  },\n\n  settingChange: function(e) {\n    var target = e.composedPath()[0];\n    var host = target.getRootNode().host;\n    const obj = {};\n    obj[target.setting] = 'rgb(' +\n      Math.round(Math.random() * 255) + ',' +\n      Math.round(Math.random() * 255) + ',' +\n      Math.round(Math.random() * 255) + ')';\n    console.time('updateStyles');\n    host.updateStyles(obj);\n    document.body.offsetWidth;\n    console.timeEnd('updateStyles');\n  }\n});\n"
  },
  {
    "path": "test/smoke/style-props/src/settings.js",
    "content": "import { Polymer } from '../../../../lib/legacy/polymer-fn.js';\nimport { html } from '../../../../lib/utils/html-tag.js';\nconst $_documentContainer = document.createElement('div');\n$_documentContainer.setAttribute('style', 'display: none;');\n\n$_documentContainer.innerHTML = `<dom-module id=\"simple-layout-styles\">\n  <template>\n    <style>\n      .horizontal.layout {\n        display: flex;\n      }\n\n      .flex {\n        flex: 1;\n      }\n\n      .flex-2 {\n        flex: 2;\n      }\n\n      .center-center {\n        justify-content: center;\n        align-items: center;\n      }\n\n      .wrap {\n        flex-wrap: wrap;\n      }\n    </style>\n  </template>\n</dom-module>`;\n\ndocument.head.appendChild($_documentContainer);\nPolymer({\n  _template: html`\n    <style include=\"simple-layout-styles\">\n    :host {\n      margin: 4px;\n      display: block;\n      -webkit-user-select: none;\n      user-select: none;\n      cursor: pointer;\n      transform: skewX(160deg);\n      -webkit-transform: skewX(160deg);\n    }\n\n    section {\n      box-sizing: border-box;\n      margin: 1px;\n      padding: 4px 16px;\n      border: 1px solid black;\n      border-radius: 4px;\n    }\n\n    .setting {\n      background-color: var(--setting-color, #eee);\n    }\n\n  </style>\n    <section class=\"center-center horizontal layout setting\"><slot></slot></section>\n`,\n\n  is: 'x-setting',\n\n  listeners: {\n    click: 'clickHandler'\n  },\n\n  ready: function() {\n    this.setting = this.textContent;\n    const obj = {\n      '--setting-color': 'var(' + this.setting + ')'\n    }\n    this.updateStyles(obj);\n  },\n\n  clickHandler: function() {\n    this.fire('setting-change', this.setting);\n  }\n});\n"
  },
  {
    "path": "test/smoke/style-props/test.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <title>style properties</title>\n  <meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <script src=\"../../../node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js\"></script>\n  <script type=\"module\" src=\"../../../polymer-legacy.js\"></script>\n  <script type=\"module\" src=\"./src/scopes.js\"></script>\n</head>\n<body>\n  <script type=\"module\">\nimport '../../../polymer-legacy.js';\nimport './src/scopes.js';\nconsole.time('rendered');\n</script>\n  <x-app></x-app>\n  <script type=\"module\">\nimport '../../../polymer-legacy.js';\nimport './src/scopes.js';\nimport { flush } from '../../../lib/utils/flush.js';\nflush();\ndocument.body.offsetWidth;\nconsole.timeEnd('rendered');\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/array-selector-elements.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport { Polymer } from '../../lib/legacy/polymer-fn.js';\n\nPolymer({\n  is: 'observe-el',\n  observers: [\n    'singleChanged(singleSelected.*)',\n    'multiChanged(multiSelected.*)'\n  ],\n  singleChanged: function() {},\n  multiChanged: function() {}\n});\n"
  },
  {
    "path": "test/unit/array-selector.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n  <script type=\"module\" src=\"./array-selector-elements.js\"></script>\n<body>\n\n<test-fixture id=\"singleConfigured\">\n  <template>\n    <array-selector\n      items='[{\"name\": \"one\"},{\"name\": \"two\"},{\"name\": \"three\"}]'>\n    </array-selector>\n  </template>\n</test-fixture>\n\n<test-fixture id=\"multiConfigured\">\n  <template>\n    <array-selector multi\n      items='[{\"name\": \"one\"},{\"name\": \"two\"},{\"name\": \"three\"}]'>\n    </array-selector>\n  </template>\n</test-fixture>\n\n<test-fixture id=\"bind\">\n  <template>\n    <dom-bind>\n      <template>\n        <observe-el id=\"observer\" single-selected=\"{{singleSelected}}\" multi-selected=\"{{multiSelected}}\"></observe-el>\n        <array-selector id=\"singleBound\" items=\"{{items}}\" selected=\"{{singleSelected}}\"></array-selector>\n        <array-selector id=\"multiBound\" items=\"{{items}}\" selected=\"{{multiSelected}}\" multi></array-selector>\n      </template>\n    </dom-bind>\n  </template>\n</test-fixture>\n\n<script type=\"module\">\nimport './array-selector-elements.js';\nsuite('single selection', function() {\n\n  test('single selection', function() {\n    var el = fixture('singleConfigured');\n    // Nothing selected\n    assert.strictEqual(el.selected, null);\n    assert.strictEqual(el.selectedItem, null);\n    assert.isFalse(el.isSelected(el.items[0]));\n    assert.isFalse(el.isSelected(el.items[1]));\n    assert.isFalse(el.isSelected(el.items[2]));\n    // Select 0\n    el.select(el.items[0]);\n    assert.strictEqual(el.selected, el.items[0]);\n    assert.strictEqual(el.selectedItem, el.items[0]);\n    assert.isTrue(el.isSelected(el.items[0]));\n    assert.isFalse(el.isSelected(el.items[1]));\n    assert.isFalse(el.isSelected(el.items[2]));\n    // Re-select 0\n    el.select(el.items[0]);\n    assert.strictEqual(el.selected, el.items[0]);\n    assert.strictEqual(el.selectedItem, el.items[0]);\n    assert.isTrue(el.isSelected(el.items[0]));\n    assert.isFalse(el.isSelected(el.items[1]));\n    assert.isFalse(el.isSelected(el.items[2]));\n    // Select 2 (using index-based API)\n    el.selectIndex(2);\n    assert.strictEqual(el.selected, el.items[2]);\n    assert.strictEqual(el.selectedItem, el.items[2]);\n    assert.isFalse(el.isIndexSelected(0));\n    assert.isFalse(el.isIndexSelected(1));\n    assert.isTrue(el.isIndexSelected(2));\n    // Toggle 2\n    el.toggle = true;\n    el.select(el.items[2]);\n    assert.strictEqual(el.selected, null);\n    assert.strictEqual(el.selectedItem, null);\n    assert.isFalse(el.isSelected(el.items[0]));\n    assert.isFalse(el.isSelected(el.items[1]));\n    assert.isFalse(el.isSelected(el.items[2]));\n    // Toggle 2\n    el.toggle = true;\n    el.select(el.items[2]);\n    assert.strictEqual(el.selected, el.items[2]);\n    assert.strictEqual(el.selectedItem, el.items[2]);\n    assert.isFalse(el.isSelected(el.items[0]));\n    assert.isFalse(el.isSelected(el.items[1]));\n    assert.isTrue(el.isSelected(el.items[2]));\n    // clearSelection\n    el.clearSelection();\n    assert.equal(el.selectedItem, null);\n  });\n\n  test('bound defaults', function() {\n    let bind = fixture('bind');\n    assert.equal(bind.$.observer.singleSelected, null);\n    assert.sameMembers(bind.$.observer.multiSelected, []);\n    bind.items = [\n      {name: 'one'},\n      {name: 'two'},\n      {name: 'three'}\n    ];\n    assert.equal(bind.$.observer.singleSelected, null);\n    assert.sameMembers(bind.$.observer.multiSelected, []);\n  });\n\n  test('single selection notification', function() {\n    let bind = fixture('bind');\n    bind.items = [\n      {name: 'one'},\n      {name: 'two'},\n      {name: 'three'}\n    ];\n    bind.$.observer.singleChanged = sinon.spy();\n    bind.$.singleBound.select(bind.items[2]);\n    assert.isTrue(bind.$.observer.singleChanged.calledOnce);\n    assert.equal(bind.$.observer.singleChanged.firstCall.args[0].path, 'singleSelected');\n    assert.equal(bind.$.observer.singleChanged.firstCall.args[0].value, bind.items[2]);\n    assert.equal(bind.$.observer.singleSelected, bind.items[2]);\n    // clear selection\n    bind.$.observer.singleChanged = sinon.spy();\n    bind.$.singleBound.clearSelection();\n    assert.equal(bind.$.observer.singleSelected, null);\n    assert.isTrue(bind.$.observer.singleChanged.calledOnce);\n    assert.equal(bind.$.observer.singleChanged.firstCall.args[0].path, 'singleSelected');\n    assert.equal(bind.$.observer.singleChanged.firstCall.args[0].value, null);\n  });\n\n  test('single selection sub-property change', function() {\n    let bind = fixture('bind');\n    bind.items = [\n      {name: 'one'},\n      {name: 'two'},\n      {name: 'three'}\n    ];\n    bind.$.singleBound.select(bind.items[2]);\n    bind.$.observer.singleChanged = sinon.spy();\n    bind.set(['items', 2, 'name'], 'test');\n    assert.isTrue(bind.$.observer.singleChanged.calledOnce);\n    assert.equal(bind.$.observer.singleChanged.firstCall.args[0].path, 'singleSelected.name');\n    assert.equal(bind.$.observer.singleChanged.firstCall.args[0].value, 'test');\n    assert.equal(bind.$.observer.singleSelected.name, 'test');\n\n    bind.$.singleBound.select(bind.items[1]);\n    bind.$.observer.singleChanged = sinon.spy();\n    bind.set(['items', 1, 'name'], 'test2');\n    assert.isTrue(bind.$.observer.singleChanged.calledOnce);\n    assert.equal(bind.$.observer.singleChanged.firstCall.args[0].path, 'singleSelected.name');\n    assert.equal(bind.$.observer.singleChanged.firstCall.args[0].value, 'test2');\n    assert.equal(bind.$.observer.singleSelected.name, 'test2');\n  });\n\n  test('single selection sub-property change after unshift', function() {\n    let bind = fixture('bind');\n    bind.items = [\n      {name: 'one'},\n      {name: 'two'},\n      {name: 'three'}\n    ];\n    bind.$.singleBound.select(bind.items[2]);\n    bind.unshift('items', {name: 'zero'});\n    bind.$.observer.singleChanged = sinon.spy();\n    bind.set(['items', 3, 'name'], 'test2');\n    assert.isTrue(bind.$.observer.singleChanged.calledOnce);\n    assert.equal(bind.$.observer.singleChanged.firstCall.args[0].path, 'singleSelected.name');\n    assert.equal(bind.$.observer.singleChanged.firstCall.args[0].value, 'test2');\n    assert.equal(bind.$.observer.singleSelected.name, 'test2');\n  });\n\n  test('single selection removal via splice', function() {\n    let bind = fixture('bind');\n    bind.items = [\n      {name: 'one'},\n      {name: 'two'},\n      {name: 'three'}\n    ];\n    bind.$.singleBound.select(bind.items[1]);\n    bind.$.observer.singleChanged = sinon.spy();\n    bind.splice('items', 1, 2);\n    assert.isTrue(bind.$.observer.singleChanged.calledOnce);\n    assert.equal(bind.$.observer.singleChanged.firstCall.args[0].path, 'singleSelected');\n    assert.equal(bind.$.observer.singleChanged.firstCall.args[0].value, null);\n    assert.equal(bind.$.observer.singleSelected, null);\n  });\n\n  test('copy array, selection should remain', function() {\n    let bind = fixture('bind');\n    bind.items = [\n      {name: 'one'},\n      {name: 'two'},\n      {name: 'three'}\n    ];\n    bind.$.singleBound.select(bind.items[2]);\n    assert.equal(bind.$.singleBound.selected, bind.items[2]);\n    // set items to copy; all should still be selected\n    bind.items = bind.items.slice();\n    assert.equal(bind.$.singleBound.selected, bind.items[2]);\n  });\n\n  test('change array, selection should go away', function() {\n    let bind = fixture('bind');\n    bind.items = [\n      {name: 'one'},\n      {name: 'two'},\n      {name: 'three'}\n    ];\n    bind.$.singleBound.select(bind.items[2]);\n    assert.equal(bind.$.singleBound.selected, bind.items[2]);\n    // set items to new objects; all should be removed (selection based on identity)\n    bind.items = [\n      {name: 'one'},\n      {name: 'two'},\n      {name: 'three'}\n    ];\n    assert.equal(bind.$.singleBound.selected, null);\n  });\n\n  test('null array, selection should go away', function() {\n    let bind = fixture('bind');\n    bind.items = [\n      {name: 'one'},\n      {name: 'two'},\n      {name: 'three'}\n    ];\n    bind.$.singleBound.select(bind.items[2]);\n    assert.equal(bind.$.singleBound.selected, bind.items[2]);\n    // set items to new objects; all should be removed (selection based on identity)\n    bind.items = null;\n    assert.equal(bind.$.singleBound.selected, null);\n  });\n\n});\n\nsuite('multi selection', function() {\n\n  test('multi selection', function() {\n    var el = fixture('multiConfigured');\n    // Nothing selected\n    assert.sameMembers(el.selected, []);\n    assert.isFalse(el.isSelected(el.items[0]));\n    assert.isFalse(el.isSelected(el.items[1]));\n    assert.isFalse(el.isSelected(el.items[2]));\n    // Select 0\n    el.select(el.items[0]);\n    assert.sameMembers(el.selected, [el.items[0]]);\n    assert.isTrue(el.isSelected(el.items[0]));\n    assert.isFalse(el.isSelected(el.items[1]));\n    assert.isFalse(el.isSelected(el.items[2]));\n    // Re-select 0\n    el.select(el.items[0]);\n    assert.sameMembers(el.selected, [el.items[0]]);\n    assert.isTrue(el.isSelected(el.items[0]));\n    assert.isFalse(el.isSelected(el.items[1]));\n    assert.isFalse(el.isSelected(el.items[2]));\n    // Select 2 (using index-based API)\n    el.selectIndex(2);\n    assert.sameMembers(el.selected, [el.items[0], el.items[2]]);\n    assert.isTrue(el.isIndexSelected(0));\n    assert.isFalse(el.isIndexSelected(1));\n    assert.isTrue(el.isIndexSelected(2));\n    // Toggle 2\n    el.toggle = true;\n    el.select(el.items[2]);\n    assert.sameMembers(el.selected, [el.items[0]]);\n    assert.isTrue(el.isSelected(el.items[0]));\n    assert.isFalse(el.isSelected(el.items[1]));\n    assert.isFalse(el.isSelected(el.items[2]));\n    // Toggle 2\n    el.toggle = true;\n    el.select(el.items[2]);\n    assert.sameMembers(el.selected, [el.items[0], el.items[2]]);\n    assert.isTrue(el.isSelected(el.items[0]));\n    assert.isFalse(el.isSelected(el.items[1]));\n    assert.isTrue(el.isSelected(el.items[2]));\n    // clear selection\n    el.clearSelection();\n    assert.sameMembers(el.selected, []);\n  });\n  test('multi selection notification', function() {\n    let bind = fixture('bind');\n    bind.items = [\n      {name: 'one'},\n      {name: 'two'},\n      {name: 'three'}\n    ];\n    // select first\n    bind.$.observer.multiChanged = sinon.spy();\n    bind.$.multiBound.select(bind.items[2]);\n    assert.isTrue(bind.$.observer.multiChanged.calledTwice);\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected.splices');\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value.indexSplices.length, 1);\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value.indexSplices[0].addedCount, 1);\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value.indexSplices[0].removed.length, 0);\n    assert.sameMembers(bind.$.observer.multiSelected, [bind.items[2]]);\n    assert.equal(bind.$.observer.multiChanged.secondCall.args[0].path, 'multiSelected.length');\n    assert.equal(bind.$.observer.multiChanged.secondCall.args[0].value, 1);\n    // select second\n    bind.$.observer.multiChanged = sinon.spy();\n    bind.$.multiBound.select(bind.items[0]);\n    assert.isTrue(bind.$.observer.multiChanged.calledTwice);\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected.splices');\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value.indexSplices.length, 1);\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value.indexSplices[0].addedCount, 1);\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value.indexSplices[0].removed.length, 0);\n    assert.sameMembers(bind.$.observer.multiSelected, [bind.items[2], bind.items[0]]);\n    assert.equal(bind.$.observer.multiChanged.secondCall.args[0].path, 'multiSelected.length');\n    assert.equal(bind.$.observer.multiChanged.secondCall.args[0].value, 2);\n    // clear selection\n    bind.$.observer.multiChanged = sinon.spy();\n    bind.$.multiBound.clearSelection();\n    assert.sameMembers(bind.$.observer.multiSelected, []);\n    assert.isTrue(bind.$.observer.multiChanged.calledOnce);\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected');\n    assert.sameMembers(bind.$.observer.multiChanged.firstCall.args[0].value, []);\n  });\n\n  test('multi selection sub-property change', function() {\n    let bind = fixture('bind');\n    bind.items = [\n      {name: 'one'},\n      {name: 'two'},\n      {name: 'three'}\n    ];\n    bind.$.multiBound.select(bind.items[2]);\n    bind.$.multiBound.select(bind.items[0]);\n    bind.$.observer.multiChanged = sinon.spy();\n    bind.set(['items', 2, 'name'], 'test');\n    assert.isTrue(bind.$.observer.multiChanged.calledOnce);\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected.0.name');\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value, 'test');\n    assert.equal(bind.$.observer.multiSelected[0].name, 'test');\n    bind.$.observer.multiChanged = sinon.spy();\n    bind.set(['items', 0, 'name'], 'test2');\n    assert.isTrue(bind.$.observer.multiChanged.calledOnce);\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected.1.name');\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value, 'test2');\n    assert.equal(bind.$.observer.multiSelected[1].name, 'test2');\n  });\n\n\n  test('multi selection sub-property change after unshift', function() {\n    let bind = fixture('bind');\n    bind.items = [\n      {name: 'one'},\n      {name: 'two'},\n      {name: 'three'}\n    ];\n    bind.$.multiBound.select(bind.items[2]);\n    bind.$.multiBound.select(bind.items[0]);\n    bind.unshift('items', {name: 'zero'});\n    bind.$.observer.multiChanged = sinon.spy();\n    bind.set(['items', 1, 'name'], 'test');\n    assert.isTrue(bind.$.observer.multiChanged.calledOnce);\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected.1.name');\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value, 'test');\n    assert.equal(bind.$.observer.multiSelected[1].name, 'test');\n  });\n\n  test('multi selection sub-property change after splice (removal)', function() {\n    let bind = fixture('bind');\n    bind.items = [\n      {name: 'one'},\n      {name: 'two'},\n      {name: 'three'}\n    ];\n    bind.$.multiBound.select(bind.items[0]);\n    bind.$.multiBound.select(bind.items[2]);\n\n    bind.$.observer.multiChanged = sinon.spy();\n    bind.splice('items', 0, 1);\n    // assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected');\n    // assert.sameMembers(bind.$.observer.multiChanged.firstCall.args[0].value, [bind.items[1]]);\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected.splices');\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value.indexSplices.length, 1);\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value.indexSplices[0].index, 0);\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value.indexSplices[0].addedCount, 0);\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value.indexSplices[0].removed.length, 1);\n\n    bind.$.observer.multiChanged = sinon.spy();\n    bind.set(['items', 1, 'name'], 'test');\n    assert.isTrue(bind.$.observer.multiChanged.calledOnce);\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected.0.name');\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value, 'test');\n    assert.equal(bind.$.observer.multiSelected[0].name, 'test');\n  });\n\n  test('multi selection sub-property change after deselect', function() {\n    let bind = fixture('bind');\n    bind.items = [\n      {name: 'one'},\n      {name: 'two'},\n      {name: 'three'}\n    ];\n    bind.$.multiBound.select(bind.items[2]);\n    bind.$.multiBound.select(bind.items[0]);\n    bind.$.observer.multiChanged = sinon.spy();\n    bind.set(['items', 0, 'name'], 'test');\n    assert.isTrue(bind.$.observer.multiChanged.calledOnce);\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected.1.name');\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value, 'test');\n    assert.equal(bind.$.observer.multiSelected[1].name, 'test');\n\n    bind.$.multiBound.deselect(bind.items[2]);\n    bind.$.observer.multiChanged = sinon.spy();\n    bind.set(['items', 0, 'name'], 'test4');\n    assert.isTrue(bind.$.observer.multiChanged.calledOnce);\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected.0.name');\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value, 'test4');\n    assert.equal(bind.$.observer.multiSelected[0].name, 'test4');\n  });\n\n  test('copy array, selection should remain', function() {\n    let bind = fixture('bind');\n    bind.items = [\n      {name: 'one'},\n      {name: 'two'},\n      {name: 'three'}\n    ];\n    bind.$.multiBound.select(bind.items[2]);\n    bind.$.multiBound.select(bind.items[0]);\n    assert.sameMembers(bind.$.multiBound.selected, [bind.items[2], bind.items[0]]);\n    // set items to copy; all should still be selected\n    bind.items = bind.items.slice();\n    assert.sameMembers(bind.$.multiBound.selected, [bind.items[2], bind.items[0]]);\n  });\n\n  test('change array, selection should go away', function() {\n    let bind = fixture('bind');\n    bind.items = [\n      {name: 'one'},\n      {name: 'two'},\n      {name: 'three'}\n    ];\n    bind.$.multiBound.select(bind.items[2]);\n    bind.$.multiBound.select(bind.items[0]);\n    assert.sameMembers(bind.$.multiBound.selected, [bind.items[2], bind.items[0]]);\n    // set items to new objects; all should be removed (selection based on identity)\n    bind.items = [\n      {name: 'one'},\n      {name: 'two'},\n      {name: 'three'}\n    ];\n    assert.sameMembers(bind.$.multiBound.selected, []);\n  });\n\n  test('null array, selection should go away', function() {\n    let bind = fixture('bind');\n    bind.items = [\n      {name: 'one'},\n      {name: 'two'},\n      {name: 'three'}\n    ];\n    bind.$.multiBound.select(bind.items[2]);\n    bind.$.multiBound.select(bind.items[0]);\n    assert.sameMembers(bind.$.multiBound.selected, [bind.items[2], bind.items[0]]);\n    // set items to new objects; all should be removed (selection based on identity)\n    bind.items = null;\n    assert.sameMembers(bind.$.multiBound.selected, []);\n  });\n\n  test('reset item in array, selection should go away', function() {\n    let bind = fixture('bind');\n    bind.items = [\n      {name: 'one'},\n      {name: 'two'},\n      {name: 'three'}\n    ];\n    bind.$.multiBound.select(bind.items[2]);\n    bind.$.multiBound.select(bind.items[0]);\n    assert.sameMembers(bind.$.multiBound.selected, [bind.items[2], bind.items[0]]);\n    // set items to new objects; all should be removed (selection based on identity)\n    bind.set('items.0', {name: 'new'});\n    assert.sameMembers(bind.$.multiBound.selected, [bind.items[2]]);\n  });\n\n});\n\nsuite('corner cases', function() {\n\n  test('switch from single to multi', function() {\n    var el = fixture('singleConfigured');\n    // Nothing selected\n    assert.strictEqual(el.selected, null);\n    assert.strictEqual(el.selectedItem, null);\n    assert.isFalse(el.isSelected(el.items[0]));\n    assert.isFalse(el.isSelected(el.items[1]));\n    assert.isFalse(el.isSelected(el.items[2]));\n    // Select 0\n    el.select(el.items[0]);\n    assert.strictEqual(el.selected, el.items[0]);\n    assert.strictEqual(el.selectedItem, el.items[0]);\n    assert.isTrue(el.isSelected(el.items[0]));\n    assert.isFalse(el.isSelected(el.items[1]));\n    assert.isFalse(el.isSelected(el.items[2]));\n    // switch to multi\n    el.multi = true;\n    assert.sameMembers(el.selected, []);\n    assert.equal(el.selectedItem, null);\n  });\n\n  test('switch from multi to single', function() {\n    var el = fixture('multiConfigured');\n    // Nothing selected\n    assert.sameMembers(el.selected, []);\n    assert.isFalse(el.isSelected(el.items[0]));\n    assert.isFalse(el.isSelected(el.items[1]));\n    assert.isFalse(el.isSelected(el.items[2]));\n    // Select 0\n    el.select(el.items[0]);\n    assert.sameMembers(el.selected, [el.items[0]]);\n    assert.isTrue(el.isSelected(el.items[0]));\n    assert.isFalse(el.isSelected(el.items[1]));\n    assert.isFalse(el.isSelected(el.items[2]));\n    // switch to single\n    el.multi = false;\n    assert.equal(el.selected, null);\n    assert.equal(el.selectedItem, null);\n  });\n\n  test('reset mutated array with gaps resulting in multiple splices', function() {\n    var bind = fixture('bind');\n    let i = bind.items = [\n      {name: '0'}, {name: '1'}, {name: '2'}, {name: '3'},\n      {name: '4'}, {name: '5'}, {name: '6'}, {name: '7'}\n    ];\n    bind.$.multiBound.selectIndex(2);\n    bind.$.multiBound.selectIndex(6);\n    bind.$.multiBound.selectIndex(1);\n    bind.$.multiBound.selectIndex(5);\n    bind.$.multiBound.selectIndex(0);\n    bind.$.multiBound.selectIndex(4);\n    assert.sameMembers(bind.$.multiBound.selected, [i[2], i[6], i[1], i[5], i[0], i[4]]);\n    bind.$.observer.multiChanged = sinon.spy();\n    bind.set('items.4.name', 'changed1');\n    assert.isTrue(bind.$.observer.multiChanged.calledOnce);\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected.5.name');\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value, 'changed1');\n\n    bind.items = [\n      i[0], i[3], i[4], i[7]\n    ];\n    assert.sameMembers(bind.$.multiBound.selected, [i[0], i[4]]);\n    bind.$.observer.multiChanged = sinon.spy();\n    bind.set('items.2.name', 'changed2');\n    assert.isTrue(bind.$.observer.multiChanged.calledOnce);\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected.1.name');\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value, 'changed2');\n  });\n\n  // Current algorithm does not handle reordering array while maintaining selection state\n  test('reset mutated array reordered resulting in multiple splices', function() {\n    var bind = fixture('bind');\n    let i = bind.items = [\n      {name: '0'}, {name: '1'}, {name: '2'}, {name: '3'},\n      {name: '4'}, {name: '5'}, {name: '6'}, {name: '7'}\n    ];\n    bind.$.multiBound.selectIndex(2);\n    bind.$.multiBound.selectIndex(6);\n    bind.$.multiBound.selectIndex(1);\n    bind.$.multiBound.selectIndex(5);\n    bind.$.multiBound.selectIndex(0);\n    bind.$.multiBound.selectIndex(4);\n    assert.sameMembers(bind.$.multiBound.selected, [i[2], i[6], i[1], i[5], i[0], i[4]]);\n    bind.$.observer.multiChanged = sinon.spy();\n    bind.set('items.4.name', 'changed1');\n    assert.isTrue(bind.$.observer.multiChanged.calledOnce);\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected.5.name');\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value, 'changed1');\n\n    bind.items = [\n      i[4], i[5], i[6], i[7], i[0], i[1], i[2], i[3]\n    ];\n    assert.sameMembers(bind.$.multiBound.selected, [i[2], i[6], i[1], i[5], i[0], i[4]]);\n    bind.$.observer.multiChanged = sinon.spy();\n    bind.set('items.0.name', 'changed2');\n    assert.isTrue(bind.$.observer.multiChanged.calledOnce);\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected.5.name');\n    assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value, 'changed2');\n  });\n\n});\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/async.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../lib/utils/async.js\"></script>\n</head>\n<body>\n\n<script type=\"module\">\nimport { microTask, timeOut, animationFrame, idlePeriod } from '../../lib/utils/async.js';\nvar capturedErrors = [];\nvar captureEnabled = false;\nwindow.addEventListener('error', function(e) {\n  if (captureEnabled) {\n    capturedErrors.push(e);\n    e.stopImmediatePropagation();\n    e.preventDefault();\n    return true;\n  }\n});\n\nsuite('Queueing micro tasks', function() {\n\n  test('The queued function runs.', function(done) {\n    var callCount = 0;\n    var callback = function() {\n      callCount++;\n    };\n\n    microTask.run(callback);\n    setTimeout(function() {\n      assert.equal(callCount, 1);\n      done();\n    });\n  });\n\n  test('Functions queued multiple times are run multiple times.',\n    function(done) {\n      var callCount = 0;\n      var callback = function() {\n        callCount++;\n      };\n      microTask.run(callback);\n      microTask.run(callback);\n      microTask.run(callback);\n      setTimeout(function() {\n        assert.equal(callCount, 3);\n        done();\n      });\n    });\n\n  test('All queued functions are run.', function(done) {\n    var callCount1 = 0;\n    var callCount2 = 0;\n    var callCount3 = 0;\n    var callback1 = function() {\n      callCount1++;\n    };\n    var callback2 = function() {\n      callCount2++;\n    };\n    var callback3 = function() {\n      callCount3++;\n    };\n    microTask.run(callback1);\n    microTask.run(callback2);\n    microTask.run(callback3);\n    setTimeout(function() {\n      assert.equal(callCount1, 1);\n      assert.equal(callCount2, 1);\n      assert.equal(callCount3, 1);\n      done();\n    });\n  });\n\n  test('Errors are thrown but the queue is continued', function(done) {\n    captureEnabled = true;\n    var callCount1 = 0;\n    var callCount2 = 0;\n    var callCount3 = 0;\n    var callCount4 = 0;\n    var callCount5 = 0;\n    var callback1 = function() {\n      callCount1++;\n    };\n    var callback2 = function() {\n      callCount2++;\n      throw new Error('intentional error 1');\n    };\n    var callback3 = function() {\n      callCount3++;\n      microTask.run(callback5);\n      throw new Error('intentional error 2');\n    };\n    var callback4 = function() {\n      callCount4++;\n    };\n    var callback5 = function() {\n      callCount5++;\n    };\n    microTask.run(callback1);\n    microTask.run(callback2);\n    microTask.run(callback3);\n    microTask.run(callback4);\n    // All callbacks have been called by the next task.\n    setTimeout(function() {\n      captureEnabled = false;\n      assert.equal(callCount1, 1);\n      assert.equal(callCount2, 1);\n      assert.equal(callCount3, 1);\n      assert.equal(callCount4, 1);\n      assert.equal(callCount5, 1);\n      assert.equal(capturedErrors.length, 2);\n      capturedErrors.length = 0;\n      done();\n    }, 100);\n  });\n});\n\nsuite('Cancelling micro tasks', function() {\n\n  test('Queued functions are cancelable.', function(done) {\n    var callCount = 0;\n    var callback = function() {\n      callCount++;\n    };\n    var asyncRef = microTask.run(callback);\n    microTask.cancel(asyncRef);\n    setTimeout(function() {\n      assert.equal(callCount, 0);\n      done();\n    });\n  });\n\n  test('Multiple instances of the same queued function are cancelable.', function(done) {\n    var callCount = 0;\n    var callback = function() {\n      callCount++;\n    };\n    var asyncRefs = [];\n    asyncRefs.push(microTask.run(callback));\n    asyncRefs.push(microTask.run(callback));\n    asyncRefs.push(microTask.run(callback));\n    microTask.cancel(asyncRefs.pop());\n    microTask.cancel(asyncRefs.pop());\n    microTask.cancel(asyncRefs.pop());\n    setTimeout(function() {\n      assert.equal(callCount, 0);\n      done();\n    });\n  });\n\n  test('Multiple queued functions are individually cancelable.', function(done) {\n    var callCount1 = 0;\n    var callCount2 = 0;\n    var callCount3 = 0;\n    var callback1 = function() {\n      callCount1++;\n    };\n    var callback2 = function() {\n      callCount2++;\n    };\n    var callback3 = function() {\n      callCount3++;\n    };\n    var asyncRef1 = microTask.run(callback1);\n    microTask.run(callback2);\n    var asyncRef3 = microTask.run(callback3);\n    microTask.cancel(asyncRef1);\n    microTask.cancel(asyncRef3);\n    setTimeout(function() {\n      assert.equal(callCount1, 0);\n      assert.equal(callCount2, 1);\n      assert.equal(callCount3, 0);\n      done();\n    });\n  });\n\n});\n\nsuite('Queueing timeouts with a wait time', function() {\n\n  test('The queued function runs.', function(done) {\n    var callCount = 0;\n    var callback = function() {\n      callCount++;\n    };\n    timeOut.run(callback, 50);\n    timeOut.after(50).run(callback);\n    setTimeout(function() {\n      assert.equal(callCount, 2);\n      done();\n    }, 100);\n  });\n\n  test('Functions queued multiple times are run multiple times.', function(done) {\n    var callCount = 0;\n    var callback = function() {\n      callCount++;\n    };\n    timeOut.run(callback, 50);\n    timeOut.after(50).run(callback);\n    timeOut.run(callback, 50);\n    timeOut.after(50).run(callback);\n    timeOut.run(callback, 200);\n    timeOut.after(200).run(callback);\n    setTimeout(function() {\n      assert.equal(callCount, 4);\n      done();\n    }, 100); // Only wait until the first two callbacks are called.\n  });\n\n  test('All queued functions are run.', function(done) {\n    var callCount1 = 0;\n    var callCount2 = 0;\n    var callCount3 = 0;\n    var callback1 = function() {\n      callCount1++;\n    };\n    var callback2 = function() {\n      callCount2++;\n    };\n    var callback3 = function() {\n      callCount3++;\n    };\n    timeOut.run(callback1, 50);\n    timeOut.run(callback2, 50);\n    timeOut.run(callback3, 200);\n    setTimeout(function() {\n      assert.equal(callCount1, 1);\n      assert.equal(callCount2, 1);\n      assert.equal(callCount3, 0);\n      done();\n    }, 100); // Only wait until the first two callbacks are called.\n  });\n\n});\n\nsuite('Cancelling timers queued with a wait time', function() {\n\n  test('Queued functions are cancelable.', function(done) {\n    var callCount = 0;\n    var callback = function() {\n      callCount++;\n    };\n    var asyncRef = timeOut.run(callback, 50);\n    timeOut.cancel(asyncRef);\n    setTimeout(function() {\n      assert.equal(callCount, 0);\n      done();\n    }, 100);\n  });\n\n  test('Multiple instances of the same queued function are cancelable.', function(done) {\n    var callCount = 0;\n    var callback = function() {\n      callCount++;\n    };\n    var queue = [];\n    queue.push(timeOut.run(callback, 50));\n    queue.push(timeOut.run(callback, 50));\n    queue.push(timeOut.after(50).run(callback));\n    queue.push(timeOut.run(callback, 200));\n    while (queue.length > 0) {\n      timeOut.cancel(queue.pop());\n    }\n    setTimeout(function() {\n      assert.equal(callCount, 0);\n      done();\n    }, 250);\n  });\n\n  test('Multiple queued functions are individually cancelable.', function(done) {\n    var callCount1 = 0;\n    var callCount2 = 0;\n    var callCount3 = 0;\n    var callback1 = function() {\n      callCount1++;\n    };\n    var callback2 = function() {\n      callCount2++;\n    };\n    var callback3 = function() {\n      callCount3++;\n    };\n    var asyncRef1 = timeOut.run(callback1, 50);\n    microTask.run(callback2, 50);\n    var asyncRef3 = timeOut.run(callback3, 200);\n    timeOut.cancel(asyncRef1);\n    timeOut.cancel(asyncRef3);\n    setTimeout(function() {\n      assert.equal(callCount1, 0);\n      assert.equal(callCount2, 1);\n      assert.equal(callCount3, 0);\n      done();\n    }, 250);\n  });\n\n});\n\nsuite('Queueing functions to run before the next paint', function() {\n\n  test('The queued function runs.', function(done) {\n    var callback = sinon.spy();\n    animationFrame.run(callback);\n    requestAnimationFrame(function() {\n      assert.isTrue(callback.calledOnce);\n      done();\n    });\n  });\n\n  test('Functions queued multiple times are run multiple times.', function(done) {\n    var callback = sinon.spy();\n    animationFrame.run(callback);\n    animationFrame.run(callback);\n    requestAnimationFrame(function() {\n      assert.isTrue(callback.calledTwice);\n      done();\n    });\n  });\n\n  test('All queued functions are run.', function(done) {\n    var callback1 = sinon.spy();\n    var callback2 = sinon.spy();\n    animationFrame.run(callback1);\n    animationFrame.run(callback2);\n    requestAnimationFrame(function() {\n      assert.isTrue(callback1.calledOnce);\n      assert.isTrue(callback2.calledOnce);\n      done();\n    });\n  });\n\n});\n\nsuite('Cancelling functions queued to run before the next paint', function() {\n\n  test('Queued functions are cancelable.', function(done) {\n    var callback = sinon.spy();\n    var asyncRef = animationFrame.run(callback);\n    animationFrame.cancel(asyncRef);\n    requestAnimationFrame(function() {\n      assert.isFalse(callback.called);\n      done();\n    });\n  });\n\n  test('Multiple instances of the same queued function are cancelable.', function(done) {\n    var callback = sinon.spy();\n    var asyncRefs = [];\n    asyncRefs.push(animationFrame.run(callback));\n    asyncRefs.push(animationFrame.run(callback));\n    asyncRefs.push(animationFrame.run(callback));\n    animationFrame.cancel(asyncRefs.pop());\n    animationFrame.cancel(asyncRefs.pop());\n    animationFrame.cancel(asyncRefs.pop());\n    requestAnimationFrame(function() {\n      assert.isFalse(callback.called);\n      done();\n    });\n  });\n\n  test('Multiple queued functions are individually cancelable.', function(done) {\n    var callback1 = sinon.spy();\n    var callback2 = sinon.spy();\n    var callback3 = sinon.spy();\n    var asyncRef1 = animationFrame.run(callback1, 50);\n    animationFrame.run(callback2, 50);\n    var asyncRef3 = animationFrame.run(callback3, 200);\n    animationFrame.cancel(asyncRef1);\n    animationFrame.cancel(asyncRef3);\n    requestAnimationFrame(function() {\n      assert.isFalse(callback1.called);\n      assert.isTrue(callback2.calledOnce);\n      assert.isFalse(callback3.called);\n      done();\n    });\n  });\n\n});\n\nsuite('Queueing functions to run during idle period', function() {\n  var whenIdle = window.requestIdleCallback ? window.requestIdleCallback : function(fn) { setTimeout(fn, 16); };\n\n  test('The queued function runs.', function(done) {\n    var callback = sinon.spy();\n    idlePeriod.run(callback);\n    whenIdle(function() {\n      assert.isTrue(callback.calledOnce);\n      done();\n    });\n  });\n\n  test('Functions queued multiple times are run multiple times.', function(done) {\n    var callback = sinon.spy();\n    idlePeriod.run(callback);\n    idlePeriod.run(callback);\n    whenIdle(function() {\n      assert.isTrue(callback.calledTwice);\n      done();\n    });\n  });\n\n  test('All queued functions are run.', function(done) {\n    var callback1 = sinon.spy();\n    var callback2 = sinon.spy();\n    idlePeriod.run(callback1);\n    idlePeriod.run(callback2);\n    whenIdle(function() {\n      assert.isTrue(callback1.calledOnce);\n      assert.isTrue(callback2.calledOnce);\n      done();\n    });\n  });\n\n});\n\n\nsuite('Cancelling functions queued to run during idle period', function() {\n  var whenIdle = window.requestIdleCallback ? window.requestIdleCallback : function(fn) { setTimeout(fn, 16); };\n\n  test('Queued functions are cancelable.', function(done) {\n    var callback = sinon.spy();\n    var asyncRef = idlePeriod.run(callback);\n    idlePeriod.cancel(asyncRef);\n    whenIdle(function() {\n      assert.isFalse(callback.called);\n      done();\n    });\n  });\n\n  test('Multiple instances of the same queued function are cancelable.', function(done) {\n    var callback = sinon.spy();\n    var asyncRefs = [];\n    asyncRefs.push(idlePeriod.run(callback));\n    asyncRefs.push(idlePeriod.run(callback));\n    asyncRefs.push(idlePeriod.run(callback));\n    idlePeriod.cancel(asyncRefs.pop());\n    idlePeriod.cancel(asyncRefs.pop());\n    idlePeriod.cancel(asyncRefs.pop());\n    whenIdle(function() {\n      assert.isFalse(callback.called);\n      done();\n    });\n  });\n\n  test('Multiple queued functions are individually cancelable.', function(done) {\n    var callback1 = sinon.spy();\n    var callback2 = sinon.spy();\n    var callback3 = sinon.spy();\n    var asyncRef1 = idlePeriod.run(callback1, 50);\n    idlePeriod.run(callback2, 50);\n    var asyncRef3 = idlePeriod.run(callback3, 200);\n    idlePeriod.cancel(asyncRef1);\n    idlePeriod.cancel(asyncRef3);\n    whenIdle(function() {\n      assert.isFalse(callback1.called);\n      assert.isTrue(callback2.calledOnce);\n      assert.isFalse(callback3.called);\n      done();\n    });\n  });\n\n});\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/attributes-elements.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport { Polymer } from '../../lib/legacy/polymer-fn.js';\n\nimport { html } from '../../lib/utils/html-tag.js';\nlet PropertyTypeBehavior = {\n  properties: {\n    behaviorShorthandNumber: Number,\n    behaviorShorthandBool: Boolean,\n    behaviorNumber: {\n      value: 11,\n      type: Number\n    },\n    behaviorBool: {\n      value: false,\n      type: Boolean\n    }\n  }\n};\n\nPolymer({\n  is: 'x-basic',\n  hostAttributes: {\n    attr1: 'this is attr 1',\n    attr2: 42,\n    attr3: 'host',\n    'aria-role': 'button',\n    title: 'awesome',\n    'attr-object': {foo: 'bar', nested: {'meaning': 42}, arr: [0, 'foo', true]},\n    'attr-stupid': false,\n    class: 'foo bar baz'\n  },\n  behaviors: [ PropertyTypeBehavior ],\n  properties: {\n    object: {\n      type: Object,\n      value: function() { return {}; }\n    },\n    array: {\n      type: Array,\n      value: function() { return []; }\n    },\n    number: {\n      type: Number,\n      value: 0\n    },\n    string: {\n      type: String,\n      value: 'none'\n    },\n    bool: {\n      type: Boolean,\n      value: true\n    },\n    negBool: {\n      type: Boolean,\n      value: false\n    },\n    date: {\n      type: Date,\n      value: function() { return new Date(0); }\n    },\n    dashCase: {\n      type: String,\n      value: 'none'\n    },\n    UPCASE: {\n      type: String,\n      value: 'none'\n    },\n    noType: {\n      value: 'none'\n    },\n    readOnly: {\n      type: String,\n      value: 'default',\n      readOnly: true\n    },\n    prop: {\n      value: 'prop',\n      observer: 'propChanged'\n    },\n    attr1: {\n      observer: 'attr1Changed'\n    },\n    shorthandNumber: Number,\n    shorthandBool: Boolean,\n    foreignTypeObjectProp: {\n      type: Object,\n      value: 'none'\n    }\n  },\n\n  propChangedCount: 0,\n  attr1ChangedCount: 0,\n\n  propChanged: function() {\n    this.propChangedCount++;\n  },\n\n  attr1Changed: function() {\n    this.attr1ChangedCount++;\n  }\n\n});\nPolymer({\n  is: 'x-reflect',\n  behaviors: [ PropertyTypeBehavior ],\n  properties: {\n    object: {\n      type: Object,\n      reflectToAttribute: true,\n      value: function() { return {}; }\n    },\n    array: {\n      type: Array,\n      reflectToAttribute: true,\n      value: function() { return []; }\n    },\n    number: {\n      type: Number,\n      reflectToAttribute: true,\n      value: 0\n    },\n    string: {\n      type: String,\n      reflectToAttribute: true,\n      value: 'none'\n    },\n    bool: {\n      type: Boolean,\n      reflectToAttribute: true,\n      value: true\n    },\n    negBool: {\n      type: Boolean,\n      reflectToAttribute: true,\n      value: false\n    },\n    date: {\n      type: Date,\n      reflectToAttribute: true,\n      value: function() { return new Date(0); }\n    },\n    dashCase: {\n      type: String,\n      reflectToAttribute: true,\n      value: 'none'\n    },\n    UPCASE: {\n      type: String,\n      reflectToAttribute: true,\n      value: 'none'\n    },\n    noType: {\n      value: 'none'\n    },\n    readOnly: {\n      type: String,\n      value: 'default',\n      readOnly: true\n    },\n    shorthandNumber: Number,\n    shorthandBool: Boolean,\n    foreignTypeObjectProp: {\n      type: Object,\n      reflectToAttribute: true,\n      value: 'none'\n    }\n  },\n  _warn: function() {\n    var search = Array.prototype.join.call(arguments, '');\n    if (search.indexOf('UPCASE') > -1) {\n      this.__warnedAboutUPCASE = true;\n    }\n  }\n});\nPolymer({\n  _template: html`\n    <x-basic id=\"basic\" prop=\"{{attr1}}\" attr1\\$=\"{{attr1}}\" class=\"should-not-override\"></x-basic>\n`,\n\n  is: 'x-compose',\n\n  hostAttributes: {\n    attr1: 'compose'\n  },\n\n  properties: {\n    attr1: String,\n    prop2: String\n  },\n\n  ready: function() {\n    this.setAttribute('prop2', 'hi');\n  }\n});\n"
  },
  {
    "path": "test/unit/attributes.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n  <script type=\"module\" src=\"./attributes-elements.js\"></script>\n<body>\n\n  <test-fixture id=\"basic\">\n    <template>\n      <x-basic attr3=\"instance\"></x-basic>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"compose\">\n    <template>\n      <x-compose></x-compose>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"basic-with-attributes\">\n    <template>\n      <x-basic\n        object='{\"foo\": \"bar\", \"nested\": {\"meaning\": 42}, \"arr\": [0, \"foo\", true]}'\n        array='[0, \"foo\", true, {\"foo\": \"bar\"}]'\n        number=\"42\"\n        string=\"The quick brown fox\"\n        bool\n        date=\"Wed Mar 04 2015 10:46:05 GMT-0800 (PST)\"\n        -u-p-c-a-s-e=\"The quick brown fox\"\n        dash-case=\"The quick brown fox\"\n        no-type=\"Should be String\"\n        read-only=\"Should not change\"\n        class=\"Should not deserialize\"\n        nard=\"Should not deserialize\"\n        behavior-bool\n        behavior-number=\"77\"\n        shorthand-bool\n        shorthand-number=\"88\"\n        behavior-shorthand-bool\n        behavior-shorthand-number=\"99\"\n        foreign-type-object-prop=\"The quick brown fox\">\n      </x-basic>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"reflect-to-attribute\">\n    <template>\n      <x-reflect></x-reflect>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"reflect-to-attribute-and-attributes\">\n    <template>\n      <x-reflect\n        object='{\"foo\": \"bar\", \"nested\": {\"meaning\": 42}, \"arr\": [0, \"foo\", true]}'\n        array='[0, \"foo\", true, {\"foo\": \"bar\"}]'\n        number=\"42\"\n        string=\"The quick brown fox\"\n        bool\n        date=\"Wed Mar 04 2015 10:46:05 GMT-0800 (PST)\"\n        dash-case=\"The quick brown fox\"\n        -u-p-c-a-s-e=\"The quick brown fox\"\n        no-type=\"Should be String\"\n        read-only=\"Should not change\"\n        class=\"Should not deserialize\"\n        nard=\"Should not deserialize\"\n        behavior-bool\n        behavior-number=\"77\"\n        shorthand-bool\n        shorthand-number=\"88\"\n        behavior-shorthand-bool\n        behavior-shorthand-number=\"99\"\n        foreign-type-object-prop=\"The quick brown fox\">\n      </x-reflect>\n    </template>\n  </test-fixture>\n\n  <script type=\"module\">\nimport './attributes-elements.js';\nsuite('create-time deserialization', function() {\n  function testAttributesMatchDefaults(element) {\n    assert.deepEqual(element.object, {});\n    assert.deepEqual(element.array, []);\n    assert.strictEqual(element.number, 0);\n    assert.strictEqual(element.string, 'none');\n    assert.strictEqual(element.bool, true);\n    assert.strictEqual(element.negBool, false);\n    assert.strictEqual(element.date.getTime(), 0);\n    assert.strictEqual(element.dashCase, 'none');\n    assert.strictEqual(element.UPCASE, 'none');\n    assert.strictEqual(element.noType, 'none');\n    assert.strictEqual(element.readOnly, 'default');\n    assert.strictEqual(element.behaviorNumber, 11);\n    assert.strictEqual(element.behaviorBool, false);\n    assert.strictEqual(element.shorthandNumber, undefined);\n    assert.strictEqual(element.shorthandBool, undefined);\n    assert.strictEqual(element.behaviorShorthandNumber, undefined);\n    assert.strictEqual(element.behaviorShorthandBool, undefined);\n    assert.strictEqual(element.foreignTypeObjectProp, 'none');\n  }\n\n  function testAttributesMatchCustomConfiguration(element) {\n    var configuredObject = {foo: 'bar', nested: {'meaning': 42}, arr: [0, 'foo', true]};\n    var configuredArray = [0, 'foo', true, {foo: 'bar'}];\n    var configuredString = \"The quick brown fox\";\n    var configuredTime = 1425494765000;\n\n    assert.deepEqual(element.object, configuredObject);\n    assert.deepEqual(element.array, configuredArray);\n    assert.strictEqual(element.number, 42);\n    assert.strictEqual(element.string, 'The quick brown fox');\n    assert.strictEqual(element.bool, true);\n    assert.strictEqual(element.negBool, false);\n    assert.strictEqual(element.date.getTime(), configuredTime);\n    assert.strictEqual(element.dashCase, configuredString);\n    assert.strictEqual(element.UPCASE, configuredString);\n    assert.strictEqual(element.noType, 'Should be String');\n    assert.strictEqual(element.readOnly, 'default');\n    assert.strictEqual(element.class, undefined);\n    assert.strictEqual(element.nard, undefined);\n    assert.strictEqual(element.behaviorNumber, 77);\n    assert.strictEqual(element.behaviorBool, true);\n    assert.strictEqual(element.shorthandNumber, 88);\n    assert.strictEqual(element.shorthandBool, true);\n    assert.strictEqual(element.behaviorShorthandNumber, 99);\n    assert.strictEqual(element.behaviorShorthandBool, true);\n    assert.strictEqual(element.foreignTypeObjectProp, configuredString);\n  }\n\n  test('basic default values', function() {\n    var element = fixture('basic');\n    testAttributesMatchDefaults(element);\n  });\n\n  test('basic deserialize attributes', function() {\n    var element = fixture('basic-with-attributes');\n    testAttributesMatchCustomConfiguration(element);\n  });\n\n  test('reflected default values', function() {\n    var element = fixture('reflect-to-attribute');\n    testAttributesMatchDefaults(element);\n  });\n\n  test('reflected deserialize attributes', function() {\n    var element = fixture('reflect-to-attribute-and-attributes');\n    testAttributesMatchCustomConfiguration(element);\n  });\n\n  test('reflected warned about reflection for UPCASE', function() {\n    var element = fixture('reflect-to-attribute');\n    assert.isTrue(element.__warnedAboutUPCASE = true);\n  });\n});\n\nsuite('imperative attribute change (no-reflect)', function() {\n  var element, configuredObject, configuredArray;\n\n  setup(function() {\n    element = fixture('basic');\n    configuredObject = {foo: 'bar', nested: {'meaning': 42}, arr: [0, 'foo', true]};\n    configuredArray = [0, 'foo', true, {foo: 'bar'}];\n  });\n\n  test('change object attribute', function() {\n    element.setAttribute('object', '{\"foo\": \"bar\", \"nested\": {\"meaning\": 42}, \"arr\": [0, \"foo\", true]}');\n    assert.deepEqual(element.object, configuredObject);\n  });\n\n  test('change object attribute to foreign type', function() {\n    element.setAttribute('object', 'The quick brown fox');\n    assert.strictEqual(element.object, 'The quick brown fox');\n  });\n\n  test('change array attribute', function() {\n    element.setAttribute('array', '[0, \"foo\", true, {\"foo\": \"bar\"}]');\n    assert.deepEqual(element.array, configuredArray);\n  });\n\n  test('change number attribute', function() {\n    element.setAttribute('number', 42);\n    assert.strictEqual(element.number, 42);\n  });\n\n  test('change string attribute', function() {\n    element.setAttribute('string', 'howdy');\n    assert.strictEqual(element.string, 'howdy');\n  });\n\n  test('change boolean attribute true', function() {\n    element.setAttribute('bool', '');\n    assert.strictEqual(element.bool, true);\n  });\n\n  test('change boolean attribute truthy', function() {\n    element.setAttribute('bool', 'sure!');\n    assert.strictEqual(element.bool, true);\n  });\n\n  test('change boolean attribute false', function() {\n    element.setAttribute('bool', '');\n    assert.strictEqual(element.bool, true);\n    element.removeAttribute('bool');\n    assert.strictEqual(element.bool, false);\n  });\n\n  test('change dashCase attribute', function() {\n    element.setAttribute('dash-case', 'Changed');\n    assert.strictEqual(element.dashCase, 'Changed');\n  });\n\n  test('value that cannot deserialize from JSON warns', function() {\n    sinon.spy(console, 'warn');\n    var badAttr = '[foo, bar]';\n    element.setAttribute('array', badAttr);\n    assert.isTrue(console.warn.calledOnce);\n    assert.include(console.warn.firstCall.args[0], badAttr);\n    console.warn.restore();\n  });\n\n});\n\nsuite('imperative attribute change (reflect)', function() {\n  var element, configuredObject, configuredArray;\n\n  setup(function() {\n    element = fixture('reflect-to-attribute');\n    configuredObject = {foo: 'bar', nested: {'meaning': 42}, arr: [0, 'foo', true]};\n    configuredArray = [0, 'foo', true, {foo: 'bar'}];\n  });\n\n  test('change object attribute', function() {\n    element.setAttribute('object', '{\"foo\": \"bar\", \"nested\": {\"meaning\": 42}, \"arr\": [0, \"foo\", true]}');\n    assert.deepEqual(element.object, configuredObject);\n  });\n\n  test('change object attribute to foreign type', function() {\n    element.setAttribute('object', 'The quick brown fox');\n    assert.strictEqual(element.object, 'The quick brown fox');\n  });\n\n  test('change array attribute', function() {\n    element.setAttribute('array', '[0, \"foo\", true, {\"foo\": \"bar\"}]');\n    assert.deepEqual(element.array, configuredArray);\n  });\n\n  test('change number attribute', function() {\n    element.setAttribute('number', 42);\n    assert.strictEqual(element.number, 42);\n  });\n\n  test('change string attribute', function() {\n    element.setAttribute('string', 'howdy');\n    assert.strictEqual(element.string, 'howdy');\n  });\n\n  test('change boolean attribute true', function() {\n    element.setAttribute('bool', '');\n    assert.strictEqual(element.bool, true);\n  });\n\n  test('change boolean attribute truthy', function() {\n    element.setAttribute('bool', 'sure!');\n    assert.strictEqual(element.bool, true);\n  });\n\n  test('change boolean attribute false', function() {\n    element.setAttribute('bool', '');\n    assert.strictEqual(element.bool, true);\n    element.removeAttribute('bool');\n    assert.strictEqual(element.bool, false);\n  });\n\n  test('change dashCase attribute', function() {\n    element.setAttribute('dash-case', 'Changed');\n    assert.strictEqual(element.dashCase, 'Changed');\n  });\n\n  test('change non-`properties` property that natively reflects', function() {\n    element.title = 'awesome';\n    assert.strictEqual(element.title, 'awesome');\n    element.title = '';\n    assert.strictEqual(element.title, '');\n    element.setAttribute('title', 'super');\n    assert.strictEqual(element.title, 'super');\n    element.removeAttribute('title');\n    assert.strictEqual(element.title, '');\n  });\n\n});\n\nsuite('hostAttributes', function() {\n  var configuredObject;\n\n  setup(function() {\n    configuredObject = {foo: 'bar', nested: {'meaning': 42}, arr: [0, 'foo', true]};\n  });\n\n  test('hostAttributes set correctly', function() {\n    var element = fixture('basic');\n    assert.strictEqual(element.getAttribute('attr1'), 'this is attr 1');\n    assert.strictEqual(element.getAttribute('attr2'), '42');\n    assert.strictEqual(element.getAttribute('attr3'), 'instance', 'host attribute overrode instance attribute and should not');\n    assert.strictEqual(element.getAttribute('aria-role'), 'button');\n    assert.strictEqual(element.getAttribute('title'), 'awesome');\n    assert.strictEqual(element.title, 'awesome');\n    assert.equal(element.getAttribute('attr-object'), JSON.stringify(configuredObject));\n    assert.equal(element.hasAttribute('attr-stupid'), false);\n    // class *is* serialized\n    // BREAKME(sorvell): document breaking change.\n    assert.ok(element.classList.contains('foo'));\n    assert.ok(element.classList.contains('bar'));\n    assert.ok(element.classList.contains('baz'));\n\n  });\n\n  test('hostAttributes set correctly in composed element', function() {\n    var element = fixture('compose');\n    assert.strictEqual(element.$.basic.getAttribute('attr1'), 'compose');\n    assert.strictEqual(element.$.basic.getAttribute('attr2'), '42');\n    assert.strictEqual(element.$.basic.getAttribute('aria-role'), 'button');\n    assert.strictEqual(element.$.basic.getAttribute('title'), 'awesome');\n    assert.strictEqual(element.$.basic.title, 'awesome');\n\n    assert.equal(element.$.basic.getAttribute('attr-object'), JSON.stringify(configuredObject));\n    assert.equal(element.$.basic.hasAttribute('attr-stupid'), false);\n\n    // class does not overwrite user setting\n    assert.notOk(element.$.basic.classList.contains('foo'));\n    assert.notOk(element.$.basic.classList.contains('bar'));\n    assert.notOk(element.$.basic.classList.contains('baz'));\n\n    assert(element.$.basic.classList.contains('should-not-override'));\n\n    // applied to property with effect\n    assert.strictEqual(element.$.basic.prop, 'compose');\n    assert.equal(element.$.basic.propChangedCount, 1);\n    assert.equal(element.$.basic.attr1ChangedCount, 1);\n    assert.equal(element.prop2, 'hi');\n  });\n\n});\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/behaviors.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\">\n    import {setLegacyOptimizations} from '../../lib/utils/settings.js';\n    setLegacyOptimizations(Boolean(window.location.search.match('legacyOptimizations')));\n  </script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n<body>\n\n  <dom-module id=\"behavior-registered\">\n    <template>\n      <div id=\"content\"></div>\n    </template>\n  </dom-module>\n\n  <dom-module id=\"template-from-base\">\n    <template>\n      <div id=\"from-base\">should not be used</div>\n    </template>\n  </dom-module>\n\n  <script type=\"module\">\n    import { Polymer, html } from '../../polymer-legacy.js';\n    window.BehaviorA = {\n      properties: {\n\n        label: {\n          type: String,\n          observer: '_labelChanged'\n        },\n\n        hasOptionsA: {\n          readOnly: true,\n          notify: true\n        },\n\n        overridableProperty: {\n          value: false\n        },\n\n        overridablePropertyB: {\n          value: false\n        },\n\n        hasBehaviorA: {\n          value: true\n        },\n\n        computeADependency: {\n          value: true\n        },\n\n        computeA: {\n          computed: '_computeProp(computeADependency)'\n        }\n      },\n\n      observers: [],\n\n      _simpleProperty: 'A',\n\n      hostAttributes: {\n        behavior: 'A',\n        element: 'A',\n        user: 'A'\n      },\n\n      listeners: {\n        change: '_changeHandler'\n      },\n\n      ready: function() {\n        this.__readyA = true;\n      },\n\n      _labelChanged: function(label) {\n        this.__label = label;\n      },\n\n      _changeHandler: function(e) {\n        this.__change = e.detail.value;\n      },\n\n      _computeProp: function(a) {\n        return a;\n      }\n    };\n\n    window.BehaviorB = {\n      properties: {\n\n        disabled: {\n          type: Boolean,\n          value: false,\n          observer: '_disabledChanged'\n        },\n\n        hasOptionsB: {\n          readOnly: true,\n          notify: true\n        },\n\n        hasBehaviorB: {\n          value: true\n        },\n\n        overridablePropertyB: {\n          value: true\n        },\n\n        computeADependencyDependency: {\n          value: 'hi'\n        },\n\n        computeADependency: {\n          computed: '_computeProp(computeADependencyDependency)'\n        }\n\n      },\n\n      hostAttributes: {\n        behavior: 'B',\n        element: 'B',\n        user: 'B'\n      },\n\n      _simpleProperty: 'B',\n\n      _disabledChanged: function(disabled) {\n        this.__disabled = disabled;\n      },\n\n      ready: function() {\n        this.__readyB = true;\n      },\n    };\n\n    window.BehaviorC = {\n\n      properties: {\n\n        hasBehaviorC: {\n          value: true\n        }\n\n      },\n\n      _simpleProperty: 'C'\n    };\n\n    window.BehaviorD = {\n\n      properties: {\n\n        hasBehaviorD: {\n          value: true\n        }\n\n      },\n      _simpleProperty: 'D'\n\n    };\n\n    Polymer({\n      is: 'single-behavior',\n\n      behaviors: [\n        window.BehaviorA\n      ],\n\n      properties: {},\n      observers: [],\n      hostAttributes: {},\n      listeners: {}\n    });\n\n    Polymer({\n      is: 'multi-behaviors',\n\n      behaviors: [\n        window.BehaviorA,\n        window.BehaviorB\n      ],\n\n      hostAttributes: {\n        element: 'element'\n      },\n\n      properties: {\n\n        foo: {\n          type: String,\n          reflectToAttribute: true,\n          readOnly: true,\n          observer: '_fooChanged'\n        },\n\n        overridableProperty: {\n          value: true\n        }\n\n      },\n\n      _fooChanged: function(foo) {\n        this.__foo = foo;\n      },\n    });\n\n    Polymer({\n      is: 'nested-behaviors',\n\n      behaviors: [\n        [window.BehaviorB, [window.BehaviorC, window.BehaviorB], window.BehaviorA],\n        [window.BehaviorD]\n      ]\n    });\n\n    window.registerBehavior1 ={\n      beforeRegister: function() {\n        this._createPropertyObserver('beforeProp', 'beforePropChanged1');\n        this.beforeRegisterCount++;\n        this.beforeRegisterBehaviors = this.behaviors;\n      },\n      registered: function() {\n        this._createPropertyObserver('prop', 'propChanged1');\n        this._createMethodObserver('propChanged2(prop)');\n        this.registeredCount++;\n        this.registeredProps = [this.prop1, this.prop2, this.prop3, this.prop4];\n        this.registeredBehaviors = this.behaviors;\n      },\n      prop1: true,\n      ready: function() {\n        this._ensureAttribute('attr', true);\n      },\n      beforePropChanged1: function() {\n        this.beforePropChangedCalled = true;\n      },\n      propChanged1: function() {\n        this.propChanged1Called = true;\n      },\n      propChanged2: function() {\n        this.propChanged2Called = true;\n      }\n    };\n\n    window.registerBehavior2 ={\n      prop2: true,\n      beforeRegister: function() {\n        this.beforeRegisterCount++;\n      },\n      registered: function() {\n        this.registeredCount++;\n      }\n    };\n\n    window.registerBehavior3 ={\n      prop3: true,\n      beforeRegister: function() {\n        this.beforeRegisterCount++;\n      },\n      registered: function() {\n        this.registeredCount++;\n      }\n    };\n\n    Polymer({\n      behaviors: [\n        window.registerBehavior1,\n        window.registerBehavior2,\n        window.registerBehavior3\n      ],\n      prop4: true,\n      beforeRegister: function() {\n        this.beforeRegisterCount++;\n      },\n      registered: function() {\n        this.registeredCount++;\n      },\n\n      beforeRegisterCount: 0,\n      registeredCount: 0,\n\n      is: 'behavior-registered'\n    });\n\n    window.templateBehavior1 = {\n      _template: html`<div id=\"from-behavior1\"></div>`\n    };\n\n    window.templateBehavior2 = {\n      _template: html`<div id=\"from-behavior2\"></div>`\n    };\n\n    window.templateBehaviorFromRegistered = {\n      registered: function() {\n        this._template = html`<div id=\"behavior-from-registered\"></div>`;\n      }\n    };\n\n    Polymer({\n      is: 'template-from-registered',\n      registered: function() {\n        this._template = html`<div id=\"from-registered\"></div>`;\n      }\n    });\n\n    Polymer({\n      is: 'template-from-base',\n      behaviors: [\n        window.templateBehavior1\n      ]\n    });\n\n    Polymer({\n      is: 'template-from-behavior',\n      behaviors: [\n        window.templateBehavior1\n      ]\n    });\n\n    Polymer({\n      is: 'template-from-behavior-overridden',\n      behaviors: [\n        window.templateBehavior1,\n        window.templateBehavior2\n      ]\n    });\n\n    Polymer({\n      is: 'template-from-behavior-registered',\n      behaviors: [\n        window.templateBehaviorFromRegistered\n      ]\n    });\n\n    const getTemplateFromFunction = () => html`<div id=\"from-function\">[[prop]]</div>`;\n    Polymer({\n      is: 'template-from-function',\n      properties: { prop: {value: 'from-function'} },\n      _template: getTemplateFromFunction\n    });\n\n    const getTemplateFromBehaviorFunction = () => html`<div id=\"from-behavior-function\">[[prop]]</div>`;\n    const functionTemplateBehavior = {\n      _template: getTemplateFromBehaviorFunction\n    };\n    Polymer({\n      is: 'template-from-behavior-function',\n      properties: { prop: {value: 'from-behavior-function'} },\n      behaviors: [functionTemplateBehavior]\n    });\n\n    window.ModifyObserversBehavior = {\n\n      __barChangedCalled: 0,\n\n      beforeRegister: function() {\n        const observers = this.constructor.generatedFrom.observers;\n        this.constructor.generatedFrom.observers = observers.concat([\n          '_barChanged(bar)'\n        ]);\n      },\n\n      _barChanged: function() {\n        this.__barChangedCalled++;\n      }\n\n    };\n\n    Polymer({\n      is: 'modify-observers-via-behavior',\n      __zonkChangedCalled: 0,\n      observers: [\n        '_zonkChanged(zonk)'\n      ],\n      behaviors: [\n        window.ModifyObserversBehavior\n      ],\n      _zonkChanged: function() {\n        this.__zonkChangedCalled++;\n      }\n    });\n\n    Polymer({\n      is: 'behavior-properties',\n      behaviors: [window.BehaviorA]\n    });\n\n    Polymer({\n      is: 'no-accessors-behavior',\n      behaviors: [{\n        _noAccessors: true,\n        properties: {\n          nug: String\n        },\n        foo: function() {},\n        bar: true\n      }],\n      _noAccessors: true,\n      zot: 'zot'\n    });\n\n    Polymer({\n      is: 'override-default-value',\n      behaviors: [\n        {\n          properties: {\n            foo: { value: 'a' },\n            bar: { value: 'a' },\n            ziz: { value: 'a' }\n          }\n        },\n        {\n          properties: {\n            foo: { value: 'b' },\n            bar: String,\n            zot: { value: 'b' },\n            ziz: { value: 'b' }\n          }\n        },\n\n      ],\n\n      properties: {\n        foo: String,\n        zot: String,\n        ziz: { value: 'c' }\n      }\n    });\n\n    Polymer({\n      is: 'property-observer-readonly',\n      behaviors: [\n        {\n          observers: ['_changed(bar)'],\n          _changed() {}\n        }\n      ],\n\n      properties: {\n        bar: {readOnly: true}\n      }\n    });\n\n</script>\n\n  <test-fixture id=\"single\">\n    <template>\n      <single-behavior></single-behavior>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"multi\">\n    <template>\n      <multi-behaviors user=\"user\"></multi-behaviors>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"nested\">\n    <template>\n      <nested-behaviors></nested-behaviors>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"registered\">\n    <template>\n      <behavior-registered></behavior-registered>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"from-registered\">\n    <template>\n      <template-from-registered></template-from-registered>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"from-base\">\n    <template>\n      <template-from-base></template-from-base>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"from-behavior\">\n    <template>\n      <template-from-behavior></template-from-behavior>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"from-behavior-overridden\">\n    <template>\n      <template-from-behavior-overridden></template-from-behavior-overridden>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"from-behavior-registered\">\n    <template>\n      <template-from-behavior-registered></template-from-behavior-registered>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"from-function\">\n    <template>\n      <template-from-function></template-from-function>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"from-behavior-function\">\n    <template>\n      <template-from-behavior-function></template-from-behavior-function>\n    </template>\n  </test-fixture>\n\n\n  <test-fixture id=\"modify-observers-via-behavior\">\n    <template>\n      <modify-observers-via-behavior></modify-observers-via-behavior>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"behavior-properties\">\n    <template>\n      <behavior-properties></behavior-properties>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"no-accessors-behavior\">\n    <template>\n      <no-accessors-behavior></no-accessors-behavior>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"override-default-value\">\n    <template>\n      <override-default-value></override-default-value>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"property-observer-readonly\">\n    <template>\n      <property-observer-readonly></property-observer-readonly>\n    </template>\n  </test-fixture>\n\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\n\nsuite('single behavior element', function() {\n  var el;\n\n  setup(function() {\n    el = fixture('single');\n  });\n\n  test('is on prototype', function() {\n    assert.equal(el.is, 'single-behavior');\n  });\n\n  test('instance behaviors, properties, observers, hostAttributes, listeners', function() {\n    assert.isOk(el.behaviors);\n    assert.isOk(el.properties);\n    assert.isOk(el.observers);\n    assert.isOk(el.hostAttributes);\n    assert.isOk(el.listeners);\n  });\n\n  test('ready from behavior', function() {\n    assert.equal(el.__readyA, true);\n  });\n\n  test('properties from behavior', function() {\n    el.label = 'foo';\n    assert.equal(el.__label, 'foo');\n  });\n\n  test('listener from behavior', function() {\n    el.fire('change', {value: 'bar'});\n    assert.equal(el.__change, 'bar');\n  });\n\n  test('property info from behavior', function() {\n    assert.equal(el._hasNotifyEffect('hasOptionsA'), true);\n    assert.equal(el._hasReadOnlyEffect('hasOptionsA'), true);\n    assert.equal(typeof el._setHasOptionsA, 'function');\n  });\n\n  test('compute property from behavior', function() {\n    assert.equal(el.computeA, true);\n  });\n\n  test('special properties not copied from behavior to element', function() {\n    const el = fixture('behavior-properties');\n    assert.notOk(el.properties);\n    assert.notOk(el.observers);\n    assert.notOk(el.hostAttributes);\n    assert.notOk(el.listeners);\n  });\n\n  test('properties on objects marked with `_noAccessors` are copied to class', function() {\n    const el = fixture('no-accessors-behavior');\n    assert.ok(el.foo);\n    assert.isTrue(el.bar);\n    assert.equal(el.zot, 'zot');\n    el.setAttribute('nug', 'nug');\n    assert.equal(el.nug, 'nug');\n  });\n\n  test('behavior default values can be overridden', function() {\n    const el = fixture('override-default-value');\n    assert.equal(el.foo, 'b');\n    assert.equal(el.bar, 'a');\n    assert.equal(el.zot, 'b');\n    assert.equal(el.ziz, 'c');\n  });\n\n  test('readOnly not applied when property was previously observed', function() {\n    const el = fixture('property-observer-readonly');\n    el.bar = 5;\n    assert.equal(el.bar, 5);\n  });\n\n});\n\nsuite('behavior.registered', function() {\n  test('can install dynamic properties', function() {\n    var el = fixture('registered');\n    assert.ok(el.$.content);\n    el.prop = 42;\n    assert.isTrue(el.propChanged1Called);\n    assert.isTrue(el.propChanged2Called);\n    assert.isTrue(el.hasAttribute('attr'));\n  });\n\n  test('called once for each behavior with access to element prototype', function() {\n    var el = fixture('registered');\n    assert.equal(el.registeredCount, 4);\n    assert.equal(el.registeredBehaviors.length, 3);\n    assert.equal(el.registeredBehaviors, el.behaviors);\n    assert.deepEqual(el.registeredProps, [true, true, true, true]);\n  });\n\n});\n\nsuite('behavior.beforeRegister', function() {\n  test('can install dynamic properties', function() {\n    var el = fixture('registered');\n    assert.ok(el.$.content);\n    el.beforeProp = 43;\n    assert.isTrue(el.beforePropChangedCalled);\n  });\n\n  test('called once for each behavior with access to element prototype', function() {\n    var el = fixture('registered');\n    assert.equal(el.beforeRegisterCount, 4);\n    assert.equal(el.beforeRegisterBehaviors.length, 3);\n    assert.equal(el.beforeRegisterBehaviors, el.behaviors);\n  });\n\n  test('modify element observers', function() {\n    var el = fixture('modify-observers-via-behavior');\n    el.bar = 1;\n    assert.equal(el.__barChangedCalled, 1);\n    el.zonk = 1;\n    assert.equal(el.__zonkChangedCalled, 1);\n  });\n\n});\n\nsuite('multi-behaviors element', function() {\n  var el;\n\n  setup(function() {\n    el = fixture('multi');\n  });\n\n  test('ready from behaviors', function() {\n    assert.equal(el.__readyA, true);\n    assert.equal(el.__readyB, true);\n  });\n\n  test('properties from behaviors', function() {\n    el.label = 'foo';\n    assert.equal(el.__label, 'foo');\n    el.disabled = true;\n    assert.equal(el.__disabled, true);\n  });\n\n  test('properties from itself', function() {\n    assert.isDefined(el._setFoo, 'readOnly setter not available');\n    el._setFoo('bar');\n    assert.equal(el.__foo, 'bar', 'observer not getting called');\n    assert.equal(el.getAttribute('foo'), 'bar', 'not getting reflected');\n  });\n\n  test('listener from behaviors', function() {\n    el.fire('change', {value: 'bar'});\n    assert.equal(el.__change, 'bar');\n  });\n\n  test('property info from behavior A', function() {\n    assert.equal(el._hasNotifyEffect('hasOptionsA'), true);\n    assert.equal(el._hasReadOnlyEffect('hasOptionsA'), true);\n    assert.equal(typeof el._setHasOptionsA, 'function');\n  });\n\n  test('property info from behavior B', function() {\n    assert.equal(el._hasReadOnlyEffect('hasOptionsB'), true);\n    assert.equal(el._hasNotifyEffect('hasOptionsB'), true);\n    assert.equal(typeof el._setHasOptionsB, 'function');\n  });\n\n  test('computed property dependency can become a computed property', function() {\n    assert.equal(el.computeA, 'hi');\n  });\n\n  test('multi-behavior overrides ordering', function() {\n    assert(el.overridableProperty, 'Behavior property was not overridden by prototype');\n    assert(el.overridablePropertyB, 'Behavior config-property was not overridden by sub-behavior');\n  });\n\n  test('hostAttributes ordering', function() {\n    assert.equal(el.attributes.behavior.value, 'B', 'Behavior hostAttribute not overridden by younger behavior');\n    assert.equal(el.attributes.element.value, 'element', 'Behavior hostAttribute overridden by behavior');\n    assert.equal(el.attributes.user.value, 'user', 'Behavior hostAttribute overrode user attribute');\n  });\n\n  test('behavior is null generates warning', function() {\n    sinon.spy(console, 'warn');\n    Polymer({\n      is: 'behavior-null',\n      behaviors: [\n        null\n      ]\n    });\n    document.createElement('behavior-null');\n    assert.equal(console.warn.callCount, 1, 'Null behaviour should generate warning');\n    console.warn.restore();\n  });\n\n  test('behavior array is unique', function() {\n    Polymer({\n      is: 'behavior-unique',\n      behaviors: [window.BehaviorA, window.BehaviorA]\n    });\n    assert.equal(document.createElement('behavior-unique').behaviors.length, 1);\n  });\n\n  test('duplicate behaviors keep first behavior', function() {\n    Polymer({\n      is: 'behavior-unique-last-behavior',\n      behaviors: [window.BehaviorA, window.BehaviorB, window.BehaviorC, window.BehaviorA, window.BehaviorB]\n    });\n    var behaviors = document.createElement('behavior-unique-last-behavior').behaviors;\n    assert.deepEqual(behaviors, [window.BehaviorC, window.BehaviorA, window.BehaviorB]);\n  });\n\n});\n\nsuite('nested-behaviors element', function() {\n  var el;\n\n  setup(function() {\n    el = fixture('nested');\n  });\n\n  test('nested-behavior dedups', function() {\n    assert.equal(el.behaviors.length, 4);\n  });\n\n  test('nested-behavior overrides ordering', function() {\n    assert.ok(el.hasBehaviorA, \"missing BehaviorA\");\n    assert.ok(el.hasBehaviorB, \"missing BehaviorB\");\n    assert.ok(el.hasBehaviorC, \"missing BehaviorC\");\n    assert.ok(el.hasBehaviorD, \"missing BehaviorD\");\n    assert.equal(el._simpleProperty, 'D', 'Behavior simple property was not overridden by sub-behavior');\n  });\n\n});\n\nsuite('templates from behaviors', function() {\n\n  test('template from registered callback', function() {\n    var el = fixture('from-registered');\n    assert.ok(el.shadowRoot.querySelector('#from-registered'));\n  });\n\n  test('template from base', function() {\n    var el = fixture('from-base');\n    assert.notOk(el.shadowRoot.querySelector('#from-base'));\n    assert.ok(el.shadowRoot.querySelector('#from-behavior1'));\n  });\n\n  test('template from behavior', function() {\n    var el = fixture('from-behavior');\n    assert.ok(el.shadowRoot.querySelector('#from-behavior1'));\n  });\n\n  test('template from overriding behavior', function() {\n    var el = fixture('from-behavior-overridden');\n    assert.notOk(el.shadowRoot.querySelector('#from-behavior1'));\n    assert.ok(el.shadowRoot.querySelector('#from-behavior2'));\n  });\n\n  test('template from behavior registered callback', function() {\n    var el = fixture('from-behavior-registered');\n    assert.ok(el.shadowRoot.querySelector('#behavior-from-registered'));\n  });\n\n});\n\nsuite('template from function', function() {\n  \n  test('template function assigned to _template', () => {\n    var el = fixture('from-function');\n    const div = el.shadowRoot.querySelector('#from-function');\n    assert.ok(div);\n    assert.equal(div.textContent, 'from-function');\n  });\n\n  test('template function assigned to _template in behavior', () => {\n    var el = fixture('from-behavior-function');\n    const div = el.shadowRoot.querySelector('#from-behavior-function');\n    assert.ok(div);\n    assert.equal(div.textContent, 'from-behavior-function');\n  });\n  \n});\n\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/case-map.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../lib/utils/case-map.js\"></script>\n</head>\n<body>\n\n<script type=\"module\">\nimport { camelToDashCase, dashToCamelCase } from '../../lib/utils/case-map.js';\nsuite('case-map', function() {\n  test('camelToDashCase converts to dashes', function() {\n    assert.equal(camelToDashCase('camelCase'), 'camel-case');\n    assert.equal(camelToDashCase('camelCCase'), 'camel-c-case');\n  });\n\n  test('dashToCamelCase converts to camelCase', function() {\n    assert.equal(dashToCamelCase('camel-case'), 'camelCase');\n    assert.equal(dashToCamelCase('camel-c-case'), 'camelCCase');\n  });\n\n  test('camelToDashCase and dashToCamelCase reverse the other function', function() {\n    var camelCase = dashToCamelCase('camel-c-case');\n    assert.equal(camelToDashCase(camelCase), 'camel-c-case');\n  });\n});\n</script>\n"
  },
  {
    "path": "test/unit/class-properties.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n</head>\n<body>\n  <script type=\"module\">\n    import {Polymer} from '../../polymer-legacy.js';\n    class Example {\n      ready() {}\n      foo() {}\n    }\n    Example.prototype.is = 'x-example';\n\n    suite('Polymer function w/Class', function() {\n      test('Polymer call works with a class', function() {\n        assert.doesNotThrow(() => Polymer(Example.prototype));\n      });\n      test('methods are copied from class input', function() {\n        const def = customElements.get('x-example');\n        assert(def.prototype.ready, 'ready should be defined');\n        assert(def.prototype.foo, 'foo should be defined');\n      });\n    });\n  </script>\n</body>\n</html>"
  },
  {
    "path": "test/unit/configure.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n</head>\n<body>\n  <script type=\"module\">\nwindow.configureBehavior = {\n\n  changeHandlerCount: 0,\n  objectChangeHandlerCount: 0,\n\n  contentChanged: function() {\n    this.changeHandlerCount++;\n    this.stomp = 10;\n  },\n  objectChanged: function() {\n    this.objectChangeHandlerCount++;\n  }\n};\n</script>\n\n  <dom-module id=\"x-configure-value\">\n    <template>\n      <span id=\"content\">{{content}}</span>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n\n  is: 'x-configure-value',\n\n  behaviors: [window.configureBehavior],\n\n  properties: {\n    content: {\n      type: String,\n      notify: true,\n      observer: 'contentChanged',\n      value: 'default'\n    },\n    object: {\n      type: Object,\n      notify: true,\n      value: function() { return {foo: 'obj-default'}; },\n      observer: 'objectChanged'\n    },\n    readOnly: {\n      readOnly: true,\n      value: 'default'\n    },\n    stomp: {\n      value: 5\n    }\n  }\n\n});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-configure-gchild\">\n    <template>\n      <span id=\"content\">{{content}}</span>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n\n  is: 'x-configure-gchild',\n\n  behaviors: [window.configureBehavior],\n\n  properties: {\n    content: {\n      type: String,\n      notify: true,\n      observer: 'contentChanged',\n      value: 'gchild'\n    },\n    object: {\n      type: Object,\n      notify: true,\n      value: function() { return {foo: 'obj-default'}; },\n      observer: 'objectChanged'\n    },\n    readOnly: {\n      readOnly: true,\n      value: 'default'\n    },\n    stomp: {\n      value: 5\n    }\n  }\n\n});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-configure-child\">\n    <template>\n      <x-configure-gchild id=\"gchild\" content=\"{{content}}\" object=\"{{object}}\"></x-configure-gchild>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n\n  is: 'x-configure-child',\n\n  behaviors: [window.configureBehavior],\n\n  properties: {\n    content: {\n      type: String,\n      notify: true,\n      observer: 'contentChanged',\n      value: 'child'\n    },\n    negatedContent: {\n      type: Boolean,\n      observer: 'negatedContentChanged',\n      value: true\n    },\n    compoundInput: {\n      type: String,\n      observer: 'compoundInputChanged',\n      value: 'default'\n    },\n    object: {\n      type: Object,\n      notify: true,\n      value: function() { return {foo: 'obj-default'}; },\n      observer: 'objectChanged'\n    },\n    readOnly: {\n      readOnly: true,\n      value: 'default'\n    },\n    stomp: {\n      value: 5\n    },\n    attrDash: {\n      observer: 'attrDashChanged',\n      value: 'default'\n    },\n    attrNumber: {\n      type: Number,\n      observer: 'attrNumberChanged',\n      value: 0\n    },\n    attrBoolean: {\n      type: Boolean,\n      observer: 'attrBooleanChanged',\n      value: false\n    }\n  },\n\n  created: function() {\n    this.attrDashChanged = sinon.spy();\n    this.attrNumberChanged = sinon.spy();\n    this.attrBooleanChanged = sinon.spy();\n    this.negatedContentChanged = sinon.spy();\n    this.compoundInputChanged = sinon.spy();\n  }\n\n});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-configure-simple-child\">\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n\n  is: 'x-configure-simple-child',\n\n  properties: {\n    noeffect: String\n  },\n\n  ready: function() {\n    this.hasPropertyAtReadyTime = (this.noeffect !== undefined);\n  }\n\n});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-configure-host\">\n    <template>\n      <x-configure-child id=\"child\"\n          content=\"{{content}}\"\n          negated-content=\"[[!content]]\"\n          compound-input=\"a [[simple]] [[content]]\"\n          object=\"{{object.goo}}\"\n          attr$=\"{{attrValue}}\"\n          attr-dash$=\"{{attrValue}}\"\n          attr-number$=\"{{attrNumber}}\"\n          attr-boolean$=\"{{attrBoolean}}\"\n      ></x-configure-child>\n      <x-configure-simple-child id=\"simple\" noeffect=\"{{simple}}\"></x-configure-simple-child>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n\n  is: 'x-configure-host',\n\n  behaviors: [window.configureBehavior],\n\n  properties: {\n    content: {\n      type: String,\n      notify: true,\n      observer: 'contentChanged',\n      value: 'host'\n    },\n    object: {\n      type: Object,\n      notify: true,\n      value: function() { return {goo: {foo: 'obj-host'}}; },\n      observer: 'objectChanged'\n    },\n    readOnly: {\n      readOnly: true,\n      value: 'default'\n    },\n    stomp: {\n      value: 5\n    },\n    attrValue: {\n      value: 'attrValue'\n    },\n    attrNumber: {\n      value: 42\n    },\n    attrBoolean: {\n      value: false\n    },\n    simple: {\n      value: 'simple'\n    }\n  }\n});\n</script>\n  </dom-module>\n\n  <script type=\"module\">\nwindow.XConfigLazy = {\n  is: 'x-config-lazy',\n  properties: {\n    noEffectProp: Number,\n    defaultUsesNoEffectProp: {\n      type: Number\n    },\n    boundNoEffectProp: {\n      type: Number,\n      value: 5\n    },\n    prop: {\n      value: 'lazy',\n      observer: 'propChanged'\n    },\n    readOnlyProp: {\n      readOnly: true,\n      value: 'readOnly'\n    },\n    hadAttrProp: {\n      value: 'hadAttrProp',\n      observer: 'hadAttrPropChanged'\n    }\n  },\n  created: function() {\n    this.noEffectProp = 1;\n    this.defaultUsesNoEffectProp = this.noEffectProp * 2;\n    this.propChanged = sinon.spy();\n    this.hadAttrPropChanged = sinon.spy();\n  }\n};\n</script>\n\n  <dom-module id=\"x-config-lazy-nodefaults\">\n    <template>\n      <div>x-config-lazy-nodefaults</div>\n    </template>\n    <script type=\"module\">\nwindow.XConfigLazyNoDefaults = {\n  is: 'x-config-lazy-nodefaults',\n  properties: {\n    prop: {\n      observer: 'propChanged'\n    }\n  },\n  created: function() {\n    this.propChanged = sinon.spy();\n  }\n};\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-config-lazy-host\">\n    <template>\n      <x-config-lazy id=\"lazy\" prop=\"{{foo}}\" read-only-prop=\"{{foo}}\" had-attr-prop=\"attrValue\" bound-no-effect-prop=\"{{foo}}\"></x-config-lazy>\n      <x-config-lazy-nodefaults prop=\"[[foo]]\"></x-config-lazy-nodefaults>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-config-lazy-host',\n  properties: {\n    foo: {\n      value: 'foo',\n      observer: 'fooChanged'\n    }\n  },\n  fooChanged: function(foo) {\n    this.$.lazy.hadAttrProp = foo;\n  }\n});\n</script>\n  </dom-module>\n\n  <x-configure-value></x-configure-value>\n\n  <x-configure-value content=\"attr\" object='{\"foo\": \"obj-attr\"}'></x-configure-value>\n\n  <x-configure-host></x-configure-host>\n\n  <x-configure-host content=\"attr\"></x-configure-host>\n\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\n\nfunction testValueAndChangeHandler(e, value) {\n  assert.equal(e.content, value, 'Property does not equal configured value');\n  assert.equal(e.changeHandlerCount, 1, 'property `change` Change handler not run when default value set');\n  assert.equal(e.objectChangeHandlerCount, 1, 'property `object` Change handler not run when default value set');\n}\n\nfunction testConfigure(e, value, objectValue) {\n  testValueAndChangeHandler(e, value);\n  assert.equal(e.object.foo, objectValue);\n  assert.equal(e.$.content.textContent, value, 'Bound value not propagated to dom');\n}\n\nfunction testConfigureHost(e, value) {\n  testValueAndChangeHandler(e, value);\n  e = e.$.child;\n  testValueAndChangeHandler(e, value);\n  e = e.$.gchild;\n  testValueAndChangeHandler(e, value);\n  assert.equal(e.$.content.textContent, value, 'Bound value not propagated to dom');\n}\n\nsuite('configure', function() {\n\n  test('value set in properties initializes correctly', function() {\n    var e = document.querySelector('x-configure-value');\n    testConfigure(e, 'default', 'obj-default');\n  });\n\n  test('attribute overrides value set in properties', function() {\n    var e = document.querySelector('x-configure-value[content]');\n    testConfigure(e, 'attr', 'obj-attr');\n  });\n\n  test('configured values initialize and propagates', function() {\n    var e = document.querySelector('x-configure-host');\n    testConfigureHost(e, 'host');\n  });\n\n  test('negated value configured correctly', function() {\n    var e = document.querySelector('x-configure-host');\n    assert.equal(e.$.child.negatedContent, false);\n    assert.isTrue(e.$.child.negatedContentChanged.calledOnce, 'negated content not changed exactly once');\n  });\n\n  test('compound effect resulting value set once', function() {\n    var e = document.querySelector('x-configure-host');\n\n    assert.equal(e.$.child.compoundInput, 'a simple host');\n    assert.isTrue(e.$.child.compoundInputChanged.calledOnce, 'compound content not changed exactly once');\n  });\n\n  test('attribute overrides configured values and propagates', function() {\n    var e = document.querySelector('x-configure-host[content]');\n    testConfigureHost(e, 'attr');\n  });\n\n  test('property changed in change handler of another not stomped by default', function() {\n    var e = document.querySelector('x-configure-value');\n    assert.equal(e.stomp, 10);\n  });\n\n  test('read-only property initialized to default value', function() {\n    var e = document.querySelector('x-configure-value');\n    assert.equal(e.readOnly, 'default');\n  });\n\n  test('attribute bindings to properties without effects not configured', function() {\n    var e = document.querySelector('x-configure-host');\n    assert.equal(e.$.child.getAttribute('attr'), 'attrValue');\n    assert.equal(e.$.child.attr, undefined);\n  });\n\n  test('attribute bindings to properties with effects configured', function() {\n    var e = document.createElement('x-configure-host');\n    document.body.appendChild(e);\n\n    assert.equal(e.$.child.getAttribute('attr-dash'), 'attrValue');\n    assert.notProperty(e.$.child, 'attr-dash');\n    assert.equal(e.$.child.attrDash, 'attrValue');\n    assert.isTrue(e.$.child.attrDashChanged.calledOnce);\n    assert.equal(e.$.child.attrDashChanged.getCall(0).args[0], 'attrValue');\n\n    assert.equal(e.$.child.getAttribute('attr-number'), '42');\n    assert.notProperty(e.$.child, 'attr-number');\n    assert.strictEqual(e.$.child.attrNumber, 42);\n    assert.isTrue(e.$.child.attrNumberChanged.calledOnce);\n    assert.strictEqual(e.$.child.attrNumberChanged.getCall(0).args[0], 42);\n\n    assert.equal(e.$.child.hasAttribute('attr-boolean'), false);\n    assert.notProperty(e.$.child, 'attr-boolean');\n    // Attribute bindings are no longer specially\n    // configured to properties as they were with 1.0. This should\n    // only affect bindings that set false (removing a non-existing attribute)\n    // to override a default of true (which is an odd default for a boolean attr).\n    assert.strictEqual(e.$.child.attrBoolean, false);\n    assert.isTrue(e.$.child.attrBooleanChanged.calledOnce);\n    assert.strictEqual(e.$.child.attrBooleanChanged.getCall(0).args[0], false);\n  });\n\n  test('bindings to properties without effects configured', function() {\n    var e = document.createElement('x-configure-host');\n    document.body.appendChild(e);\n    assert.isTrue(e.$.simple.hasPropertyAtReadyTime, 'property value not configured and therefore not set at ready time');\n  });\n\n  test('pre-register property assignment does not break getters and setters', function() {\n    var x = document.createElement('x-late-register');\n    document.body.appendChild(x);\n    // set property\n    x.shouldChange = '1';\n    // now register element\n    Polymer({\n      is: 'x-late-register',\n      properties: {\n        shouldChange : {\n          observer: 'shouldChangeCallback',\n          type: String\n        }\n      },\n      shouldChangeCallback: function() {\n        this.textContent = this.shouldChange;\n      }\n    });\n    assert.equal(x.shouldChange, '1');\n    assert.equal(x.shouldChange, x.textContent);\n    x.shouldChange = '2';\n    assert.equal(x.shouldChange, '2');\n    assert.equal(x.shouldChange, x.textContent);\n    document.body.removeChild(x);\n  });\n\n  // Created is no longer called before\n  // default properties are set. This means values set in created cannot\n  // be used to calculate defaults. However, defaults can now be set for\n  // any property (including those with effects) in created.\n  test('setting properties in created works with configuration', function() {\n    var x = document.createElement('x-late-register2');\n    document.body.appendChild(x);\n    // now register element\n    Polymer({\n      is: 'x-late-register2',\n      properties: {\n        a: {\n          type: Number,\n          value: 0\n        },\n        b: {\n          type: Number\n        }\n      },\n      created: function() {\n        this.a = 1;\n        this.b = this.a * 2;\n      }\n    });\n    assert.equal(x.b, 2);\n    document.body.removeChild(x);\n  });\n\n  test('lazy upgrade binding use cases', function() {\n    var el = document.createElement('x-config-lazy-host');\n    document.body.appendChild(el);\n    Polymer(window.XConfigLazy);\n    // The purpose of this test is to test lazy upgrading an element that\n    // has a property pre-bound to it (that has an accessor) but that has\n    // no defaults for it (stresses a prior bug in ready() code that called\n    // _attachDom twice, which throws in Safari's native SD\n    Polymer(window.XConfigLazyNoDefaults);\n    assert.equal(el.$.lazy.noEffectProp, 1);\n    assert.equal(el.$.lazy.defaultUsesNoEffectProp, 2);\n    assert.equal(el.$.lazy.boundNoEffectProp, 'foo');\n    assert.equal(el.$.lazy.prop, 'foo');\n    assert.isTrue(el.$.lazy.propChanged.calledOnce);\n    assert.equal(el.$.lazy.readOnlyProp, 'readOnly');\n    assert.equal(el.$.lazy.hadAttrProp, 'foo');\n    assert.isTrue(el.$.lazy.hadAttrPropChanged.calledOnce);\n    document.body.removeChild(el);\n  });\n\n});\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/css-parse.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n\n  <meta charset=\"utf-8\">\n\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n\n  <title>css-parse</title>\n\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n\n</head>\n<body>\n\n  <style id=\"test\">\n    :host {\n      background: red;\n    }\n\n    .foo .bar .baz, zonk[happy]:focus {\n      font-family: sans-serif;\n      font-size: 15px;\n    }\n\n    @-webkit-keyframes fill-unfill-rotate {\n      12.5% { transform: rotate(135deg);  }\n      25%   { transform: rotate(270deg);  }\n      37.5% { transform: rotate(405deg);  }\n      50%   { transform: rotate(540deg);  }\n      62.5% { transform: rotate(675deg);  }\n      75%   { transform: rotate(810deg);  }\n      87.5% { transform: rotate(945deg);  }\n      to    { transform: rotate(1080deg); }\n    }\n\n    @media (max-width: 400px) {\n      div {\n        margin-left: 0 !important;\n      }\n    }\n  </style>\n\n  <style id=\"test-ignore\">\n    @import '';\n\n    /* comment */\n    .stuff {\n      background: red;\n    }\n    /* comment */\n\n    /*\n      This is a multi-line comment\n    */\n\n    /*.aclassThatShouldBeIgnored {\n      someProperty: thatMustNotShowUp\n    }*/\n  </style>\n\n  <style id=\"short-escape-sequence\">\n    .\\33 d-model {\n      border-top: 3px solid red;\n    }\n    .\\a33 d-model {\n      border-top: 3px solid red;\n    }\n    .\\b333 d-model {\n      border-top: 3px solid red;\n    }\n    .\\c3333 d-model {\n      border-top: 3px solid red;\n    }\n    .\\d33333 d-model {\n      border-top: 3px solid red;\n    }\n    .\\e33333d-model {\n      border-top: 3px solid red;\n    }\n  </style>\n\n  <style id=\"multiple-spaces\">\n    .foo  .bar {}\n    .foo    .bar {}\n    .foo\n\n\n    .bar {}\n  </style>\n<script type=\"module\">\n\nfunction sanitizeCss(text) {\n  return text.replace(/[\\s]+/g, ' ').trim();\n}\n\nsuite('css-parse', function() {\n  var css, s, tree;\n\n  setup(function() {\n    css = Polymer.CssParse;\n    s = document.querySelector('style#test');\n    tree = css.parse(s.textContent);\n  });\n\n  test('css rules parse', function() {\n    assert.equal(tree.rules.length, 4, 'unexpected number of rules');\n    assert.equal(tree.rules[2].rules.length, 8, 'unexpected number of rules in keyframes');\n    assert.equal(tree.rules[3].rules.length, 1, 'unexpected number of rules in @media');\n  });\n\n  test('rule selectors parse', function() {\n    assert.equal(tree.rules[0].selector, ':host', 'unexpected selector');\n    assert.equal(tree.rules[2].selector, '@-webkit-keyframes fill-unfill-rotate', 'unexpected selector in keyframes');\n    assert.equal(tree.rules[3].selector, '@media (max-width: 400px)', 'unexpected selector in @media');\n  });\n\n  test('rule cssText parse', function() {\n    assert.equal(tree.rules[0].cssText, 'background: red;', 'unexpected cssText');\n    assert.match(tree.rules[2].cssText, /^12.5%/, 'unexpected cssText in keyframes');\n    assert.equal(tree.rules[2].rules[2].cssText, 'transform: rotate(405deg);', 'unexpected cssText in keyframes');\n    assert.match(tree.rules[3].cssText, /^div/, 'unexpected cssText in @media');\n    assert.equal(tree.rules[3].rules[0].cssText, 'margin-left: 0 !important;', 'unexpected cssText in @media');\n  });\n\n  test('rule types', function() {\n    assert.equal(tree.rules[0].type, css.types.STYLE_RULE);\n    assert.equal(tree.rules[1].type, css.types.STYLE_RULE);\n    assert.equal(tree.rules[2].type, css.types.KEYFRAMES_RULE);\n    assert.equal(tree.rules[3].type, css.types.MEDIA_RULE);\n    assert.equal(tree.rules[3].rules[0].type, css.types.STYLE_RULE);\n\n  });\n\n  test('rules stringify', function() {\n    var orig = sanitizeCss(s.textContent);\n    var result = sanitizeCss(css.stringify(tree));\n    assert.equal(result, orig, 'unexpected stringified output');\n  });\n\n  test('parse correctly ignores @import and comments', function() {\n    var s2 = document.querySelector('#test-ignore');\n    var t = css.parse(s2.textContent);\n    assert.equal(t.rules[0].selector, '.stuff', 'unexpected rule selector');\n    assert.equal(t.rules[0].cssText, 'background: red;', 'unexpected rule cssText');\n    var result = sanitizeCss(css.stringify(t));\n    assert.equal(result, '.stuff { background: red; }', 'unexpected stringified output');\n  });\n\n  test('short escape sequences', function() {\n    var s3 = document.querySelector('#short-escape-sequence');\n    var t = css.parse(s3.textContent);\n    assert.equal(t.rules[0].selector, '.\\\\000033d-model');\n    assert.equal(t.rules[1].selector, '.\\\\000a33d-model');\n    assert.equal(t.rules[2].selector, '.\\\\00b333d-model');\n    assert.equal(t.rules[3].selector, '.\\\\0c3333d-model');\n    assert.equal(t.rules[4].selector, '.\\\\d33333d-model');\n    assert.equal(t.rules[5].selector, '.\\\\e33333d-model');\n  });\n\n  test('multiple consequent spaces in CSS selector', function() {\n    var s4 = document.querySelector('#multiple-spaces');\n    var t = css.parse(s4.textContent);\n    assert.equal(t.rules[0].selector, '.foo .bar');\n    assert.equal(t.rules[1].selector, '.foo .bar');\n    assert.equal(t.rules[2].selector, '.foo .bar');\n  });\n\n});\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/custom-style-async-import.html",
    "content": "<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<custom-style>\n  <style is=\"custom-style\">\n    html {\n      --cs-blue: {\n        border : 8px solid blue;\n      };\n    }\n  </style>\n</custom-style>\n<dom-module id=\"x-client\">\n  <template>\n    <style>\n      :host {\n        display: inline-block;\n        border : 4px solid red;\n        @apply (--cs-blue);\n      }\n    </style>\n    x-client\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../lib/legacy/polymer-fn.js';\nPolymer({\n  is: 'x-client'\n});\n</script>\n</dom-module>\n"
  },
  {
    "path": "test/unit/custom-style-async-import.js",
    "content": "import { Polymer } from '../../lib/legacy/polymer-fn.js';\n\nconst $_documentContainer = document.createElement('template');\n\n$_documentContainer.innerHTML = `<custom-style>\n<style is=\"custom-style\">\n  html {\n    --cs-blue: {\n      border : 8px solid blue;\n    };\n  }\n</style>\n</custom-style>\n<dom-module id=\"x-client\">\n<template>\n  <style>\n    :host {\n      display: inline-block;\n      border : 4px solid red;\n      @apply (--cs-blue);\n    }\n  </style>\n  x-client\n</template>\n</dom-module>`;\n\ndocument.body.appendChild($_documentContainer.content);\n\nPolymer({\n  is: 'x-client'\n});\n"
  },
  {
    "path": "test/unit/custom-style-async.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n\n</head>\n<body>\n\n  <dom-module id=\"x-host\">\n    <template>\n      <style>\n        :host {\n          display: inline-block;\n          border: 4px solid orange;\n          padding: 4px;\n        }\n        .whatever { color: var(--whatever); }\n      </style>\n      <x-client id=\"client\"></x-client>\n    </template>\n  </dom-module>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-host'\n});\n</script>\n\n  <x-host id=\"host\"></x-host>\n\n  <script type=\"module\">\nimport { afterNextRender } from '../../lib/utils/render-status.js';\n/* global host */\n\nsuite('async global custom-style', function() {\n\n  test('async loaded custom-style applies', function(done) {\n    import('./custom-style-async-import.js').then(() => {\n      afterNextRender(null, function() {\n        assertComputed(host.$.client, '8px');\n        done();\n      });\n    });\n  });\n\n});\n\nfunction assertComputed(element, value, property, pseudo) {\n  var computed = getComputedStyle(element, pseudo);\n  property = property || 'border-top-width';\n  assert.equal(computed[property], value, 'computed style incorrect for ' + property);\n}\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/custom-style-import.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\nimport './sub/style-import.js';\nconst $_documentContainer = document.createElement('template');\n$_documentContainer.setAttribute('style', 'display: none;');\n\n$_documentContainer.innerHTML = `<dom-module id=\"shared-style\">\n  <template>\n    <style>\n      html {\n        --import-var: 3px solid orange;\n      }\n    </style>\n  </template>\n</dom-module><dom-module id=\"shared-style2\">\n  <template>\n    <style>\n      .zazz {\n        border: 16px solid orange;\n      }\n    </style>\n  </template>\n</dom-module><custom-style>\n<style is=\"custom-style\" include=\"shared-style style-import\n  style-import2\">\n  html {\n\n    --import-mixin: {\n      border: 4px solid blue;\n    };\n\n    padding: 10px;\n  }\n</style>\n</custom-style>`;\n\ndocument.head.appendChild($_documentContainer.content);\n"
  },
  {
    "path": "test/unit/custom-style-late.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n</head>\n<body>\n\n  <custom-style>\n    <style is=\"custom-style\">\n      x-input {\n        border: 4px solid red;\n        @apply --cs-blue;\n      }\n    </style>\n  </custom-style>\n\n  <template id=\"late\">\n  <custom-style>\n    <style is=\"custom-style\">\n      html {\n        --cs-blue: {\n          border: 8px solid blue;\n        };\n      }\n    </style>\n  </custom-style>\n  </template>\n\n  <x-input id=\"input\"></x-input>\n\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nimport { afterNextRender } from '../../lib/utils/render-status.js';\n/* global input */\n\nsuite('custom-style late property definition', function() {\n\n  test('late defined properties applied to custom-style', function(done) {\n    Polymer({\n      is: 'x-input'\n    });\n    var template = document.querySelector('template#late');\n    document.body.appendChild(document.importNode(template.content, true));\n    // wait 2 rounds of `afterNextRender` as `<custom-style>` boots asynchronously\n    afterNextRender(null, function() {\n      afterNextRender(null, function() {\n        assertComputed(input, '8px');\n        done();\n      });\n    });\n  });\n\n});\n\nfunction assertComputed(element, value, property, pseudo) {\n  var computed = getComputedStyle(element, pseudo);\n  property = property || 'border-top-width';\n  assert.equal(computed[property], value, 'computed style incorrect for ' + property);\n}\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/custom-style-scope-cache.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n\n</head>\n<body>\n  <custom-style>\n    <style is=\"custom-style\">\n      .c {\n        --cache-element-border: 8px solid blue;\n      }\n    </style>\n  </custom-style>\n  <dom-module id=\"cache-element\">\n    <template>\n      <style>\n        :host {\n          display: block;\n          border: var(--cache-element-border, 4px solid orange);\n        }\n      </style>\n      cache-element\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'cache-element'\n});\n</script>\n  </dom-module>\n\n  <cache-element id=\"cache1\" class=\"c\"></cache-element>\n  <cache-element id=\"cache2\"></cache-element>\n\n  <script type=\"module\">\n\nsuite('custom-style scope cache', function() {\n\n  test('elements created declaratively conditionally styled via custom style receive correct properties', function() {\n    var t1 = document.querySelector('#cache1');\n    var t2 = document.querySelector('#cache2');\n    assertComputed(t1, '8px');\n    assertComputed(t2, '4px');\n  });\n\n\n  test('elements created imperatively conditionally styled via custom style receive correct properties', function() {\n    var t1 = document.createElement('cache-element');\n    t1.classList.add('c');\n    var t2 = document.createElement('cache-element');\n    document.body.appendChild(t1);\n    document.body.appendChild(t2);\n    assertComputed(t1, '8px');\n    assertComputed(t2, '4px');\n  });\n\n});\n\n\nfunction assertComputed(element, value, property, pseudo) {\n  var computed = getComputedStyle(element, pseudo);\n  property = property || 'border-top-width';\n  assert.equal(computed[property], value, 'computed style incorrect for ' + property);\n}\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/custom-style.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n  <script type=\"module\" src=\"./custom-style-import.js\"></script>\n</head>\n<body>\n  <!-- FIXME(polymer-modulizer):\n        These imperative modules that innerHTML your HTML are\n        a hacky way to be sure that any mixins in included style\n        modules are ready before any elements that reference them are\n        instantiated, otherwise the CSS @apply mixin polyfill won't be\n        able to expand the underlying CSS custom properties.\n        See: https://github.com/Polymer/polymer-modulizer/issues/154\n        -->\n    <script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n\n$_documentContainer.innerHTML = `<custom-style>\n  <style is=\"custom-style\">\n    x-bar {\n      border: 1px solid red;\n      display: block;\n    }\n\n    html {\n      --bag2: {\n        border: 12px solid beige;\n      };\n    }\n\n    html {\n      --red-text : {\n        color : red;\n      };\n    }\n\n    html{--blue-text:{color:#0000ff};--dummy-mixin:{};--bold-text:{font-weight:700}}\n\n\n    html {\n\n      --italic: italic;\n\n      --bag: {\n        margin: 1px;\n        border: 1px solid black;\n      };\n\n      /* mocha.css in the testing environment is hosing this test;\n      use !important as a workaround */\n      margin: 10px !important;\n      width: auto;\n\n      --special: var(--primary);\n\n      --after: 11px solid orange;\n      @apply --bag2;\n    }\n\n    x-foo {\n\n      --primary: 10px;\n      --x-foo-more: 6px solid orange;\n    }\n  </style>\n</custom-style>`;\n\ndocument.body.appendChild($_documentContainer.content);\n</script>\n  <script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n\n$_documentContainer.innerHTML = `<custom-style>\n  <style is=\"custom-style\">\n    .bag {\n      ;@apply --bag;\n    }\n\n    .italic {\n      font-style: var(--italic);\n    }\n\n    .import-mixin {\n      @apply --import-mixin;\n    }\n\n    .import-var {\n      border: var(--import-var);\n    }\n\n    .dynamic {\n      border: var(--dynamic);\n    }\n\n    #after::after {\n      content: 'after';\n      border: var(--after);\n    }\n  </style>\n</custom-style>`;\n\ndocument.body.appendChild($_documentContainer.content);\n</script>\n\n<script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n\n$_documentContainer.innerHTML = `<custom-style>\n  <style is=\"custom-style\" include=\"shared-style2\">\n    .zazz {\n      border: 20px solid blue;\n    }\n  </style>\n  <style>\n    .foo--bar {\n      border-top : 3px solid red;\n    }\n  </style>\n</custom-style>`;\n\ndocument.body.appendChild($_documentContainer.content);\n</script>\n<script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n\n$_documentContainer.innerHTML = `<custom-style>\n  <style is=\"custom-style\">\n    @media (min-width: 1px) {\n      .foo--bar {\n        border-top : 20px solid blue;\n      }\n    }\n  </style>\n</custom-style>`;\n\ndocument.body.appendChild($_documentContainer.content);\n</script>\n  <script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n$_documentContainer.innerHTML = `<div class=\"italic\">italic</div>`;\ndocument.body.appendChild($_documentContainer.content);\n</script>\n  <script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n$_documentContainer.innerHTML = `<div class=\"bag\">bag</div>`;\ndocument.body.appendChild($_documentContainer.content);\n</script>\n  <script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n$_documentContainer.innerHTML = `<div class=\"mix\">mix</div>`;\ndocument.body.appendChild($_documentContainer.content);\n</script>\n\n  <script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n$_documentContainer.innerHTML = `<div class=\"dynamic\">dynamic</div>`;\ndocument.body.appendChild($_documentContainer.content);\n</script>\n\n  <script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n$_documentContainer.innerHTML = `<div class=\"import-mixin\">import-mixin</div>`;\ndocument.body.appendChild($_documentContainer.content);\n</script>\n  <script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n$_documentContainer.innerHTML = `<div class=\"import-var\">import-var</div>`;\ndocument.body.appendChild($_documentContainer.content);\n</script>\n\n  <script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n$_documentContainer.innerHTML = `<x-bar></x-bar>`;\ndocument.body.appendChild($_documentContainer.content);\n</script>\n\n  <script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n$_documentContainer.innerHTML = `<x-foo></x-foo>`;\ndocument.body.appendChild($_documentContainer.content);\n</script>\n\n  <script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n$_documentContainer.innerHTML = `<x-red-text></x-red-text>`;\ndocument.body.appendChild($_documentContainer.content);\n</script>\n\n  <script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n$_documentContainer.innerHTML = `<x-blue-bold-text></x-blue-bold-text>`;\ndocument.body.appendChild($_documentContainer.content);\n</script>\n\n  <script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n$_documentContainer.innerHTML = `<parent-variable-with-var></parent-variable-with-var>`;\ndocument.body.appendChild($_documentContainer.content);\n</script>\n\n  <script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n$_documentContainer.innerHTML = `<br>`;\ndocument.body.appendChild($_documentContainer.content);\n</script><script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n$_documentContainer.innerHTML = `<br>`;\ndocument.body.appendChild($_documentContainer.content);\n</script>\n  <script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n$_documentContainer.innerHTML = `<div id=\"after\"></div>`;\ndocument.body.appendChild($_documentContainer.content);\n</script>\n\n  <script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n$_documentContainer.innerHTML = `<div class=\"foo\"></div>`;\ndocument.body.appendChild($_documentContainer.content);\n</script>\n\n  <script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n$_documentContainer.innerHTML = `<div class=\"foo--bar\"></div>`;\ndocument.body.appendChild($_documentContainer.content);\n</script>\n\n  <script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n\n$_documentContainer.innerHTML = `<dom-module id=\"x-baz\">\n    <template>\n    <style>\n      :host {\n        display: block;\n      }\n    </style>\n      <div id=\"me\">x-baz</div>\n    </template>\n  </dom-module>`;\n\ndocument.body.appendChild($_documentContainer.content);\n</script>\n\n  <script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n\n$_documentContainer.innerHTML = `<dom-module id=\"x-bar\">\n    <template>\n    <style>\n      :host {\n        display: block;\n      }\n    </style>\n      <div>x-bar</div>\n      <x-baz id=\"baz\"></x-baz>\n    </template>\n  </dom-module>`;\n\ndocument.body.appendChild($_documentContainer.content);\n</script>\n\n  <script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n\n$_documentContainer.innerHTML = `<dom-module id=\"x-foo\">\n    <template>\n    <style>\n      :host {\n        display: block;\n        border: solid tomato;\n        border-width: var(--special);\n      }\n\n      div {\n        @apply --bag;\n      }\n\n      #more {\n        border: var(--x-foo-more);\n      }\n    </style>\n      <div id=\"me\">x-foo</div>\n      <x-bar id=\"bar1\"></x-bar>\n      <x-bar id=\"bar2\"></x-bar>\n      <x-bar id=\"bar3\"></x-bar>\n      <div id=\"more\">deep</div>\n    </template>\n  </dom-module>`;\n\ndocument.body.appendChild($_documentContainer.content);\n</script>\n\n  <script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n\n$_documentContainer.innerHTML = `<dom-module id=\"x-red-text\">\n    <template>\n    <style>\n      :host {\n        @apply --red-text;\n      }\n    </style>\n      x-red-text\n    </template>\n  </dom-module>`;\n\ndocument.body.appendChild($_documentContainer.content);\n</script>\n\n  <script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n\n$_documentContainer.innerHTML = `<dom-module id=\"x-blue-bold-text\">\n    <template>\n    <style>\n      :host {@apply --blue-text;@apply --bold-text;}\n    </style>\n      x-blue-bold-text\n    </template>\n  </dom-module>`;\n\ndocument.body.appendChild($_documentContainer.content);\n</script>\n\n  <script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n\n$_documentContainer.innerHTML = `<dom-module id=\"parent-variable-with-var\">\n    <template>\n      <style>\n        child-variable-with-var {\n          --variable-property-own-line: 1px;\n          --variable-property-preceded-property: 2px;\n          --variable-property-before-property: yellow;\n          --variable-property-after-property: 3px;\n          --variable-property-after-assignment: 4px;\n          --variable-property-before-assignment: 5px;\n          --variable-into-first-variable: 9px;\n          --variable-into-second-variable: 10px;\n          --variable-into-third-variable: 11px;\n        }\n      </style>\n      <child-variable-with-var id=\"child\"></child-variable-with-var>\n    </template>\n  </dom-module>`;\n\ndocument.body.appendChild($_documentContainer.content);\n</script>\n\n  <script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n\n$_documentContainer.innerHTML = `<dom-module id=\"child-variable-with-var\">\n    <template>\n      <style>\n        child-of-child-with-var {\n          /* in certain browsers (e.g. Safari) \\`top\\`, \\`bottom\\`, \\`left\\`, \\`right\\` don't compute\n             when no explicit position is defined (\\`relative\\` / \\`absolute\\` / \\`fixed\\`) */\n          position: relative;\n          --variable-own-line: \"Varela font\";\n          margin-top: var(--variable-property-own-line);\n          margin-bottom: var(--variable-property-preceded-property);\n          --variable-between-properties: 6px;\n          background-color: var(--variable-property-before-property); padding-top: var(--variable-property-after-property);\n          --variable-assignment-before-property: 7px; padding-bottom: var(--variable-property-after-assignment);\n          padding-left: var(--variable-property-before-assignment);--variable-assignment-after-property: 8px;\n          top: 12px;--variable-from-other-variable: var(--variable-into-first-variable);--variable-from-another-variable: var(--variable-into-second-variable); --variable-from-last-variable: var(--variable-into-third-variable);\n          height: 20px;\n        }\n      </style>\n      <child-of-child-with-var id=\"child\"></child-of-child-with-var>\n    </template>\n  </dom-module>`;\n\ndocument.body.appendChild($_documentContainer.content);\n</script>\n\n  <script type=\"module\">\nconst $_documentContainer = document.createElement('template');\n\n$_documentContainer.innerHTML = `<dom-module id=\"child-of-child-with-var\">\n    <template>\n      <style>\n        :host {\n          font-family: var(--variable-own-line);\n          padding-right: var(--variable-between-properties);\n          margin-left: var(--variable-assignment-before-property);\n          margin-right: var(--variable-assignment-after-property);\n          bottom: var(--variable-from-other-variable);\n          left: var(--variable-from-another-variable);\n          right: var(--variable-from-last-variable);\n        }\n      </style>\n      Text\n    </template>\n  </dom-module>`;\n\ndocument.body.appendChild($_documentContainer.content);\n</script>\n\n  <script type=\"module\">\nimport './custom-style-import.js';\nimport { Polymer } from '../../lib/legacy/polymer-fn.js';\nPolymer({\n  is: 'x-baz'\n});\n\nPolymer({\n  is: 'x-bar'\n});\n\nPolymer({\n  is: 'x-foo'\n});\n\nPolymer({\n  is: 'x-red-text'\n});\n\nPolymer({\n  is: 'x-blue-bold-text'\n});\n</script>\n\n  <script type=\"module\">\nimport './custom-style-import.js';\nimport { updateStyles } from '../../lib/mixins/element-mixin.js';\nimport { Polymer } from '../../lib/legacy/polymer-fn.js';\n\nsuite('custom-style', function() {\n\n  var xBar, xFoo, stylesBuilt;\n\n  suiteSetup(function() {\n    xBar = document.querySelector('x-bar');\n    xFoo = document.querySelector('x-foo');\n  });\n\n  test('root styles applied', function() {\n    assertComputed(xBar, '1px');\n  });\n\n  test('root styles have lower bound encapsulation', function() {\n    assertComputed(xFoo.$.bar1, '0px');\n  });\n\n  test('custom properties registered as defaults', function() {\n    var propsToCheck = ['--italic'];\n    if (!window.ShadyCSS || ShadyCSS.nativeCss || stylesBuilt) {\n      var sep = window.ShadyCSS.ApplyShim._separator;\n      propsToCheck.push('--bag' + sep + 'margin', '--bag' + sep + 'border');\n    } else {\n      propsToCheck.push('--bag');\n    }\n    if (!window.ShadyCSS || ShadyCSS.nativeCss) {\n      var cs = getComputedStyle(document.documentElement);\n      propsToCheck.forEach(function(p) {\n        assert.ok(cs.getPropertyValue(p));\n      });\n    } else {\n      propsToCheck.forEach(function(p) {\n        assert.ok(ShadyCSS.ScopingShim.getComputedStyleValue(document.documentElement, p));\n      });\n    }\n  });\n\n  test('custom properties with space before semicolon', function() {\n    var red = document.querySelector('x-red-text');\n    assertComputed(red, 'rgb(255, 0, 0)', 'color');\n  });\n\n  test('custom properties in minified css', function() {\n    var blue = document.querySelector('x-blue-bold-text');\n    assertComputed(blue, 'rgb(0, 0, 255)', 'color');\n\n    var computed = getComputedStyle(blue);\n    // Firefox returns `700`, while Chrome returns original `bold`\n    assert.ok(computed.fontWeight == '700' || computed.fontWeight == 'bold', 'computed style incorrect for fontWeight');\n  });\n\n  test('custom-styles apply normal and property values to main document', function() {\n    var bag = document.querySelector('.bag');\n    var italic = document.querySelector('.italic');\n    assertComputed(bag, '1px');\n    assertComputed(italic, 'italic', 'font-style');\n  });\n\n  test('imported custom-styles apply', function() {\n    if (stylesBuilt && window.ShadyCSS && !ShadyCSS.nativeCss) {\n      // css build will test this by using vulcanize.\n      // this inlines the custom-style after the consumption point, and changes the timing for custom property shim\n      // Force an update style for this weird corner case in the tests\n      updateStyles();\n    }\n    var v = document.querySelector('.import-var');\n    var m = document.querySelector('.import-mixin');\n    assertComputed(v, '3px');\n    assertComputed(m, '4px');\n  });\n\n  test('dynamic custom-styles apply', function() {\n    var dynamic = document.querySelector('.dynamic');\n    assertComputed(dynamic, '0px');\n    var cs = document.createElement('custom-style');\n    var s = document.createElement('style');\n    s.textContent = ':root { --dynamic: 11px solid orange; }';\n    cs.appendChild(s);\n    document.body.appendChild(cs);\n    updateStyles();\n    assertComputed(dynamic, '11px');\n  });\n\n  test('custom-styles apply normal and property values to elements and cannot be late bound via inheritance', function() {\n    var e = document.querySelector('x-foo').$.me;\n    assertComputed(e, '1px');\n  });\n\n  test('custom-styles apply to pseudo elements', function() {\n    var e = document.querySelector('#after');\n    assertComputed(e, '11px', null, '::after');\n  });\n\n  test('style paths in included dom-modules loaded in import', function() {\n    var foo = document.querySelector('.foo');\n    var url = getComputedStyle(foo).backgroundImage;\n    assert.include(url, 'sub/google.png');\n  });\n\n  test('style paths can have arbitrary whitespace', function() {\n    var foo = document.querySelector('.foo');\n    assertComputed(foo, '4px', 'width');\n  });\n\n  test('imperative custom style', function() {\n    var cs = document.createElement('custom-style');\n    var style = document.createElement('style');\n    style.textContent = '.zonk { border: 13px solid tomato;}';\n    cs.appendChild(style);\n    var d = document.createElement('div');\n    d.classList.add('zonk');\n    document.body.appendChild(d);\n    document.body.appendChild(cs);\n    updateStyles();\n    if (window.ShadyDOM) {\n      assert.ok(style.textContent.match(':not'));\n    }\n    assertComputed(d, '13px');\n    document.body.removeChild(d);\n    document.body.removeChild(cs);\n\n  });\n\n  test('imperative custom style with include', function() {\n    var cs = document.createElement('custom-style');\n    var style = document.createElement('style');\n    style.setAttribute('include', 'shared-style2');\n    cs.appendChild(style);\n    var d = document.createElement('div');\n    d.classList.add('zazz');\n    document.body.appendChild(d);\n    document.body.appendChild(cs);\n    updateStyles();\n    assertComputed(d, '16px');\n    document.body.removeChild(d);\n    document.body.removeChild(cs);\n  });\n\n  test('imperative custom style with non-existent include', function() {\n    var s1 = document.createElement('custom-style');\n    var style = document.createElement('style');\n    s1.appendChild(style);\n    style.setAttribute('include', 'does-not-exist');\n    style.textContent = '.ziz { border: 14px solid tomato;}';\n    var d = document.createElement('div');\n    d.classList.add('ziz');\n    document.body.appendChild(d);\n    document.body.appendChild(s1);\n    updateStyles();\n    assertComputed(d, '14px');\n    document.body.removeChild(d);\n    document.body.removeChild(s1);\n  });\n\n  test('include style data applied before textContent', function() {\n    var d = document.createElement('div');\n    d.classList.add('zazz');\n    document.body.appendChild(d);\n    assertComputed(d, '20px');\n    document.body.removeChild(d);\n  });\n\n  test('variable name with assignment including var correctly applied', function() {\n    Polymer({\n      is: 'parent-variable-with-var'\n    });\n    Polymer({\n      is: 'child-variable-with-var'\n    });\n    Polymer({\n      is: 'child-of-child-with-var'\n    });\n\n    var d = document.querySelector('parent-variable-with-var');\n    var el = d.$.child.$.child;\n    assertComputed(el, '1px', 'margin-top');\n    assertComputed(el, '2px', 'margin-bottom');\n    assertComputed(el, '3px', 'padding-top');\n    assertComputed(el, '4px', 'padding-bottom');\n    assertComputed(el, '5px', 'padding-left');\n    assertComputed(el, '6px', 'padding-right');\n    assertComputed(el, '7px', 'margin-left');\n    assertComputed(el, '8px', 'margin-right');\n    assertComputed(el, 'rgb(255, 255, 0)', 'background-color');\n    assertComputed(el, '9px', 'bottom');\n    assertComputed(el, '10px', 'left');\n    assertComputed(el, '11px', 'right');\n    assertComputed(el, '12px', 'top');\n\n    // Avoid Edge bug with CSS Custom Properties and Fonts.\n    if (navigator.userAgent.match('Edge') && (!window.ShadyCSS || window.ShadyCSS.nativeCss)) {\n      return;\n    }\n\n    // Because FireFox and Chrome parse font-family differently...\n    var computed = getComputedStyle(el);\n    assert.equal(computed['font-family'].replace(/['\"]+/g, ''), 'Varela font');\n  });\n\n  test('BEM-like CSS selectors under media queries', function() {\n    assertComputed(document.querySelector('.foo--bar'), '20px');\n  });\n\n});\n\n\nfunction assertComputed(element, value, property, pseudo) {\n  var computed = getComputedStyle(element, pseudo);\n  property = property || 'border-top-width';\n  assert.equal(computed[property], value, 'computed style incorrect for ' + property);\n}\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/debounce.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n</head>\n<body>\n  <test-fixture id=\"basic\">\n    <template>\n      <x-basic></x-basic>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"another\">\n    <template>\n      <x-basic></x-basic>\n    </template>\n  </test-fixture>\n\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nimport { Debouncer } from '../../lib/utils/debounce.js';\nimport { microTask, timeOut, animationFrame, idlePeriod } from '../../lib/utils/async.js';\nimport { enqueueDebouncer, flush } from '../../lib/utils/flush.js';\nPolymer({is: 'x-basic'});\n\nsuite('enqueueDebouncer & flush', function() {\n\n  // NOTE: This is a regression test; the bug it fixed only occurred if the\n  // debouncer was flushed before any microtasks run, hence it should be\n  // first in this file\n  test('re-enqueue canceled debouncer', function() {\n    const cb = sinon.spy();\n    let db;\n    db = Debouncer.debounce(null, microTask, cb);\n    enqueueDebouncer(db);\n    db.cancel();\n    assert.equal(db.isActive(), false);\n    assert.equal(cb.callCount, 0);\n    db = Debouncer.debounce(db, microTask, cb);\n    enqueueDebouncer(db);\n    flush();\n    assert.isTrue(cb.calledOnce);\n  });\n\n  test('flushDebouncers from enqueued debouncer', function(done) {\n    const cb = sinon.spy(() => flush());\n    let db = Debouncer.debounce(null, microTask, cb);\n    enqueueDebouncer(db);\n    setTimeout(() => {\n      assert.isTrue(cb.calledOnce);\n      done();\n    });\n  });\n\n  const testEnqueue = (shouldFlush, done) => {\n    const actualOrder = [];\n    const enqueue = (type, {db, cb} = {}) => {\n      cb = cb || (() => actualOrder.push(cb));\n      db = Debouncer.debounce(db, type, cb);\n      enqueueDebouncer(db);\n      return {db, cb};\n    };\n    const db1 = enqueue(microTask);\n    const db2 = enqueue(microTask);\n    const db3 = enqueue(timeOut);\n    const db4 = enqueue(microTask);\n    enqueue(microTask, db2);\n    enqueue(microTask, db1);\n    if (shouldFlush) {\n      flush();\n      assert.deepEqual(actualOrder, [db1.cb, db2.cb, db3.cb, db4.cb]);\n      done();\n    } else {\n      timeOut.run(() => {\n        assert.deepEqual(actualOrder, [db4.cb, db2.cb, db1.cb, db3.cb]);\n        done();\n      });\n    }\n  };\n\n  test('non-flushed', function(done) {\n    testEnqueue(false, done);\n  });\n\n  test('flushed', function(done) {\n    testEnqueue(true, done);\n  });\n\n  test('reentrant flush', function() {\n    const cb2 = sinon.spy();\n    let db2;\n    const cb1 = sinon.spy(() => {\n      flush();\n      db2 = Debouncer.debounce(null, microTask, cb2);\n      enqueueDebouncer(db2);\n    });\n    const db1 = Debouncer.debounce(null, microTask, cb1);\n    enqueueDebouncer(db1);\n    flush();\n    assert.isTrue(cb1.calledOnce);\n    assert.isTrue(cb2.calledOnce);\n  });\n\n});\n\nsuite('debounce', function() {\n  var element;\n\n  setup(function() {\n    element = fixture('basic');\n  });\n\n  test('debounce (no-wait)', function(done) {\n    var called = 0;\n    var callback = function() {\n      called++;\n    };\n\n    element.debounce('job', callback);\n    element.debounce('job', callback);\n    element.debounce('job', callback);\n\n    setTimeout(function() {\n      assert.equal(called, 1, 'debounce should be called exactly once');\n      done();\n    }, 50);\n  });\n\n  test('debounce (wait)', function(done) {\n    var called = 0;\n    var now = Date.now();\n    var callback = function() {\n      called++;\n    };\n\n    element.debounce('job', callback);\n    element.debounce('job', callback, 100);\n    element.debounce('job', callback, 100);\n\n    setTimeout(function() {\n      assert.equal(called, 1, 'debounce should be called exactly once');\n      assert(Date.now() - now > 100, 'debounce should be called after at least 100ms');\n      done();\n    }, 200);\n  });\n\n  suite('debounce does not carry across multiple elements', function() {\n    var element1, element2;\n\n    setup(function() {\n      element1 = fixture('basic');\n      element2 = fixture('another');\n    });\n\n    test('debounce (no-wait)', function(done) {\n      var called = 0;\n      var callback = function() {\n        called++;\n      };\n\n      element1.debounce('job', callback);\n      element2.debounce('job', callback);\n      element1.debounce('job', callback);\n      element2.debounce('job', callback);\n\n      setTimeout(function() {\n        assert.equal(called, 2, 'debounce should be called exactly twice');\n        done();\n      }, 50);\n    });\n  });\n\n  suite('Polymer.Debouncer.debounce', function() {\n    test('same debouncer and multiple micro tasks', function(done) {\n      var callback = sinon.spy();\n      var job = Debouncer.debounce(null, microTask, callback);\n      Debouncer.debounce(job, microTask, callback);\n\n      setTimeout(function() {\n        assert.isTrue(callback.calledOnce, 'callback should be called once');\n        done();\n      });\n    });\n\n    test('flush debouncer', function(done) {\n      var callback = sinon.spy();\n      var job = Debouncer.debounce(null, microTask, callback);\n\n      setTimeout(function() {\n        job.flush();\n        assert.isTrue(callback.calledOnce, 'callback should be called once');\n        done();\n      });\n    });\n\n    test('different debouncers and multiple micro tasks', function(done) {\n      var callback = sinon.spy();\n      var job1 = Debouncer.debounce(null, microTask, callback);\n      Debouncer.debounce(job1, microTask, callback);\n      var job2 = Debouncer.debounce(null, microTask, callback);\n      Debouncer.debounce(job2, microTask, callback);\n\n      setTimeout(function() {\n        assert.isTrue(callback.calledTwice, 'callback should be called twice');\n        done();\n      });\n    });\n\n    test('same debouncer and multiple timers', function(done) {\n      var callback = sinon.spy();\n      var job = Debouncer.debounce(null, timeOut.after(10), callback);\n      Debouncer.debounce(job, timeOut.after(10), callback);\n\n      setTimeout(function() {\n        assert.isTrue(callback.calledOnce, 'callback should be called once');\n        done();\n      }, 20);\n    });\n\n    test('different debouncers and multiple timers', function(done) {\n      var callback = sinon.spy();\n      var job1 = Debouncer.debounce(null, timeOut.after(10), callback);\n      Debouncer.debounce(job1, timeOut.after(10), callback);\n      var job2 = Debouncer.debounce(null, timeOut.after(10), callback);\n      Debouncer.debounce(job2, timeOut.after(10), callback);\n\n      setTimeout(function() {\n        assert.isTrue(callback.calledTwice, 'callback should be called twice');\n        done();\n      }, 20);\n    });\n\n    test('same debouncer and multiple animation frames', function(done) {\n      var callback = sinon.spy();\n      var job = Debouncer.debounce(null, animationFrame, callback);\n      Debouncer.debounce(job, animationFrame, callback);\n\n      requestAnimationFrame(function() {\n        assert.isTrue(callback.calledOnce, 'callback should be called once');\n        done();\n      });\n    });\n\n    test('different debouncer and multiple animation frames', function(done) {\n      var callback = sinon.spy();\n      var job1 = Debouncer.debounce(null, animationFrame, callback);\n      Debouncer.debounce(job1, animationFrame, callback);\n      var job2 = Debouncer.debounce(null, animationFrame, callback);\n      Debouncer.debounce(job2, animationFrame, callback);\n\n      requestAnimationFrame(function() {\n        assert.isTrue(callback.calledTwice, 'callback should be called twice');\n        done();\n      });\n    });\n\n    test('same debouncer and multiple idle callbacks', function(done) {\n      var callback = sinon.spy();\n      var job = Debouncer.debounce(null, idlePeriod, callback);\n      Debouncer.debounce(job, idlePeriod, callback);\n      idlePeriod.run(function() {\n        assert.isTrue(callback.calledOnce, 'callback should be called once');\n        done();\n      });\n    });\n\n    test('different debouncer and multiple idle callbacks', function(done) {\n      var callback = sinon.spy();\n      var job1 = Debouncer.debounce(null, idlePeriod, callback);\n      Debouncer.debounce(job1, idlePeriod, callback);\n      var job2 = Debouncer.debounce(null, idlePeriod, callback);\n      Debouncer.debounce(job2, idlePeriod, callback);\n      idlePeriod.run(function() {\n        assert.isTrue(callback.calledTwice, 'callback should be called twice');\n        done();\n      });\n    });\n\n  });\n\n});\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/dir.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html dir=\"rtl\">\n<head>\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n</head>\n<body>\n  <!--\n    Issues\n    1. regex will process entire string, including comments and properties, not just selectors...\n    2. complex selectors. not ok... e.g.\n    bad: .special > *:dir(rtl)\n    but ok: .special:dir(rtl) > *\n    3. multiple selectors per line? ok.\n  -->\n  <dom-module id=\"x-inner-dir\">\n    <template>\n      <style>\n        :host {\n          display: block;\n          height: 20px;\n          color: white;\n        }\n        input, section {\n          border-top-width: 0px;\n        }\n\n        section:dir(rtl), input:dir(rtl) {\n          border: 10px solid rgb(123, 123, 123);\n        }\n\n        .special:dir(rtl) > * {\n          color: rgb(0, 128, 0);\n        }\n      </style>\n      <div>no rtl styling</div>\n      <section>rtl styling</section>\n      <input value=\"rtl styling\">\n      <div class=\"special\">\n        <div>at the right.</div>\n      </div>\n    </template>\n    <script type=\"module\">\nimport { DirMixin } from '../../lib/mixins/dir-mixin.js';\nimport { PolymerElement } from '../../polymer-element.js';\nclass XInnerDir extends DirMixin(PolymerElement) {\n  static get is() {return 'x-inner-dir';}\n}\ncustomElements.define(XInnerDir.is, XInnerDir);\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-dir\">\n    <template>\n      <style>\n        :host {\n          display: block;\n          background-color: rgb(0, 0, 255);\n          min-height: 100px;\n          width: 100px;\n        }\n        :host(:dir(rtl)) {\n          background-color: rgb(0, 128, 0);\n        }\n        #foo:dir(rtl) {\n          border: 10px solid rgb(255, 0, 0);\n        }\n        .thing:dir(rtl) {\n          border: 10px solid rgb(0, 0, 255);\n        }\n      </style>\n      <div id=\"foo\"></div>\n      <div class=\"thing\"></div>\n      <x-inner-dir></x-inner-dir>\n    </template>\n    <script type=\"module\">\nimport { DirMixin } from '../../lib/mixins/dir-mixin.js';\nimport { PolymerElement } from '../../polymer-element.js';\nclass XDir extends DirMixin(PolymerElement) {\n  static get is() {return 'x-dir';}\n}\ncustomElements.define(XDir.is, XDir);\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-dir-legacy\">\n    <template>\n      <style>\n        :host {\n          display: block;\n          border: 10px solid black;\n        }\n        :host(:dir(rtl)) {\n          border: 2px dotted blue;\n        }\n      </style>\n    </template>\n    <script type=\"module\">\nimport '../../lib/mixins/dir-mixin.js';\nimport { Polymer } from '../../lib/legacy/polymer-fn.js';\nPolymer({is: 'x-dir-legacy'});\n</script>\n  </dom-module>\n\n  <test-fixture id=\"dir\">\n    <template>\n      <x-dir></x-dir>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"preset\">\n    <template>\n      <x-inner-dir dir=\"ltr\"></x-inner-dir>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"legacy\">\n    <template>\n      <x-dir-legacy></x-dir-legacy>\n    </template>\n  </test-fixture>\n\n  <script type=\"module\">\nimport '../../lib/mixins/dir-mixin.js';\nimport { PolymerElement } from '../../polymer-element.js';\nclass OtherElement extends PolymerElement {}\ncustomElements.define('other-element', OtherElement);\n</script>\n\n  <dom-module id=\"x-complicated\">\n    <template>\n      <style>\n        #direct:dir(rtl) {\n          border: 10px solid black;\n        }\n        :dir(rtl) #indirect {\n          border: 9px solid black;\n        }\n        other-element:dir(rtl) {\n          border: 8px solid black;\n        }\n        #container:dir(rtl) ::slotted(*) {\n          border: 7px solid black;\n        }\n      </style>\n      <div id=\"direct\"></div>\n      <div id=\"indirect\"></div>\n      <other-element id=\"other\"></other-element>\n      <div id=\"container\">\n        <slot></slot>\n      </div>\n    </template>\n    <script type=\"module\">\nimport { DirMixin } from '../../lib/mixins/dir-mixin.js';\nimport { PolymerElement } from '../../polymer-element.js';\nclass XComplicated extends DirMixin(PolymerElement) {\n  static get is() {return 'x-complicated';}\n}\ncustomElements.define(XComplicated.is, XComplicated);\n</script>\n  </dom-module>\n\n  <test-fixture id=\"complicated\">\n    <template>\n      <x-complicated>\n        <div></div>\n      </x-complicated>\n    </template>\n  </test-fixture>\n\n  <script type=\"module\">\nimport '../../lib/mixins/dir-mixin.js';\nfunction assertComputed(node, expected, property = 'border-top-width') {\n  let actual = getComputedStyle(node).getPropertyValue(property).trim();\n  assert.equal(expected, actual);\n}\n\nsuite(':dir', function() {\n  teardown(function() {\n    document.documentElement.setAttribute('dir', 'rtl');\n  });\n\n  test(':dir(rtl) functions when html element dir attr set to rtl', function() {\n    let el = fixture('dir');\n    assertComputed(el, 'rgb(0, 128, 0)', 'background-color');\n    assertComputed(el.shadowRoot.querySelector('#foo'), '10px');\n    assertComputed(el.shadowRoot.querySelector('.thing'), '10px');\n    let inner = el.shadowRoot.querySelector('x-inner-dir');\n    assertComputed(inner.shadowRoot.querySelector('.special > div'), 'rgb(0, 128, 0)', 'color');\n    assertComputed(inner.shadowRoot.querySelector('section'), '10px');\n    assertComputed(inner.shadowRoot.querySelector('input'), '10px');\n  });\n\n  test(':dir reacts to html attribute changing', function(done) {\n    let el = fixture('dir');\n    document.documentElement.setAttribute('dir', 'ltr');\n    requestAnimationFrame(() => {\n      assertComputed(el, 'rgb(0, 0, 255)', 'background-color');\n      assertComputed(el.shadowRoot.querySelector('#foo'), '0px');\n      assertComputed(el.shadowRoot.querySelector('.thing'), '0px');\n      let inner = el.shadowRoot.querySelector('x-inner-dir');\n      assertComputed(inner.shadowRoot.querySelector('.special > div'), 'rgb(255, 255, 255)', 'color');\n      assertComputed(inner.shadowRoot.querySelector('section'), '0px');\n      assertComputed(inner.shadowRoot.querySelector('input'), '0px');\n      done();\n    });\n  });\n\n  test('elements with dir attribute explicitly set will not change', function() {\n    if (window.ShadyDOM && window.ShadyDOM.inUse) {\n      this.skip();\n    }\n    let inner = fixture('preset');\n    assert.equal(document.documentElement.getAttribute('dir'), 'rtl');\n    assertComputed(inner.shadowRoot.querySelector('.special > div'), 'rgb(255, 255, 255)', 'color');\n    assertComputed(inner.shadowRoot.querySelector('section'), '0px');\n    assertComputed(inner.shadowRoot.querySelector('input'), '0px');\n  });\n\n  test('elements will adopt dir status when reconnected', function(done) {\n    let el = fixture('dir');\n    assertComputed(el, 'rgb(0, 128, 0)', 'background-color');\n    let parent = el.parentNode;\n    parent.removeChild(el);\n    document.documentElement.setAttribute('dir', 'ltr');\n    requestAnimationFrame(() => {\n      parent.appendChild(el);\n      requestAnimationFrame(() => {\n        assertComputed(el, 'rgb(0, 0, 255)', 'background-color');\n        done();\n      });\n    });\n  });\n\n  test('legacy elements worth with DirMixin', function() {\n    let el = fixture('legacy');\n    assertComputed(el, '2px');\n  });\n\n  test('complicated setup', function() {\n    if (window.ShadyDOM && window.ShadyDOM.inUse) {\n      this.skip();\n    }\n    let el = fixture('complicated');\n    assertComputed(el.$.direct, '10px');\n    assertComputed(el.$.indirect, '9px');\n    assertComputed(el.$.other, '8px');\n    assertComputed(el.firstElementChild, '7px');\n  });\n});\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/disable-upgrade.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html dir=\"rtl\">\n<head>\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n  <script type=\"module\" src=\"../../lib/mixins/disable-upgrade-mixin.js\"></script>\n</head>\n<body>\n\n  <dom-module id=\"x-disabled\">\n    <template>\n      <style>\n        :host {\n          display: block;\n        }\n\n        h2 {\n          letter-spacing: 1em;\n        }\n      </style>\n      <h2 id=\"element\">[[prop]]</h2>\n      <!-- force an accessor for the default property -->\n      default: [[default]]\n    </template>\n\n    <script type=\"module\">\nimport { DisableUpgradeMixin } from '../../lib/mixins/disable-upgrade-mixin.js';\nimport { PolymerElement } from '../../polymer-element.js';\nconst Disabled = DisableUpgradeMixin(class extends PolymerElement {\n  static get is() { return 'x-disabled'; }\n  static get properties() {\n    return {\n      prop: {\n        type: String\n      },\n      default: {\n        type: String,\n        value: 'default'\n      }\n    };\n  }\n  constructor() {\n    super();\n    this.prop = 'enabled!';\n  }\n\n  ready() {\n    super.ready();\n    this.enabled = true;\n  }\n\n  connectedCallback() {\n    this.wasConnected = true;\n    super.connectedCallback();\n  }\n\n  disconnectedCallback() {\n    this.wasDisconnected = true;\n    super.disconnectedCallback();\n  }\n});\ncustomElements.define(Disabled.is, Disabled);\n</script>\n\n  </dom-module>\n\n  <dom-module id=\"x-disabled-legacy\">\n      <template>\n        <style>\n          :host {\n            display: block;\n          }\n\n          h2 {\n            letter-spacing: 1em;\n          }\n        </style>\n        <h2 id=\"element\">[[prop]]</h2>\n        <!-- force an accessor for the default property -->\n        default: [[default]]\n      </template>\n\n      <script type=\"module\">\nimport { Polymer } from '../../lib/legacy/polymer-fn.js';\nimport {setLegacyOptimizations} from '../../lib/utils/settings.js';\n\n// This setting is for all tests...\nsetLegacyOptimizations(true);\n\nPolymer({\n  is: 'x-disabled-legacy',\n  properties: {\n    prop: {\n      type: String\n    },\n    default: {\n      type: String,\n      value: 'default'\n    }\n  },\n  listeners: {\n    foo: 'fooHandler'\n  },\n  created() {\n    this.hasCreated = true;\n    this.prop = 'enabled!';\n  },\n  attached() {\n    this.wasConnected = true;\n  },\n  detached() {\n    this.wasDisconnected = true;\n  },\n  ready() {\n    this.enabled = true;\n  },\n  fooHandler() {}\n});\n\nPolymer({\n  is: 'x-disabled-legacy-reg1',\n  registered() {\n    this.hasRegistered = true;\n  }\n});\n\nPolymer({\n  is: 'x-disabled-legacy-reg2',\n  registered() {\n    this.hasRegistered = true;\n  }\n});\n</script>\n\n    </dom-module>\n\n  <dom-module id=\"my-element\">\n\n    <template>\n      <x-disabled id=\"enabledEl\">Disabled</x-disabled>\n      <x-disabled id=\"disabledEl\" disable-upgrade default=\"custom\">Disabled</x-disabled>\n      <x-disabled id=\"disabledBoundEl\" disable-upgrade$=\"[[upgradeDisabled]]\" default=\"[[default]]\">Disabled</x-disabled>\n    </template>\n\n    <script type=\"module\">\nimport '../../lib/mixins/disable-upgrade-mixin.js';\nimport { PolymerElement } from '../../polymer-element.js';\nclass MyElement extends PolymerElement {\n  static get is() { return 'my-element'; }\n  static get properties() {\n    return {\n      upgradeDisabled: {value: true},\n      default: {type: String, value: 'custom'}\n    };\n  }\n  enable() {\n    this.$.disabledEl.removeAttribute('disable-upgrade');\n    this.upgradeDisabled = false;\n  }\n}\ncustomElements.define(MyElement.is, MyElement);\n</script>\n\n  </dom-module>\n\n  <dom-module id=\"my-element-legacy\">\n\n    <template>\n      <x-disabled-legacy id=\"enabledEl\">Disabled</x-disabled-legacy>\n      <x-disabled-legacy id=\"disabledEl\" disable-upgrade default=\"custom\">Disabled</x-disabled-legacy>\n      <x-disabled-legacy id=\"disabledBoundEl\" disable-upgrade$=\"[[upgradeDisabled]]\" default=\"[[default]]\">Disabled</x-disabled-legacy>\n      <x-disabled-legacy-reg1 id=\"disabledRegEl\" disable-upgrade>Disabled</x-disabled-legacy-reg1>\n      <x-disabled-legacy-reg2 id=\"disabledRegBoundEl\" disable-upgrade$=\"[[upgradeDisabled]]\">Disabled</x-disabled-legacy-reg2>\n\n    </template>\n\n    <script type=\"module\">\nimport { Polymer } from '../../lib/legacy/polymer-fn.js';\nPolymer({\n  is: 'my-element-legacy',\n  properties: {\n    upgradeDisabled: { type: Boolean, value: true },\n    default: {type: String, value: 'custom'}\n  },\n  enable() {\n    this.$.disabledEl.removeAttribute('disable-upgrade');\n    this.$.disabledRegEl.removeAttribute('disable-upgrade');\n    this.upgradeDisabled = false;\n  }\n});\n</script>\n\n  </dom-module>\n\n<dom-module id=\"disable-upgrade-extensions\">\n  <template>\n    <ext-disabled-legacy id=\"enabledEl1\">Disabled</ext-disabled-legacy>\n    <ext-disabled-legacy id=\"disabledEl1\" disable-upgrade>Disabled</ext-disabled-legacy>\n    <ext-disabled-legacy id=\"disabledBoundEl1\" disable-upgrade$=\"[[upgradeDisabled]]\">Disabled</ext-disabled-legacy>\n\n    <ext-disabled id=\"enabledEl2\">Disabled</ext-disabled>\n    <ext-disabled id=\"disabledEl2\" disable-upgrade>Disabled</ext-disabled>\n    <ext-disabled id=\"disabledBoundEl2\" disable-upgrade$=\"[[upgradeDisabled]]\">Disabled</ext-disabled>\n\n    <ext-disabled-behaviors id=\"enabledEl3\">Disabled</ext-disabled-behaviors>\n    <ext-disabled-behaviors id=\"disabledEl3\" disable-upgrade>Disabled</ext-disabled-behaviors>\n    <ext-disabled-behaviors id=\"disabledBoundEl3\" disable-upgrade$=\"[[upgradeDisabled]]\">Disabled</ext-disabled-behaviors>\n\n  </template>\n  <script type=\"module\">\n    import { Polymer } from '../../lib/legacy/polymer-fn.js';\n    import {mixinBehaviors} from '../../lib/legacy/class.js';\n    import { DisableUpgradeMixin } from '../../lib/mixins/disable-upgrade-mixin.js';\n\n    const DisabledLegacy = customElements.get('x-disabled-legacy');\n\n    customElements.define('ext-disabled-legacy', class extends DisabledLegacy {});\n\n    customElements.define('ext-disabled', DisableUpgradeMixin(class extends customElements.get('x-disabled') {}));\n\n    customElements.define('ext-disabled-behaviors', mixinBehaviors([], DisabledLegacy));\n\n    Polymer({\n      is: 'disable-upgrade-extensions',\n      properties: {\n        upgradeDisabled: { type: Boolean, value: true }\n      },\n      enable() {\n        this.$.disabledEl1.removeAttribute('disable-upgrade');\n        this.$.disabledEl2.removeAttribute('disable-upgrade');\n        this.$.disabledEl3.removeAttribute('disable-upgrade');\n        this.upgradeDisabled = false;\n      }\n    });\n  </script>\n</dom-module>\n\n<dom-module id=\"disable-dom-if-repeat\">\n  <template>\n    <template is=\"dom-repeat\" items=\"[1]\">\n      <my-element-legacy></my-element-legacy>\n      <my-element-legacy upgrade-disabled=\"[[upgradeDisabled]]\"></my-element-legacy>\n    </template>\n    <template is=\"dom-if\" if=\"true\">\n      <my-element-legacy></my-element-legacy>\n      <my-element-legacy upgrade-disabled=\"[[upgradeDisabled]]\"></my-element-legacy>\n    </template>\n  </template>\n  <script type=\"module\">\n    import { Polymer } from '../../lib/legacy/polymer-fn.js';\n    Polymer({\n      is: 'disable-dom-if-repeat',\n      properties: {\n        upgradeDisabled: { type: Boolean, value: true }\n      },\n      enable() {\n        this.upgradeDisabled = false;\n      }\n    });\n  </script>\n</dom-module>\n\n<script type=\"module\">\n  import { Polymer } from '../../lib/legacy/polymer-fn.js';\n  Polymer({\n    is: 'x-disabled-camel',\n    properties: {\n      camelCaseProperty: Boolean,\n      bootedCorrectly: {\n        type: Boolean,\n        value: false\n      }\n    },\n    attached() {\n      if (this.camelCaseProperty) {\n        this.bootedCorrectly = true;\n      }\n    }\n  });\n</script>\n\n  <script type=\"module\">\nimport '../../lib/mixins/disable-upgrade-mixin.js';\nimport {flush} from '../../lib/utils/flush.js';\nimport {wrap} from '../../lib/utils/wrap.js';\nsuite('disable-upgrade', function() {\n  let el;\n\n  setup(() => {\n    el = document.createElement('my-element');\n    document.body.appendChild(el);\n  });\n  teardown(function() {\n    if (el.parentNode) {\n      document.body.removeChild(el);\n    }\n  });\n\n  test('elements upgrade as expected with and without `disable-upgrade`', function() {\n    assert.ok(el.$.enabledEl.enabled);\n    assert.ok(el.$.enabledEl.$.element);\n    assert.ok(el.$.enabledEl.wasConnected);\n    assert.equal(el.$.enabledEl.$.element.textContent, 'enabled!');\n    assert.notOk(el.$.disabledEl.wasConnected);\n    assert.notOk(el.$.disabledEl.enabled);\n    assert.equal(el.$.disabledEl.default, 'custom');\n    assert.notOk(el.$.disabledEl.$);\n    assert.notOk(el.$.disabledBoundEl.enabled);\n    assert.equal(el.$.disabledBoundEl.default, 'custom');\n    assert.notOk(el.$.disabledBoundEl.wasConnected);\n    assert.notOk(el.$.disabledBoundEl.$);\n  });\n\n  test('elements upgrade when `disable-upgrade` removed', function() {\n    assert.notOk(el.$.disabledEl.enabled);\n    assert.notOk(el.$.disabledEl.$);\n    assert.notOk(el.$.disabledEl.wasConnected);\n    assert.notOk(el.$.disabledBoundEl.enabled);\n    assert.notOk(el.$.disabledBoundEl.$);\n    assert.notOk(el.$.disabledBoundEl.wasConnected);\n    el.enable();\n    assert.ok(el.$.disabledEl.enabled);\n    assert.ok(el.$.disabledEl.$.element);\n    assert.equal(el.$.disabledEl.$.element.textContent, 'enabled!');\n    assert.equal(el.$.disabledEl.default, 'custom');\n    assert.ok(el.$.disabledEl.wasConnected);\n    assert.ok(el.$.disabledBoundEl.enabled);\n    assert.equal(el.$.disabledBoundEl.default, 'custom');\n    assert.ok(el.$.disabledBoundEl.$.element);\n    assert.ok(el.$.disabledBoundEl.wasConnected);\n    assert.equal(el.$.disabledBoundEl.$.element.textContent, 'enabled!');\n  });\n\n  test('elements do not connect/disconnect when disabled', function() {\n    el.parentNode.removeChild(el);\n    assert.ok(el.$.enabledEl.wasConnected);\n    assert.ok(el.$.enabledEl.wasDisconnected);\n    assert.notOk(el.$.disabledEl.wasConnected);\n    assert.notOk(el.$.disabledEl.wasDisconnected);\n    assert.notOk(el.$.disabledBoundEl.wasConnected);\n    assert.notOk(el.$.disabledBoundEl.wasDisconnected);\n    document.body.appendChild(el);\n    el.enable();\n    assert.ok(el.$.disabledEl.wasConnected);\n    assert.notOk(el.$.disabledEl.wasDisconnected);\n    assert.ok(el.$.disabledBoundEl.wasConnected);\n    assert.notOk(el.$.disabledBoundEl.wasDisconnected);\n    document.body.appendChild(el);\n    assert.ok(el.$.disabledEl.wasDisconnected);\n    assert.ok(el.$.disabledBoundEl.wasDisconnected);\n  });\n\n\n});\n\nsuite('disable-upgrade-legacy', function() {\n  let el;\n\n  setup(() => {\n    el = document.createElement('my-element-legacy');\n    document.body.appendChild(el);\n  });\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('elements call `registered` as expected with `disable-upgrade`', function() {\n    assert.notOk(el.$.disabledRegEl.hasRegistered);\n    assert.notOk(el.$.disabledRegBoundEl.hasRegistered);\n    el.enable();\n    assert.ok(el.$.disabledRegEl.hasRegistered);\n    assert.ok(el.$.disabledRegBoundEl.hasRegistered);\n  });\n\n\n  test('elements upgrade as expected with and without `disable-upgrade`', function() {\n    assert.ok(el.$.enabledEl.hasCreated);\n    assert.ok(el.$.enabledEl.enabled);\n    assert.ok(el.$.enabledEl.$.element);\n    assert.ok(el.$.enabledEl.wasConnected);\n    assert.equal(el.$.enabledEl.$.element.textContent, 'enabled!');\n    el.$.enabledEl.fooHandler = sinon.spy();\n    el.$.enabledEl.fire('foo');\n    assert.equal(el.$.enabledEl.fooHandler.callCount, 1);\n    assert.notOk(el.$.disabledEl.hasCreated);\n    assert.notOk(el.$.disabledEl.enabled);\n    assert.equal(el.$.disabledEl.default, 'custom');\n    assert.notOk(el.$.disabledEl.$);\n    assert.notOk(el.$.disabledEl.wasConnected);\n    el.$.disabledEl.fooHandler = sinon.spy();\n    el.$.disabledEl.fire('foo');\n    assert.equal(el.$.disabledEl.fooHandler.callCount, 0);\n    assert.notOk(el.$.disabledBoundEl.hasCreated);\n    assert.notOk(el.$.disabledBoundEl.enabled);\n    assert.equal(el.$.disabledBoundEl.default, 'custom');\n    assert.notOk(el.$.disabledBoundEl.$);\n    assert.notOk(el.$.disabledBoundEl.wasConnected);\n    el.$.disabledBoundEl.fooHandler = sinon.spy();\n    el.$.disabledBoundEl.fire('foo');\n    assert.equal(el.$.disabledBoundEl.fooHandler.callCount, 0);\n  });\n\n  test('elements upgrade when `disable-upgrade` removed', function() {\n    el.enable();\n    assert.ok(el.$.disabledEl.hasCreated);\n    assert.ok(el.$.disabledEl.enabled);\n    assert.equal(el.$.disabledEl.default, 'custom');\n    assert.ok(el.$.disabledEl.$.element);\n    assert.ok(el.$.disabledEl.wasConnected);\n    assert.equal(el.$.disabledEl.$.element.textContent, 'enabled!');\n    el.$.disabledEl.fooHandler = sinon.spy();\n    el.$.disabledEl.fire('foo');\n    assert.equal(el.$.disabledEl.fooHandler.callCount, 1);\n    assert.ok(el.$.disabledBoundEl.hasCreated);\n    assert.ok(el.$.disabledBoundEl.enabled);\n    assert.equal(el.$.disabledBoundEl.default, 'custom');\n    assert.ok(el.$.disabledBoundEl.$.element);\n    assert.ok(el.$.disabledBoundEl.wasConnected);\n    assert.equal(el.$.disabledBoundEl.$.element.textContent, 'enabled!');\n    el.$.disabledBoundEl.fooHandler = sinon.spy();\n    el.$.disabledBoundEl.fire('foo');\n    assert.equal(el.$.disabledBoundEl.fooHandler.callCount, 1);\n  });\n\n  test('elements do not connect/disconnect when disabled', function() {\n    el.parentNode.removeChild(el);\n    assert.ok(el.$.enabledEl.wasConnected);\n    assert.ok(el.$.enabledEl.wasDisconnected);\n    assert.notOk(el.$.disabledEl.wasConnected);\n    assert.notOk(el.$.disabledEl.wasDisconnected);\n    assert.notOk(el.$.disabledBoundEl.wasConnected);\n    assert.notOk(el.$.disabledBoundEl.wasDisconnected);\n    document.body.appendChild(el);\n    el.enable();\n    assert.ok(el.$.disabledEl.wasConnected);\n    assert.notOk(el.$.disabledEl.wasDisconnected);\n    assert.ok(el.$.disabledBoundEl.wasConnected);\n    assert.notOk(el.$.disabledBoundEl.wasDisconnected);\n    document.body.appendChild(el);\n    assert.ok(el.$.disabledEl.wasDisconnected);\n    assert.ok(el.$.disabledBoundEl.wasDisconnected);\n  });\n\n  test('elements with camelCase properties initialize correctly after being enabled', function() {\n    const div = document.createElement('div');\n    div.innerHTML = `<x-disabled-camel disable-upgrade camel-case-property></x-disabled-camel>`;\n    const camel = div.querySelector('x-disabled-camel');\n    document.body.appendChild(div);\n    camel.removeAttribute('disable-upgrade');\n    assert.ok(camel.bootedCorrectly);\n  });\n\n});\n\nsuite('disable-upgrade-extensions', function() {\n  let el;\n\n  setup(() => {\n    el = document.createElement('disable-upgrade-extensions');\n    document.body.appendChild(el);\n  });\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('elements upgrade as expected with and without `disable-upgrade`', function() {\n    assert.ok(el.$.enabledEl1.enabled);\n    assert.ok(el.$.enabledEl1.$.element);\n    assert.ok(el.$.enabledEl1.wasConnected);\n    assert.equal(el.$.enabledEl1.$.element.textContent, 'enabled!');\n    assert.notOk(el.$.disabledEl1.enabled);\n    assert.notOk(el.$.disabledEl1.$);\n    assert.notOk(el.$.disabledEl1.wasConnected);\n    assert.notOk(el.$.disabledBoundEl1.enabled);\n    assert.notOk(el.$.disabledBoundEl1.$);\n    assert.notOk(el.$.disabledBoundEl1.wasConnected);\n\n    assert.ok(el.$.enabledEl2.enabled);\n    assert.ok(el.$.enabledEl2.$.element);\n    assert.ok(el.$.enabledEl2.wasConnected);\n    assert.equal(el.$.enabledEl2.$.element.textContent, 'enabled!');\n    assert.notOk(el.$.disabledEl2.enabled);\n    assert.notOk(el.$.disabledEl2.$);\n    assert.notOk(el.$.disabledEl2.wasConnected);\n    assert.notOk(el.$.disabledBoundEl2.enabled);\n    assert.notOk(el.$.disabledBoundEl2.$);\n    assert.notOk(el.$.disabledBoundEl2.wasConnected);\n\n    assert.ok(el.$.enabledEl3.enabled);\n    assert.ok(el.$.enabledEl3.$.element);\n    assert.ok(el.$.enabledEl3.wasConnected);\n    assert.equal(el.$.enabledEl3.$.element.textContent, 'enabled!');\n    assert.notOk(el.$.disabledEl3.enabled);\n    assert.notOk(el.$.disabledEl3.$);\n    assert.notOk(el.$.disabledEl3.wasConnected);\n    assert.notOk(el.$.disabledBoundEl3.enabled);\n    assert.notOk(el.$.disabledBoundEl3.$);\n    assert.notOk(el.$.disabledBoundEl3.wasConnected);\n  });\n\n  test('elements upgrade when `disable-upgrade` removed', function() {\n    assert.notOk(el.$.disabledEl1.enabled);\n    assert.notOk(el.$.disabledEl1.$);\n    assert.notOk(el.$.disabledEl1.wasConnected);\n    assert.notOk(el.$.disabledBoundEl1.enabled);\n    assert.notOk(el.$.disabledBoundEl1.$);\n    assert.notOk(el.$.disabledBoundEl1.wasConnected);\n\n    assert.notOk(el.$.disabledEl2.enabled);\n    assert.notOk(el.$.disabledEl2.$);\n    assert.notOk(el.$.disabledEl2.wasConnected);\n    assert.notOk(el.$.disabledBoundEl2.enabled);\n    assert.notOk(el.$.disabledBoundEl2.$);\n    assert.notOk(el.$.disabledBoundEl2.wasConnected);\n\n    assert.notOk(el.$.disabledEl3.enabled);\n    assert.notOk(el.$.disabledEl3.$);\n    assert.notOk(el.$.disabledEl3.wasConnected);\n    assert.notOk(el.$.disabledBoundEl3.enabled);\n    assert.notOk(el.$.disabledBoundEl3.$);\n    assert.notOk(el.$.disabledBoundEl3.wasConnected);\n\n    el.enable();\n\n    assert.ok(el.$.disabledEl1.enabled);\n    assert.ok(el.$.disabledEl1.$.element);\n    assert.ok(el.$.disabledEl1.wasConnected);\n    assert.equal(el.$.disabledEl1.$.element.textContent, 'enabled!');\n    assert.ok(el.$.disabledBoundEl1.enabled);\n    assert.ok(el.$.disabledBoundEl1.$.element);\n    assert.ok(el.$.disabledBoundEl1.wasConnected);\n    assert.equal(el.$.disabledBoundEl1.$.element.textContent, 'enabled!');\n\n    assert.ok(el.$.disabledEl2.enabled);\n    assert.ok(el.$.disabledEl2.$.element);\n    assert.ok(el.$.disabledEl2.wasConnected);\n    assert.equal(el.$.disabledEl2.$.element.textContent, 'enabled!');\n    assert.ok(el.$.disabledBoundEl2.enabled);\n    assert.ok(el.$.disabledBoundEl2.$.element);\n    assert.ok(el.$.disabledBoundEl2.wasConnected);\n    assert.equal(el.$.disabledBoundEl2.$.element.textContent, 'enabled!');\n\n    assert.ok(el.$.disabledEl3.enabled);\n    assert.ok(el.$.disabledEl3.$.element);\n    assert.ok(el.$.disabledEl3.wasConnected);\n    assert.equal(el.$.disabledEl3.$.element.textContent, 'enabled!');\n    assert.ok(el.$.disabledBoundEl3.enabled);\n    assert.ok(el.$.disabledBoundEl3.$.element);\n    assert.ok(el.$.disabledBoundEl3.wasConnected);\n    assert.equal(el.$.disabledBoundEl3.$.element.textContent, 'enabled!');\n  });\n});\n\nsuite('disable-upgrade-dom-if-repeat', function() {\n  let el;\n\n  setup(() => {\n    el = document.createElement('disable-dom-if-repeat');\n    document.body.appendChild(el);\n    flush();\n  });\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('elements upgrade as expected with and without `disable-upgrade` and upgrad when disable-upgrade is removed', function() {\n    const els = Array.from(wrap(el).shadowRoot.querySelectorAll('my-element-legacy'));\n    assert.equal(els.length, 4);\n\n    const checkDisabledEl = (e) => {\n      assert.ok(e.$.enabledEl.enabled);\n      assert.ok(e.$.enabledEl.$.element);\n      assert.ok(e.$.enabledEl.wasConnected);\n      assert.equal(e.$.enabledEl.$.element.textContent, 'enabled!');\n      assert.notOk(e.$.disabledEl.enabled);\n      assert.notOk(e.$.disabledEl.$);\n      assert.notOk(e.$.disabledEl.wasConnected);\n      assert.notOk(e.$.disabledBoundEl.enabled);\n      assert.notOk(e.$.disabledBoundEl.$);\n      assert.notOk(e.$.disabledBoundEl.wasConnected);\n    };\n    // check initial state\n    els.forEach(checkDisabledEl);\n\n    // check state after upgrade\n    el.enable();\n\n    const checkEnabledEl = (e) => {\n      assert.notOk(e.$.disabledEl.enabled);\n      assert.notOk(e.$.disabledEl.$);\n      assert.notOk(e.$.disabledEl.wasConnected);\n      assert.ok(e.$.disabledBoundEl.enabled);\n      assert.ok(e.$.disabledBoundEl.$.element);\n      assert.ok(e.$.disabledBoundEl.wasConnected);\n      assert.equal(e.$.disabledBoundEl.$.element.textContent, 'enabled!');\n    };\n    checkEnabledEl(els[1]);\n    checkEnabledEl(els[3]);\n\n  });\n});\n</script>\n</body>\n</html>"
  },
  {
    "path": "test/unit/dom-bind-elements1.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport { Polymer } from '../../lib/legacy/polymer-fn.js';\n\nimport { html } from '../../lib/utils/html-tag.js';\nPolymer({\n  is: 'x-basic',\n  properties: {\n    notifyingvalue: {\n      notify: true\n    }\n  }\n});\nPolymer({\n  _template: html`\n<div id=\"container\"><slot id=\"slot\"></slot></div>\n`,\n\n  is: 'x-content'\n});\nPolymer({\n  _template: html`\n<x-content id=\"local\"></x-content>\n`,\n\n  is: 'x-attach-dom-bind',\n\n  attached: function() {\n    var domBind = document.createElement('dom-bind');\n    var template = document.createElement('template');\n\n    domBind.appendChild(template);\n\n    var span = document.createElement('span');\n    span.innerHTML = '{{hello}}';\n\n    template.content.appendChild(span);\n    domBind.hello = 'hey';\n\n    this.$.local.appendChild(domBind);\n  }\n});\nPolymer({\n  _template: html`\n<x-content id=\"local\"></x-content>\n`,\n\n  is: 'x-compose'\n});\nPolymer({\n  is: 'x-produce-a',\n  properties: {\n    bindToText: {\n      notify: true,\n      value: 'this text is bound'\n    }\n  }\n});\n"
  },
  {
    "path": "test/unit/dom-bind-elements2.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport { Polymer } from '../../lib/legacy/polymer-fn.js';\n\nPolymer({\n  is: 'x-needs-host',\n  attached: function() {\n    if (!this.__dataHost) {\n      throw \"No dataHost at ready time\";\n    }\n    this.config = this.__dataHost.getAttribute('config');\n  }\n});\n"
  },
  {
    "path": "test/unit/dom-bind.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n</head>\n<body>\n\n  <dom-bind id=\"earlyDomBind\">\n    <template>\n      <div id=\"earlyBoundChild\">{{value}}</div>\n    </template>\n  </dom-bind>\n\n  <script type=\"module\">\nimport './dom-bind-elements1.js';\nimport './dom-bind-elements2.js';\n/* global earlyDomBind */\nearlyDomBind.value = 'hi!';\n</script>\n\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n  <script type=\"module\" src=\"./dom-bind-elements1.js\"></script>\n\n  <dom-bind id=\"declarativeDomBind\">\n    <template>\n      <x-basic id=\"declaredXBasic1\" value=\"{{value}}\" notifyingvalue=\"{{nvalue}}\" on-custom=\"handleEvent\" on-tap=\"handleTap\" computed=\"{{compute(dep)}}\"></x-basic>\n      <x-basic id=\"declaredXBasic2\" value=\"{{value}}\" notifyingvalue=\"{{nvalue}}\"></x-basic>\n      <x-produce-a bind-to-text={{boundText}}></x-produce-a>\n      <div id=\"boundTextDiv\">{{boundText}}</div>\n    </template>\n  </dom-bind>\n\n  <div id=\"container\">\n  </div>\n\n  <dom-bind id=\"timingDomBind\" config=\"config\">\n    <template>\n      <x-needs-host id=\"needsHost\"></x-needs-host>\n    </template>\n  </dom-bind>\n\n  <script type=\"module\">\nimport './dom-bind-elements1.js';\nimport './dom-bind-elements2.js';\n</script>\n\n  <div id=\"nonUpgrade\">\n    <dom-bind>\n      <template>stamped</template>\n    </dom-bind>\n  </div>\n\n  <script type=\"module\">\nimport './dom-bind-elements1.js';\nimport './dom-bind-elements2.js';\nimport { DomBind } from '../../lib/elements/dom-bind.js';\nimport { flush } from '../../lib/utils/flush.js';\n\nsuite('Polymer.DomBind class', function() {\n  test('is available', function() {\n    assert.isDefined(DomBind);\n    assert.equal(typeof DomBind, 'function');\n  });\n});\n\nsuite('dom-bind touched before upgrade', function() {\n  test('value binds top-down', function() {\n    /* global earlyBoundChild*/\n    assert.equal(earlyBoundChild.textContent, 'hi!');\n  });\n});\n\nsuite('declarative dom-bind', function() {\n\n  var domBind;\n  var el1;\n  var el2;\n\n  setup(function() {\n    /* global declarativeDomBind declaredXBasic1 declaredXBasic2 */\n    domBind = declarativeDomBind;\n    el1 = declaredXBasic1;\n    el2 = declaredXBasic2;\n  });\n\n  test('value binds top-down', function() {\n    domBind.value = 'foo';\n    assert.equal(el1.value, 'foo');\n    assert.equal(el2.value, 'foo');\n  });\n\n  test('notifyingvalue binds from child to child', function() {\n    el1.notifyingvalue = 'bar';\n    assert.equal(domBind.nvalue, 'bar');\n    assert.equal(el2.notifyingvalue, 'bar');\n  });\n\n  test('event listener fires', function() {\n    domBind.handleEvent = sinon.spy();\n    el1.fire('custom');\n    assert.equal(domBind.handleEvent.callCount, 1);\n  });\n\n  test('gesture event listener fires', function() {\n    domBind.handleTap = sinon.spy();\n    el1.click();\n    assert.equal(domBind.handleTap.callCount, 1);\n  });\n\n  test('inline function runs', function() {\n    domBind.compute = function(val) {\n      return val * 10;\n    };\n    domBind.dep = 5;\n    assert.equal(el1.computed, 50);\n  });\n\n  test('initial value notifies to dom-bind', function() {\n    assert.equal(domBind.boundText, 'this text is bound');\n    /* global boundTextDiv */\n    assert.equal(boundTextDiv.textContent, 'this text is bound');\n  });\n\n});\n\nsuite('imperative dom-bind', function() {\n  var domBind;\n  var el1;\n  var el2;\n\n  setup(function() {\n    domBind = document.createElement('dom-bind');\n    var template = document.createElement('template');\n\n    domBind.appendChild(template);\n\n    var doc = template.content.ownerDocument;\n    el1 = doc.createElement('x-basic');\n\n    el1.setAttribute('id', 'impEl1');\n    el1.setAttribute('value', '{{value}}');\n    el1.setAttribute('notifyingvalue', '{{nvalue}}');\n    el1.setAttribute('on-custom', 'handleEvent');\n    el1.setAttribute('on-tap', 'handleTap');\n    el1.setAttribute('computed', '{{compute(dep)}}');\n\n    el2 = doc.createElement('x-basic');\n    el2.setAttribute('id', 'impEl2');\n    el2.setAttribute('value', '{{value}}');\n    el2.setAttribute('notifyingvalue', '{{nvalue}}');\n\n    template.content.appendChild(el1);\n    template.content.appendChild(el2);\n    document.body.appendChild(domBind);\n\n\n    el1 = domBind.$.impEl1;\n    el2 = domBind.$.impEl2;\n  });\n\n  teardown(function() {\n    if (domBind.parentElement) {\n      domBind.parentElement.removeChild(domBind);\n    }\n  });\n\n  test('value binds top-down', function() {\n    domBind.value = 'foo';\n    assert.equal(el1.value, 'foo');\n    assert.equal(el2.value, 'foo');\n  });\n\n  test('notifyingvalue binds from child to child', function() {\n    el1.notifyingvalue = 'bar';\n    assert.equal(domBind.nvalue, 'bar');\n    assert.equal(el2.notifyingvalue, 'bar');\n  });\n\n  test('event listener fires', function() {\n    domBind.handleEvent = sinon.spy();\n    el1.fire('custom');\n    assert.equal(domBind.handleEvent.callCount, 1);\n  });\n\n  test('gesture event listener fires', function() {\n    domBind.handleTap = sinon.spy();\n    el1.click();\n    assert.equal(domBind.handleTap.callCount, 1);\n  });\n\n  test('inline function runs', function() {\n    domBind.compute = function(val) {\n      return val * 10;\n    };\n    domBind.dep = 5;\n    assert.equal(el1.computed, 50);\n  });\n\n  test('move dom-bind', function( ) {\n    /* global container */\n    container.appendChild(domBind);\n\n    assert.equal(container.firstElementChild, el1);\n    assert.equal(container.firstElementChild.nextElementSibling, el2);\n  });\n\n  test('remove dom-bind', function() {\n    assert(document.body.contains(el1));\n    assert(document.body.contains(el2));\n\n    domBind.parentElement.removeChild(domBind);\n\n    assert(!document.body.contains(el1));\n    assert(!document.body.contains(el2));\n  });\n\n  test('dom-bind distributed when inserted in element attached',\n      function() {\n    var el = document.createElement('x-attach-dom-bind');\n    document.body.appendChild(el);\n\n    // Flush CE & distribution\n    flush();\n\n    assert.equal(el.$.local.$.slot.assignedNodes()[0].textContent, 'hey',\n        'dom-bind did not distribute');\n    document.body.removeChild(el);\n  });\n\n  test('dom-bind distributed when inserted dynamically', function() {\n    var composeEl = document.createElement('x-compose');\n    document.body.appendChild(composeEl);\n\n    var dynamicDomBind = document.createElement('dom-bind');\n    var dynamicTemplate = document.createElement('template');\n\n    dynamicDomBind.appendChild(dynamicTemplate);\n\n    var span = document.createElement('span');\n    span.innerHTML = '{{hello}}';\n\n    dynamicTemplate.content.appendChild(span);\n    dynamicDomBind.hello = 'hey';\n    composeEl.$.local.appendChild(dynamicDomBind);\n\n    // Flush CE & distribution\n    flush();\n\n    assert.equal(composeEl.$.local.$.slot.assignedNodes()[0].textContent, 'hey',\n        'dom-bind did not distribute');\n    document.body.removeChild(composeEl);\n  });\n\n});\n/* global needsHost nonUpgrade */\nsuite('timing', function() {\n\n  test('late-loaded import should block stamping', function() {\n    assert.equal(needsHost.config, 'config');\n  });\n\n  test('non-upgrade case finds template', function() {\n    assert.equal(nonUpgrade.textContent.trim(), 'stamped');\n  });\n\n});\n</script>\n\n  <script type=\"module\" src=\"./dom-bind-elements2.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/dom-if-elements.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport { Polymer } from '../../lib/legacy/polymer-fn.js';\n\nimport { html } from '../../lib/utils/html-tag.js';\nPolymer({\n  _template: html`\n    <x-bar id=\"bar\" prop=\"{{prop}}\" item-prop=\"{{item.prop}}\">\n    </x-bar>\n`,\n\n  is: 'x-foo',\n\n  properties: {\n    prop: {\n      notify: true\n    },\n    itemProp: {\n      notify: true\n    }\n  }\n});\nPolymer({\n  is: 'x-bar',\n  properties: {\n    prop: {\n      notify: true\n    },\n    itemProp: {\n      notify: true\n    }\n  }\n});\nPolymer({\n  _template: html`\n    <template is=\"dom-if\" id=\"if-1\" if=\"{{shouldStamp}}\" on-dom-change=\"domUpdateHandler\">\n      <!-- Comments should be good -->\n      <x-foo on-test1=\"testHandler1\" prop=\"{{prop}}\" item-prop=\"{{item.prop}}\">\n      </x-foo>\n      <template is=\"dom-if\" id=\"if-2\" if=\"{{shouldStamp}}\">\n        <!-- Comments should be good -->\n        <x-foo on-test2=\"testHandler2\" prop=\"{{prop}}\" item-prop=\"{{item.prop}}\">\n        </x-foo>\n        <template is=\"dom-if\" id=\"if-3\" if=\"{{shouldStamp}}\">\n        <!-- Comments should be good -->\n          <x-foo on-test3=\"testHandler3\" prop=\"{{prop}}\" item-prop=\"{{item.prop}}\">\n          </x-foo>\n        </template>\n      </template>\n    </template>\n`,\n\n  is: 'x-nested-if',\n  testHandler1Count: 0,\n  testHandler2Count: 0,\n  testHandler3Count: 0,\n  domUpdateHandlerCount: 0,\n\n  testHandler1: function() {\n    this.testHandler1Count++;\n  },\n\n  testHandler2: function() {\n    this.testHandler2Count++;\n  },\n\n  testHandler3: function() {\n    this.testHandler3Count++;\n  },\n\n  render: function() {\n    this.$['if-1'].render();\n  },\n\n  domUpdateHandler: function() {\n    this.domUpdateHandlerCount++;\n  }\n});\nPolymer({\n  _template: html`\n    <template is=\"dom-if\" id=\"if-1\" if=\"{{shouldStamp}}\">\n      <!-- Comments should be good -->\n      <x-foo prop=\"{{prop}}\" item-prop=\"{{item.prop}}\">\n      </x-foo>\n      <template is=\"dom-if\" id=\"if-2\" if=\"{{shouldStamp}}\">\n        <!-- Comments should be good -->\n        <x-foo prop=\"{{prop}}\" item-prop=\"{{item.prop}}\">\n        </x-foo>\n        <template is=\"dom-if\" id=\"if-3\" if=\"{{shouldStamp}}\">\n          <!-- Comments should be good -->\n          <x-foo prop=\"{{prop}}\" item-prop=\"{{item.prop}}\">\n          </x-foo>\n        </template>\n      </template>\n    </template>\n`,\n\n  is: 'x-nested-if-configured',\n\n  properties: {\n    shouldStamp: {\n      value: true\n    },\n    prop: {\n      value: 'outer'\n    },\n    item: {\n      value: function() { return {prop: 'outerItem'}; }\n    }\n  },\n\n  render: function() {\n    this.$['if-1'].render();\n  }\n});\nPolymer({\n  _template: html`\n    <template is=\"dom-if\" id=\"if-1\" if=\"{{shouldStamp1}}\">\n      <x-foo prop=\"{{prop1}}\"></x-foo>\n      <template is=\"dom-if\" id=\"if-2\" if=\"{{shouldStamp2}}\">\n        <x-foo prop=\"{{prop2}}\"></x-foo>\n        <template is=\"dom-if\" id=\"if-3-1\" if=\"{{shouldStamp3_1}}\" restamp>\n          <x-foo prop=\"{{prop3_1}}\"></x-foo>\n        </template>\n        <template is=\"dom-if\" id=\"if-4-2\" if=\"{{shouldStamp3_2}}\" restamp>\n          <x-foo prop=\"{{prop3_2}}\"></x-foo>\n        </template>\n        <template is=\"dom-if\" id=\"if-5-3\" if=\"{{shouldStamp3_3}}\" restamp>\n          <x-foo prop=\"{{prop3_3}}\"></x-foo>\n        </template>\n      </template>\n    </template>\n`,\n\n  is: 'x-nested-if-individual',\n\n  properties: {\n    prop1: {\n      value: 'prop1'\n    },\n    prop2: {\n      value: 'prop2'\n    },\n    prop3_1: {\n      value: 'prop3_1'\n    },\n    prop3_2: {\n      value: 'prop3_2'\n    },\n    prop3_3: {\n      value: 'prop3_3'\n    },\n    item: {\n      value: function() { return {prop: 'outerItem'}; }\n    }\n  },\n\n  render: function() {\n    this.$['if-1'].render();\n  }\n});\nPolymer({\n  _template: html`\n    <template id=\"domIf\" is=\"dom-if\" if=\"\">\n      <div>1</div>\n      <div>2</div>\n      <div>3</div>\n      {{text}}\n      <div>4</div>\n    </template>\n`,\n\n  is: 'x-textcontent',\n\n  properties: {\n    text: {\n      value: 'Stuff'\n    }\n  }\n});\nPolymer({\n  _template: html`\n      <template id=\"domIf\" is=\"dom-if\" if=\"\">\n        <div class=\"stuff\">stuff</div>\n        <slot id=\"one\" name=\"one\"></slot><template id=\"innerIf\" is=\"dom-if\" if=\"\" restamp=\"\">hi</template>\n        <slot id=\"two\" name=\"two\"></slot>\n        {{text}}\n        <slot id=\"three\" name=\"three\"></slot>\n      </template>\n`,\n\n  is: 'x-slot',\n\n  properties: {\n    text: {\n      value: 'Stuff'\n    }\n  }\n});\nPolymer({\n  _template: html`\n    <template id=\"domif\" is=\"dom-if\" if=\"\">\n      <x-client></x-client>\n      <x-client></x-client>\n      <x-client></x-client>\n    </template>\n`,\n\n  is: 'x-host'\n});\nPolymer({\n  is: 'x-client',\n  statics: {\n    uid: 0\n  },\n  ready: function() {\n    this.uid = this.statics.uid++;\n  }\n});\nPolymer({\n  _template: html`\n    <template is=\"dom-if\" if=\"{{bool}}\" restamp=\"{{restamp}}\">{{guarded(bool)}}</template>\n`,\n\n  is: 'x-guard-prop',\n\n  created: function() {\n    this.guarded = sinon.spy(function(val) {\n      return val;\n    });\n  }\n});\nPolymer({\n  _template: html`\n    <template is=\"dom-if\" if=\"{{isTrue(bool)}}\" restamp=\"{{restamp}}\">{{guarded(bool)}}</template>\n`,\n\n  is: 'x-guard-inline',\n\n  created: function() {\n    this.guarded = sinon.spy(function(val) {\n      return val;\n    });\n  },\n\n  isTrue: function(val) {\n    return val;\n  }\n});\nPolymer({\n  _template: html`\n    <template is=\"dom-if\" if=\"{{switch}}\" restamp=\"{{restamp}}\">{{guarded(bool)}}</template>\n`,\n\n  is: 'x-guard-computed',\n\n  properties: {\n    switch: {\n      computed: 'computeSwitch(bool)'\n    }\n  },\n\n  created: function() {\n    this.guarded = sinon.spy(function(val) {\n      return val;\n    });\n  },\n\n  computeSwitch: function(val) {\n    return val;\n  }\n});\nPolymer({\n  _template: html`\n    <template is=\"dom-if\" if=\"{{obj.bool}}\" restamp=\"{{restamp}}\">{{guarded(obj.bool)}}</template>\n`,\n\n  is: 'x-guard-object',\n\n  created: function() {\n    this.guarded = sinon.spy(function(val) {\n      return val;\n    });\n  }\n});\nPolymer({\n  _template: html`\n    <template is=\"dom-if\" if=\"{{switch}}\" restamp=\"{{restamp}}\">{{guarded(obj.bool)}}</template>\n`,\n\n  is: 'x-guard-object-computed',\n\n  properties: {\n    switch: {\n      computed: 'computeSwitch(obj.bool)'\n    }\n  },\n\n  created: function() {\n    this.guarded = sinon.spy(function(val) {\n      return val;\n    });\n  },\n\n  computeSwitch: function(val) {\n    return val;\n  }\n});\n\nPolymer({\n  is: 'prop-observer',\n  properties: {\n    prop: {\n      observer: 'propChanged'\n    }\n  },\n  observers: ['pathChanged(obj.*)'],\n  created() {\n    this.propChanged = sinon.spy();\n    this.pathChanged = sinon.spy();\n  }\n});\n\nPolymer({\n  _template: html`\n    <template is=\"dom-if\" if=\"{{b}}\" restamp=\"{{restamp}}\">\n      {{guarded(a)}}\n      <prop-observer id=\"observer\" prop=\"[[c.d]]\" obj=\"[[c]]\"></prop-observer>\n    </template>\n`,\n\n  is: 'x-guard-separate-props',\n\n  created: function() {\n    this.guarded = sinon.spy(function(val) {\n      return val;\n    });\n  }\n});\nPolymer({\n  _template: html`\n    <template is=\"dom-if\" if=\"{{obj.b}}\" restamp=\"{{restamp}}\">{{guarded(obj.a)}}</template>\n`,\n\n  is: 'x-guard-separate-paths',\n\n  created: function() {\n    this.guarded = sinon.spy(function(val) {\n      return val;\n    });\n  }\n});\n"
  },
  {
    "path": "test/unit/dom-if.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\">\n    import { setRemoveNestedTemplates, setFastDomIf } from '../../lib/utils/settings.js';\n    setRemoveNestedTemplates(location.search.match(/removeNestedTemplates/));\n    setFastDomIf(location.search.match(/fastDomIf/));\n  </script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n  <script type=\"module\" src=\"./dom-if-elements.js\"></script>\n</head>\n<body>\n\n  <x-nested-if-configured id=\"configured\"></x-nested-if-configured>\n\n  <x-nested-if-individual id=\"individual\"></x-nested-if-individual>\n\n  <dom-bind id=\"unconfigured\">\n    <template>\n      <x-nested-if id=\"unconfigured1\"></x-nested-if>\n      <x-nested-if id=\"unconfigured2\"></x-nested-if>\n    </template>\n  </dom-bind>\n\n  <div id=\"inDocumentContainer\">\n    <dom-if id=\"inDocumentIf\">\n      <template>\n        <x-foo\n               prop=\"{{prop}}\"\n               item-prop=\"{{item.prop}}\">\n        </x-foo>\n        <template is=\"dom-if\">\n          <x-foo\n                 prop=\"{{prop}}\"\n                 item-prop=\"{{item.prop}}\">\n          </x-foo>\n          <template is=\"dom-if\">\n            <x-foo\n                   prop=\"{{prop}}\"\n                   item-prop=\"{{item.prop}}\">\n            </x-foo>\n          </template>\n        </template>\n      </template>\n    </dom-if>\n  </div>\n\n  <div id=\"structuredContainer\">\n    <dom-bind id=\"structuredDomBind\">\n      <template>\n        <template is=\"dom-if\" id=\"structuredDomIf\" if=\"{{item.show}}\">\n          <div class=\"showing\"></div>\n        </template>\n      </template>\n    </dom-bind>\n  </div>\n\n  <div id=\"outerContainer\">\n    <dom-if id=\"simple\">\n      <template>\n        <x-client></x-client>\n        <x-client></x-client>\n        <x-client></x-client>\n      </template>\n    </dom-if>\n\n    <div id=\"innerContainer\">\n    </div>\n  </div>\n\n  <div id=\"removalContainer\">\n    <dom-if if id=\"toBeRemoved\">\n      <template><div id=\"shouldBeRemoved\"></div></template>\n    </dom-if>\n  </div>\n\n  <script type=\"module\">\nimport './dom-if-elements.js';\n</script>\n\n  <div id=\"nonUpgrade\">\n    <dom-if if>\n      <template>stamped</template>\n    </dom-if>\n  </div>\n\n\n  <script type=\"module\">\nimport './dom-if-elements.js';\nimport { flush } from '../../lib/utils/flush.js';\n/* global configured individual unconfigured1 unconfigured2 inDocumentContainer inDocumentIf structuredContainer structuredDomIf structuredDomBind outerContainer innerContainer shouldBeRemoved toBeRemoved removalContainer nonUpgrade*/\nsuite('nested pre-configured dom-if', function() {\n\n  test('parent scope binding', function() {\n    let stamped = configured.shadowRoot.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 3, 'total stamped count incorrect');\n    assert.equal(stamped[0].prop, 'outer');\n    assert.equal(stamped[0].itemProp, 'outerItem');\n    assert.equal(stamped[1].prop, 'outer');\n    assert.equal(stamped[1].itemProp, 'outerItem');\n    assert.equal(stamped[2].prop, 'outer');\n    assert.equal(stamped[2].itemProp, 'outerItem');\n  });\n\n  test('parent scope downward notification', function() {\n    let stamped = configured.shadowRoot.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    configured.prop = 'yes';\n    assert.equal(stamped[0].prop, 'yes');\n    assert.equal(stamped[1].prop, 'yes');\n    assert.equal(stamped[2].prop, 'yes');\n    configured.set('item.prop', 'yay');\n    assert.equal(stamped[0].itemProp, 'yay');\n    assert.equal(stamped[1].itemProp, 'yay');\n    assert.equal(stamped[2].itemProp, 'yay');\n  });\n\n  test('parent upward upward notification', function() {\n    let stamped = configured.shadowRoot.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    stamped[2].prop = 'nice';\n    assert.equal(configured.prop, 'nice');\n    assert.equal(stamped[0].prop, 'nice');\n    assert.equal(stamped[1].prop, 'nice');\n    assert.equal(stamped[2].prop, 'nice');\n  });\n\n  test('dom-change event composed, bubbles outside dom-if scope', function() {\n    let domChangeFired = 0;\n    let domIf = configured.$['if-1'];\n    configured.addEventListener('dom-change', function() {\n      domChangeFired++;\n    });\n    domIf.if = !domIf.if;\n    domIf.render();\n    domIf.if = !domIf.if;\n    domIf.render();\n    assert.equal(domChangeFired, 2);\n  });\n\n});\n\nsuite('nested individually-controlled dom-if', function() {\n\n  test('nothing stamped', function() {\n    let stamped = individual.shadowRoot.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 0, 'total stamped count incorrect');\n  });\n\n  test('show 1', function() {\n    individual.shouldStamp1 = true;\n    individual.render();\n    let stamped = individual.shadowRoot.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 1, 'total stamped count incorrect');\n    assert.equal(stamped[0].prop, 'prop1');\n    assert.equal(getComputedStyle(stamped[0]).display, 'inline', 'stamped 1 display wrong');\n  });\n\n  test('show 2', function() {\n    individual.shouldStamp2 = true;\n    individual.render();\n    let stamped = individual.shadowRoot.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 2, 'total stamped count incorrect');\n    assert.equal(stamped[0].prop, 'prop1');\n    assert.equal(stamped[1].prop, 'prop2');\n    assert.equal(getComputedStyle(stamped[0]).display, 'inline', 'stamped 1 display wrong');\n    assert.equal(getComputedStyle(stamped[1]).display, 'inline', 'stamped 2 display wrong');\n  });\n\n  test('show 3-1', function() {\n    individual.shouldStamp3_1 = true;\n    individual.render();\n    let stamped = individual.shadowRoot.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 3, 'total stamped count incorrect');\n    assert.equal(stamped[0].prop, 'prop1');\n    assert.equal(stamped[1].prop, 'prop2');\n    assert.equal(stamped[2].prop, 'prop3_1');\n    assert.equal(getComputedStyle(stamped[0]).display, 'inline', 'stamped 1 display wrong');\n    assert.equal(getComputedStyle(stamped[1]).display, 'inline', 'stamped 2 display wrong');\n    assert.equal(getComputedStyle(stamped[2]).display, 'inline', 'stamped 3-1 display wrong');\n  });\n\n  test('show 3-2', function() {\n    individual.shouldStamp3_2 = true;\n    individual.render();\n    let stamped = individual.shadowRoot.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 4, 'total stamped count incorrect');\n    assert.equal(stamped[0].prop, 'prop1');\n    assert.equal(stamped[1].prop, 'prop2');\n    assert.equal(stamped[2].prop, 'prop3_1');\n    assert.equal(stamped[3].prop, 'prop3_2');\n    assert.equal(getComputedStyle(stamped[0]).display, 'inline', 'stamped 1 display wrong');\n    assert.equal(getComputedStyle(stamped[1]).display, 'inline', 'stamped 2 display wrong');\n    assert.equal(getComputedStyle(stamped[2]).display, 'inline', 'stamped 3-1 display wrong');\n    assert.equal(getComputedStyle(stamped[3]).display, 'inline', 'stamped 3-2 display wrong');\n  });\n\n  test('remove 3-2', function() {\n    individual.shouldStamp3_2 = false;\n    individual.render();\n    let stamped = individual.shadowRoot.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 3, 'total stamped count incorrect');\n    assert.equal(stamped[0].prop, 'prop1');\n    assert.equal(stamped[1].prop, 'prop2');\n    assert.equal(stamped[2].prop, 'prop3_1');\n    assert.equal(getComputedStyle(stamped[0]).display, 'inline', 'stamped 1 display wrong');\n    assert.equal(getComputedStyle(stamped[1]).display, 'inline', 'stamped 2 display wrong');\n    assert.equal(getComputedStyle(stamped[2]).display, 'inline', 'stamped 3-1 display wrong');\n  });\n\n  test('show 3-3', function() {\n    individual.shouldStamp3_3 = true;\n    individual.render();\n    let stamped = individual.shadowRoot.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 4, 'total stamped count incorrect');\n    assert.equal(stamped[0].prop, 'prop1');\n    assert.equal(stamped[1].prop, 'prop2');\n    assert.equal(stamped[2].prop, 'prop3_1');\n    assert.equal(stamped[3].prop, 'prop3_3');\n    assert.equal(getComputedStyle(stamped[0]).display, 'inline', 'stamped 1 display wrong');\n    assert.equal(getComputedStyle(stamped[1]).display, 'inline', 'stamped 2 display wrong');\n    assert.equal(getComputedStyle(stamped[2]).display, 'inline', 'stamped 3-1 display wrong');\n    assert.equal(getComputedStyle(stamped[3]).display, 'inline', 'stamped 3-3 display wrong');\n  });\n\n  test('update 3-3', function() {\n    individual.prop3_3 = 'prop3_3*';\n    let stamped = individual.shadowRoot.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 4, 'total stamped count incorrect');\n    assert.equal(stamped[0].prop, 'prop1');\n    assert.equal(stamped[1].prop, 'prop2');\n    assert.equal(stamped[2].prop, 'prop3_1');\n    assert.equal(stamped[3].prop, 'prop3_3*');\n  });\n\n  test('remove 3-3', function() {\n    individual.shouldStamp3_3 = false;\n    individual.render();\n    let stamped = individual.shadowRoot.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 3, 'total stamped count incorrect');\n    assert.equal(stamped[0].prop, 'prop1');\n    assert.equal(stamped[1].prop, 'prop2');\n    assert.equal(stamped[2].prop, 'prop3_1');\n    assert.equal(getComputedStyle(stamped[0]).display, 'inline', 'stamped 1 display wrong');\n    assert.equal(getComputedStyle(stamped[1]).display, 'inline', 'stamped 2 display wrong');\n    assert.equal(getComputedStyle(stamped[2]).display, 'inline', 'stamped 3-1 display wrong');\n  });\n\n  test('remove 3', function() {\n    individual.shouldStamp3_1 = false;\n    individual.render();\n    let stamped = individual.shadowRoot.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 2, 'total stamped count incorrect');\n    assert.equal(stamped[0].prop, 'prop1');\n    assert.equal(stamped[1].prop, 'prop2');\n    assert.equal(getComputedStyle(stamped[0]).display, 'inline', 'stamped 1 display wrong');\n    assert.equal(getComputedStyle(stamped[1]).display, 'inline', 'stamped 2 display wrong');\n  });\n\n  test('hide 2', function() {\n    individual.shouldStamp2 = false;\n    individual.render();\n    let stamped = individual.shadowRoot.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 2, 'total stamped count incorrect');\n    assert.equal(getComputedStyle(stamped[0]).display, 'inline', 'stamped 1 display wrong');\n    assert.equal(getComputedStyle(stamped[1]).display, 'none', 'stamped 2 display wrong');\n  });\n\n  test('hide 1', function() {\n    individual.shouldStamp1 = false;\n    individual.render();\n    let stamped = individual.shadowRoot.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 2, 'total stamped count incorrect');\n    assert.equal(getComputedStyle(stamped[0]).display, 'none', 'stamped 1 display wrong');\n    assert.equal(getComputedStyle(stamped[1]).display, 'none', 'stamped 2 display wrong');\n  });\n\n  test('show 1', function() {\n    individual.shouldStamp1 = true;\n    individual.render();\n    let stamped = individual.shadowRoot.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 2, 'total stamped count incorrect');\n    assert.equal(getComputedStyle(stamped[0]).display, 'inline', 'stamped 1 display wrong');\n    assert.equal(getComputedStyle(stamped[1]).display, 'none', 'stamped 2 display wrong');\n  });\n\n  test('show 2', function() {\n    individual.shouldStamp2 = true;\n    individual.render();\n    let stamped = individual.shadowRoot.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 2, 'total stamped count incorrect');\n    assert.equal(getComputedStyle(stamped[0]).display, 'inline', 'stamped 1 display wrong');\n    assert.equal(getComputedStyle(stamped[1]).display, 'inline', 'stamped 2 display wrong');\n  });\n\n  test('show 3', function() {\n    individual.shouldStamp3_1 = true;\n    individual.render();\n    let stamped = individual.shadowRoot.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 3, 'total stamped count incorrect');\n    assert.equal(getComputedStyle(stamped[0]).display, 'inline', 'stamped 1 display wrong');\n    assert.equal(getComputedStyle(stamped[1]).display, 'inline', 'stamped 2 display wrong');\n    assert.equal(getComputedStyle(stamped[2]).display, 'inline', 'stamped 3 display wrong');\n  });\n\n});\n\nsuite('nested un-configured dom-if in document', function() {\n\n  test('if=false: nothing rendered', function() {\n    let stamped = inDocumentContainer.querySelectorAll('*:not(template):not(dom-if)');\n    assert.equal(stamped.length, 0, 'total stamped count incorrect');\n  });\n\n  test('if=true: everything rendered and visible', function() {\n    // first dom-if\n    inDocumentIf.if = true;\n    inDocumentIf.render();\n    let stamped = inDocumentContainer.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 1, 'total stamped count incorrect');\n\n    // second dom-if\n    let xif = inDocumentContainer.querySelector('dom-if');\n    xif.if = true;\n    xif.render();\n    stamped = inDocumentContainer.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 2, 'total stamped count incorrect');\n\n    // third dom-if\n    xif = inDocumentContainer.querySelector('dom-if');\n    xif.if = true;\n    xif.render();\n    stamped = inDocumentContainer.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 3, 'total stamped count incorrect');\n\n    stamped = inDocumentContainer.querySelectorAll('*:not(template):not(dom-if)');\n    stamped.forEach(function(n) {\n      assert.equal(getComputedStyle(n).display, 'inline', 'node was hidden but should not have been');\n    });\n  });\n\n  test('if=false, restamp=false: everything hidden', function() {\n    inDocumentIf.if = false;\n    inDocumentIf.render();\n    let stamped = inDocumentContainer.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 3, 'total stamped count incorrect');\n    stamped = inDocumentContainer.querySelectorAll('*:not(template):not(dom-if)');\n    stamped.forEach(function(n) {\n      assert.equal(getComputedStyle(n).display, 'none', 'node was not hidden but should have been');\n    });\n  });\n\n  test('if=true, restamp=true, everything rendered and visible', function() {\n    inDocumentIf.restamp = true;\n    inDocumentIf.if = true;\n    inDocumentIf.render();\n    let stamped = inDocumentContainer.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 3, 'total stamped count incorrect');\n    stamped = inDocumentContainer.querySelectorAll('*:not(template):not(dom-if)');\n    stamped.forEach(function(n) {\n      assert.equal(getComputedStyle(n).display, 'inline', 'node was hidden but should not have been');\n    });\n  });\n\n  test('if=false, restamp=true, everything gone', function() {\n    inDocumentIf.restamp = true;\n    inDocumentIf.if = false;\n    inDocumentIf.render();\n    // 2nd one needed to force nested if to detach\n    let stamped = inDocumentContainer.querySelectorAll('*:not(template):not(dom-if)');\n    assert.equal(stamped.length, 0, 'total stamped count incorrect');\n  });\n\n  // repeat, just to get everything rendered again...\n  test('if=true: everything rendered and visible', function() {\n    // first dom-if\n    inDocumentIf.if = true;\n    inDocumentIf.render();\n    let stamped = inDocumentContainer.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 1, 'total stamped count incorrect');\n\n    // second dom-if\n    let xif = inDocumentContainer.querySelector('dom-if');\n    xif.if = true;\n    xif.render();\n    stamped = inDocumentContainer.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 2, 'total stamped count incorrect');\n\n    // third dom-if\n    xif = inDocumentContainer.querySelector('dom-if');\n    xif.if = true;\n    xif.render();\n    stamped = inDocumentContainer.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 3, 'total stamped count incorrect');\n\n    stamped = inDocumentContainer.querySelectorAll('*:not(template):not(dom-if)');\n    stamped.forEach(function(n) {\n      assert.equal(getComputedStyle(n).display, 'inline', 'node was hidden but should not have been');\n    });\n  });\n\n  test('parent scope binding', function() {\n    let stamped = inDocumentContainer.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    stamped[0].prop = 'outer';\n    assert.equal(stamped[1].prop, 'outer');\n    assert.equal(stamped[2].prop, 'outer');\n  });\n\n});\n\nsuite('nested un-configured dom-if', function() {\n\n  test('if=false: nothing rendered', function() {\n    let stamped = unconfigured1.shadowRoot.querySelectorAll('*:not(template):not(dom-if)');\n    assert.equal(stamped.length, 0, 'total stamped count incorrect');\n  });\n\n  test('if=true: everything rendered and visible', function() {\n    unconfigured1.domUpdateHandlerCount = 0;\n    unconfigured1.shouldStamp = true;\n    unconfigured2.shouldStamp = true;\n    unconfigured1.render();\n    let stamped = unconfigured1.shadowRoot.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 3, 'total stamped count incorrect');\n    stamped[0].prop = 'outer';\n    assert.equal(unconfigured1.domUpdateHandlerCount, 1);\n  });\n\n  test('if=false, restamp=false: everything hidden', function() {\n    unconfigured1.domUpdateHandlerCount = 0;\n    unconfigured1.shouldStamp = false;\n    unconfigured1.render();\n    let stamped = unconfigured1.shadowRoot.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 3, 'total stamped count incorrect');\n    stamped = unconfigured1.shadowRoot.querySelectorAll('*:not(template):not(dom-if)');\n    stamped.forEach(function(n) {\n      assert.equal(getComputedStyle(n).display, 'none', 'node was not hidden but should have been');\n    });\n    assert.equal(unconfigured1.domUpdateHandlerCount, 1);\n  });\n\n  test('if=true, restamp=true, everything rendered and visible', function() {\n    unconfigured1.domUpdateHandlerCount = 0;\n    unconfigured1.$['if-1'].restamp = true;\n    unconfigured1.shouldStamp = true;\n    unconfigured1.$['if-1'].render();\n    let stamped = unconfigured1.shadowRoot.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 3, 'total stamped count incorrect');\n    stamped = unconfigured1.shadowRoot.querySelectorAll('*:not(template):not(dom-if)');\n    stamped.forEach(function(n) {\n      assert.equal(getComputedStyle(n).display, 'inline', 'node was hidden but should not have been');\n    });\n    assert.equal(unconfigured1.domUpdateHandlerCount, 1);\n  });\n\n  test('if=false, restamp=true, everything gone', function() {\n    unconfigured1.domUpdateHandlerCount = 0;\n    unconfigured1.$['if-1'].restamp = true;\n    unconfigured1.shouldStamp = false;\n    unconfigured1.$['if-1'].render();\n    let stamped = unconfigured1.shadowRoot.querySelectorAll('*:not(template):not(dom-if)');\n    assert.equal(unconfigured1.domUpdateHandlerCount, 1);\n    assert.equal(stamped.length, 0, 'total stamped count incorrect');\n    assert.equal(unconfigured1.domUpdateHandlerCount, 1);\n  });\n\n  // repeat, just to get everything rendered again...\n  test('if=true: everything rendered and visible', function() {\n    unconfigured1.domUpdateHandlerCount = 0;\n    unconfigured1.shouldStamp = true;\n    unconfigured2.shouldStamp = true;\n    unconfigured1.render();\n    unconfigured2.render();\n    let stamped = unconfigured1.shadowRoot.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped.length, 3, 'total stamped count incorrect');\n    stamped[0].prop = 'outer';\n    assert.equal(unconfigured1.domUpdateHandlerCount, 1);\n  });\n\n  test('parent scope binding', function() {\n    let stamped = unconfigured1.shadowRoot.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    assert.equal(stamped[1].prop, 'outer');\n    assert.equal(stamped[2].prop, 'outer');\n  });\n\n  test('parent upward upward notification', function() {\n    let stamped = unconfigured1.shadowRoot.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    stamped[2].prop = 'nice';\n    assert.equal(stamped[0].prop, 'nice');\n    assert.equal(stamped[1].prop, 'nice');\n  });\n\n  test('event handlers', function() {\n    let stamped = unconfigured1.shadowRoot.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    stamped[0].fire('test1');\n    assert.equal(unconfigured1.testHandler1Count, 1);\n    stamped[1].fire('test2');\n    assert.equal(unconfigured1.testHandler2Count, 1);\n    stamped[2].fire('test3');\n    assert.equal(unconfigured1.testHandler3Count, 1);\n  });\n\n});\n\nsuite('notification between two dom-ifs', function() {\n\n  test('change to one scope doesn\\'t affect other dom-if', function() {\n    let stamped1 = unconfigured1.shadowRoot.querySelectorAll('*:not(template):not(dom-if):not(span)');\n    let stamped2 = unconfigured2.shadowRoot.querySelectorAll('*:not(template):not(dom-if):not(span)');\n\n    unconfigured1.prop = 'foo';\n    unconfigured2.prop = 'bar';\n    assert.equal(stamped1[0].prop, 'foo');\n    assert.equal(stamped1[1].prop, 'foo');\n    assert.equal(stamped1[2].prop, 'foo');\n    assert.equal(stamped2[0].prop, 'bar');\n    assert.equal(stamped2[1].prop, 'bar');\n    assert.equal(stamped2[2].prop, 'bar');\n  });\n});\n\nsuite('structured data controlling if', function() {\n\n  test('item changed with no if field', function() {\n    let showing;\n    showing = structuredContainer.querySelector('.showing');\n    assert.notOk(showing);\n    structuredDomBind.item = {show: true};\n    structuredDomIf.render();\n    showing = structuredContainer.querySelector('.showing');\n    assert.ok(showing);\n    assert.equal(getComputedStyle(showing).display, 'block');\n    structuredDomBind.item = {};\n    structuredDomIf.render();\n    showing = structuredContainer.querySelector('.showing');\n    assert.ok(showing);\n    assert.equal(getComputedStyle(showing).display, 'none');\n    structuredDomBind.item = {show: true};\n    structuredDomIf.render();\n    showing = structuredContainer.querySelector('.showing');\n    assert.ok(showing);\n    assert.equal(getComputedStyle(showing).display, 'block');\n  });\n\n  test('item changed with no if field (restamp)', function() {\n    let showing;\n    structuredDomIf.restamp = true;\n    structuredDomIf.if = false;\n    structuredDomIf.render();\n    showing = structuredContainer.querySelector('.showing');\n    assert.notOk(showing);\n    structuredDomBind.item = {show: true};\n    structuredDomIf.render();\n    showing = structuredContainer.querySelector('.showing');\n    assert.ok(showing);\n    structuredDomBind.item = {};\n    structuredDomIf.render();\n    showing = structuredContainer.querySelector('.showing');\n    assert.notOk(showing);\n    structuredDomBind.item = {show: true};\n    structuredDomIf.render();\n    showing = structuredContainer.querySelector('.showing');\n    assert.ok(showing);\n  });\n\n});\n\nsuite('text node handling', function() {\n\n  test('text nodes cleared on if=false', function() {\n    let x = document.createElement('x-textcontent');\n    document.body.appendChild(x);\n    x.$.domIf.render();\n    let stamped = x.shadowRoot.childNodes;\n    assert.equal(stamped.length, 12);\n    assert.equal(stamped[7].textContent.trim(), 'Stuff');\n    x.$.domIf.if = false;\n    x.$.domIf.render();\n    stamped = x.shadowRoot.childNodes;\n    assert.equal(stamped.length, 12);\n    assert.equal(stamped[7].textContent.trim(), '');\n    x.$.domIf.if = true;\n    x.$.domIf.render();\n    stamped = x.shadowRoot.childNodes;\n    assert.equal(stamped.length, 12);\n    assert.equal(stamped[7].textContent.trim(), 'Stuff');\n    document.body.removeChild(x);\n  });\n\n  test('binding to text nodes changed while if=false', function() {\n    let x = document.createElement('x-textcontent');\n    document.body.appendChild(x);\n    x.$.domIf.render();\n    let stamped = x.shadowRoot.childNodes;\n    assert.equal(stamped.length, 12);\n    assert.equal(stamped[7].textContent.trim(), 'Stuff');\n    x.$.domIf.if = false;\n    x.$.domIf.render();\n    x.text = 'Hollaaaaa!';\n    stamped = x.shadowRoot.childNodes;\n    assert.equal(stamped.length, 12);\n    assert.equal(stamped[7].textContent.trim(), '');\n    x.$.domIf.if = true;\n    x.$.domIf.render();\n    stamped = x.shadowRoot.childNodes;\n    assert.equal(stamped.length, 12);\n    assert.equal(stamped[7].textContent.trim(), 'Hollaaaaa!');\n    document.body.removeChild(x);\n  });\n\n});\n\nsuite('slot handling', function() {\n\n  test('slots added/removed on if=true/false', function() {\n    let x = document.createElement('x-slot');\n    let one = document.createElement('div');\n    one.slot = 'one';\n    x.appendChild(one);\n    let two = document.createElement('div');\n    two.slot = 'two';\n    x.appendChild(two);\n    let three = document.createElement('div');\n    three.slot = 'three';\n    x.appendChild(three);\n    document.body.appendChild(x);\n    x.$.domIf.render();\n    let stamped = x.shadowRoot.childNodes;\n    assert.equal(stamped.length, 14);\n    assert.equal(stamped[4].assignedNodes()[0], one);\n    assert.equal(stamped[8].assignedNodes()[0], two);\n    assert.equal(stamped[10].assignedNodes()[0], three);\n    x.$.domIf.if = false;\n    x.$.domIf.render();\n    stamped = x.shadowRoot.childNodes;\n    assert.equal(stamped.length, 14);\n    x.$.domIf.if = true;\n    x.$.domIf.render();\n    stamped = x.shadowRoot.childNodes;\n    assert.equal(stamped.length, 14);\n    assert.equal(stamped[4].assignedNodes()[0], one);\n    assert.equal(stamped[8].assignedNodes()[0], two);\n    assert.equal(stamped[10].assignedNodes()[0], three);\n    x.$.domIf.if = false;\n    x.$.domIf.render();\n    const innerIf = x.shadowRoot.querySelector('#innerIf');\n    innerIf.if = false;\n    innerIf.render();\n    x.$.domIf.if = true;\n    x.$.domIf.render();\n    stamped = x.shadowRoot.childNodes;\n    assert.equal(stamped[4].assignedNodes()[0], one);\n    assert.equal(stamped[7].assignedNodes()[0], two);\n    assert.equal(stamped[9].assignedNodes()[0], three);\n    document.body.removeChild(x);\n  });\n\n});\n\nsuite('attach/detach tests', function() {\n\n  test('move domif (clients persist)', function(done) {\n    let domif = document.querySelector('#simple');\n    domif.if = true;\n    innerContainer.appendChild(domif);\n    setTimeout(function() {\n      let clients = innerContainer.querySelectorAll('x-client');\n      // Same clients as before since move happened in one turn\n      assert.equal(clients[0].uid, 0);\n      assert.equal(clients[1].uid, 1);\n      assert.equal(clients[2].uid, 2);\n      assert.equal(clients[1].previousElementSibling, clients[0]);\n      assert.equal(clients[2].previousElementSibling, clients[1]);\n      assert.equal(domif.previousElementSibling, clients[2]);\n      done();\n    });\n  });\n\n  test('remove, wait, append domif (clients recreated)', function(done) {\n    let domif = document.querySelector('#simple');\n    domif.if = true;\n    innerContainer.removeChild(domif);\n    setTimeout(function() {\n      let clients = innerContainer.querySelectorAll('x-client');\n      assert.equal(clients.length, 0);\n      innerContainer.appendChild(domif);\n      setTimeout(function() {\n        let clients = outerContainer.querySelectorAll('x-client');\n        // New clients since removed for a turn\n        assert.equal(clients[0].uid, 3);\n        assert.equal(clients[1].uid, 4);\n        assert.equal(clients[2].uid, 5);\n        assert.equal(clients[1].previousElementSibling, clients[0]);\n        assert.equal(clients[2].previousElementSibling, clients[1]);\n        assert.equal(domif.previousElementSibling, clients[2]);\n        done();\n      });\n    });\n  });\n\n  test('move host with domif (clients persist)', function(done) {\n    let host = document.createElement('x-host');\n    outerContainer.appendChild(host);\n    setTimeout(function() {\n      let clients = host.shadowRoot.querySelectorAll('x-client');\n      // New clients created in host instance\n      assert.equal(clients[0].uid, 6);\n      assert.equal(clients[1].uid, 7);\n      assert.equal(clients[2].uid, 8);\n      assert.equal(clients[1].previousElementSibling, clients[0]);\n      assert.equal(clients[2].previousElementSibling, clients[1]);\n      assert.equal(host.$.domif.previousElementSibling, clients[2]);\n      innerContainer.appendChild(host);\n      setTimeout(function() {\n        let clients = host.shadowRoot.querySelectorAll('x-client');\n        // Clients in removed host persist\n        assert.equal(clients[0].uid, 6);\n        assert.equal(clients[1].uid, 7);\n        assert.equal(clients[2].uid, 8);\n        assert.equal(clients[1].previousElementSibling, clients[0]);\n        assert.equal(clients[2].previousElementSibling, clients[1]);\n        assert.equal(host.$.domif.previousElementSibling, clients[2]);\n        done();\n      });\n    });\n  });\n\n  test('remove, wait, append host with domif (clients persist)', function(done) {\n    let host = document.createElement('x-host');\n    outerContainer.appendChild(host);\n    setTimeout(function() {\n      let clients = host.shadowRoot.querySelectorAll('x-client');\n      // New clients created in host instance\n      assert.equal(clients[0].uid, 9);\n      assert.equal(clients[1].uid, 10);\n      assert.equal(clients[2].uid, 11);\n      assert.equal(clients[1].previousElementSibling, clients[0]);\n      assert.equal(clients[2].previousElementSibling, clients[1]);\n      assert.equal(host.$.domif.previousElementSibling, clients[2]);\n      outerContainer.removeChild(host);\n      setTimeout(function() {\n        // Clients in removed host persist\n        assert.equal(clients[0].uid, 9);\n        assert.equal(clients[1].uid, 10);\n        assert.equal(clients[2].uid, 11);\n        assert.equal(clients[1].previousElementSibling, clients[0]);\n        assert.equal(clients[2].previousElementSibling, clients[1]);\n        assert.equal(host.$.domif.previousElementSibling, clients[2]);\n        innerContainer.appendChild(host);\n        setTimeout(function() {\n          // Clients in removed host persist\n          let clients = host.shadowRoot.querySelectorAll('x-client');\n          assert.equal(clients[0].uid, 9);\n          assert.equal(clients[1].uid, 10);\n          assert.equal(clients[2].uid, 11);\n          assert.equal(clients[1].previousElementSibling, clients[0]);\n          assert.equal(clients[2].previousElementSibling, clients[1]);\n          assert.equal(host.$.domif.previousElementSibling, clients[2]);\n          done();\n        });\n      });\n    });\n  });\n\n  test('remove, append domif', function(done) {\n    let domif = document.querySelector('#simple');\n    let parent = domif.parentNode;\n    domif.if = true;\n    parent.removeChild(domif);\n    setTimeout(function() {\n      let clients = parent.querySelectorAll('x-client');\n      assert.equal(clients.length, 0);\n      parent.appendChild(domif);\n      setTimeout(function() {\n        let clients = parent.querySelectorAll('x-client');\n        assert.equal(clients[0].uid, 12);\n        assert.equal(clients[1].uid, 13);\n        assert.equal(clients[2].uid, 14);\n        assert.equal(clients[1].previousElementSibling, clients[0]);\n        assert.equal(clients[2].previousElementSibling, clients[1]);\n        assert.equal(domif.previousElementSibling, clients[2]);\n        done();\n      });\n    });\n  });\n\n  test('move into doc fragment', function(done) {\n    let el = shouldBeRemoved;\n    assert.equal(el.parentNode, removalContainer);\n    let frag = document.createDocumentFragment();\n    frag.appendChild(toBeRemoved);\n    setTimeout(function() {\n      assert.equal(el.parentNode, null);\n      removalContainer.appendChild(frag);\n      setTimeout(function() {\n        assert.equal(shouldBeRemoved.parentNode, removalContainer);\n        done();\n      });\n    });\n  });\n\n  test('move into shadow root', function(done) {\n    if (window.ShadyCSS && window.ShadyCSS.nativeShadow) {\n      let el = shouldBeRemoved;\n      assert.equal(el.parentNode, removalContainer);\n      let div = document.createElement('div');\n      document.body.appendChild(div);\n      let frag = div.attachShadow({mode: 'open'});\n      frag.appendChild(toBeRemoved);\n      setTimeout(function() {\n        assert.equal(el.parentNode, frag);\n        done();\n      });\n    } else {\n      done();\n    }\n  });\n\n});\n\nsuite('timing', function() {\n\n  test('non-upgrade case finds template', function() {\n    assert.equal(nonUpgrade.textContent.trim(), 'stamped');\n  });\n\n});\n\n[true, false].forEach(function(restamp) {\n\n  suite('ordering, restamp: ' + restamp, function() {\n\n    test('effects in if not run when `if` goes false via property', function() {\n      let el = document.createElement('x-guard-prop');\n      el.restamp = restamp;\n      document.body.appendChild(el);\n      el.bool = true;\n      flush();\n      assert.equal(el.guarded.callCount, 1);\n      assert.equal(el.shadowRoot.textContent.trim(), 'true');\n      el.bool = false;\n      flush();\n      assert.equal(el.guarded.callCount, 1);\n      assert.equal(el.shadowRoot.textContent.trim(), '');\n      document.body.removeChild(el);\n    });\n\n    test('effects in if not run when `if` goes false via inline function', function() {\n      let el = document.createElement('x-guard-inline');\n      el.restamp = restamp;\n      document.body.appendChild(el);\n      el.bool = true;\n      flush();\n      assert.equal(el.guarded.callCount, 1);\n      assert.equal(el.shadowRoot.textContent.trim(), 'true');\n      el.bool = false;\n      flush();\n      assert.equal(el.guarded.callCount, 1);\n      assert.equal(el.shadowRoot.textContent.trim(), '');\n      document.body.removeChild(el);\n    });\n\n    test('effects in if not run when `if` goes false via computed property', function() {\n      let el = document.createElement('x-guard-computed');\n      el.restamp = restamp;\n      document.body.appendChild(el);\n      el.bool = true;\n      flush();\n      assert.equal(el.guarded.callCount, 1);\n      assert.equal(el.shadowRoot.textContent.trim(), 'true');\n      el.bool = false;\n      flush();\n      assert.equal(el.guarded.callCount, 1);\n      assert.equal(el.shadowRoot.textContent.trim(), '');\n      document.body.removeChild(el);\n    });\n\n    test('effects in if not run when `if` goes false via object sub-property', function() {\n      let el = document.createElement('x-guard-object');\n      el.restamp = restamp;\n      document.body.appendChild(el);\n      el.obj = {bool: true};\n      flush();\n      assert.equal(el.guarded.callCount, 1);\n      assert.equal(el.shadowRoot.textContent.trim(), 'true');\n      el.obj = {bool: false};\n      flush();\n      assert.equal(el.guarded.callCount, 1);\n      assert.equal(el.shadowRoot.textContent.trim(), '');\n      document.body.removeChild(el);\n    });\n\n    test('effects in if not run when `if` goes false via computed from object sub-property', function() {\n      let el = document.createElement('x-guard-object-computed');\n      el.restamp = restamp;\n      document.body.appendChild(el);\n      el.obj = {bool: true};\n      flush();\n      assert.equal(el.guarded.callCount, 1);\n      assert.equal(el.shadowRoot.textContent.trim(), 'true');\n      el.obj = {bool: false};\n      flush();\n      assert.equal(el.guarded.callCount, 1);\n      assert.equal(el.shadowRoot.textContent.trim(), '');\n      document.body.removeChild(el);\n    });\n\n    test('effects in if not run when `if` goes false via setProperties batch', function() {\n      let el = document.createElement('x-guard-separate-props');\n      el.restamp = restamp;\n      document.body.appendChild(el);\n      el.setProperties({a: 'ok', b: true});\n      flush();\n      assert.equal(el.guarded.callCount, 1);\n      assert.equal(el.shadowRoot.textContent.trim(), 'ok');\n      el.setProperties({a: 'notok', b: false});\n      flush();\n      assert.equal(el.guarded.callCount, 1);\n      assert.equal(el.shadowRoot.textContent.trim(), '');\n      document.body.removeChild(el);\n    });\n\n    test('host properties in sync when changed while false', function() {\n      let el = document.createElement('x-guard-separate-props');\n      el.restamp = restamp;\n      document.body.appendChild(el);\n      el.b = true;\n      flush();\n      el.a = 'ok';\n      el.c = {d: 'ok'};\n      assert.equal(el.shadowRoot.textContent.trim(), 'ok');\n      let observer = el.shadowRoot.querySelector('#observer');\n      assert.equal(observer.propChanged.callCount, 1);\n      assert.equal(observer.pathChanged.callCount, 1);\n      assert.equal(observer.pathChanged.getCalls()[0].args[0].path, 'obj');\n      el.b = false;\n      el.a = 'notok';\n      el.set('c.d', 'notok');\n      flush();\n      assert.equal(el.shadowRoot.textContent.trim(), '');\n      if (!restamp) {\n        const observer = el.shadowRoot.querySelector('#observer');\n        assert.equal(observer.propChanged.callCount, 1);\n        assert.equal(observer.pathChanged.callCount, 1);\n      }\n      el.set('c.d', 'changed');\n      el.a = 'changed';\n      el.b = true;\n      flush();\n      assert.equal(el.shadowRoot.textContent.trim(), 'changed');\n      observer = el.shadowRoot.querySelector('#observer');\n      // Note that path bindings in a falsey dom-if will be updated when the\n      // dom-if becomes truthy, however path notifications to other elements\n      // will be lost; this is a fundamental limitation (#4818) due to the fact\n      // that batched path notifications are not supported. Hence the\n      // `propChanged` count increments, but the `pathChanged` count does not.\n      assert.equal(observer.propChanged.callCount, restamp ? 1 : 2);\n      assert.equal(observer.pathChanged.callCount, 1);\n      document.body.removeChild(el);\n    });\n\n    test('host properties in sync toggling true-false-true synchronously', function() {\n      let el = document.createElement('x-guard-separate-props');\n      el.restamp = restamp;\n      document.body.appendChild(el);\n      el.a = 'initial';\n      el.b = true;\n      flush();\n      assert.equal(el.shadowRoot.textContent.trim(), 'initial');\n      el.setProperties({b: false, a: 'changed'});\n      el.b = true;\n      flush();\n      assert.equal(el.shadowRoot.textContent.trim(), 'changed');\n      document.body.removeChild(el);\n    });\n\n    test('host paths in sync when changed while false', function() {\n      let el = document.createElement('x-guard-separate-paths');\n      el.restamp = restamp;\n      document.body.appendChild(el);\n      el.obj = {a: 'ok', b: true};\n      flush();\n      assert.equal(el.shadowRoot.textContent.trim(), 'ok');\n      el.set('obj.b', false);\n      el.set('obj.a', 'notok');\n      flush();\n      assert.equal(el.shadowRoot.textContent.trim(), '');\n      el.set('obj.a', 'changed');\n      el.set('obj.b', true);\n      flush();\n      assert.equal(el.shadowRoot.textContent.trim(), 'changed');\n      document.body.removeChild(el);\n    });\n\n  });\n\n});\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/dom-repeat-elements.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport { Polymer } from '../../lib/legacy/polymer-fn.js';\n\nimport { html } from '../../lib/utils/html-tag.js';\nimport { MutableData } from '../../lib/mixins/mutable-data.js';\nwindow.getData = () => [\n  {\n    prop: 'prop-1',\n    items: [\n      {\n        prop: 'prop-1-1',\n        items: [\n          { prop: 'prop-1-1-1' },\n          { prop: 'prop-1-1-2' },\n          { prop: 'prop-1-1-3' }\n        ]\n      },\n      {\n        prop: 'prop-1-2',\n        items: [\n          { prop: 'prop-1-2-1' },\n          { prop: 'prop-1-2-2' },\n          { prop: 'prop-1-2-3' }\n        ]\n      },\n      {\n        prop: 'prop-1-3',\n        items: [\n          { prop: 'prop-1-3-1' },\n          { prop: 'prop-1-3-2' },\n          { prop: 'prop-1-3-3' }\n        ]\n      }\n    ]\n  },\n  {\n    prop: 'prop-2',\n    items: [\n      {\n        prop: 'prop-2-1',\n        items: [\n          { prop: 'prop-2-1-1' },\n          { prop: 'prop-2-1-2' },\n          { prop: 'prop-2-1-3' }\n        ]\n      },\n      {\n        prop: 'prop-2-2',\n        items: [\n          { prop: 'prop-2-2-1' },\n          { prop: 'prop-2-2-2' },\n          { prop: 'prop-2-2-3' }\n        ]\n      },\n      {\n        prop: 'prop-2-3',\n        items: [\n          { prop: 'prop-2-3-1' },\n          { prop: 'prop-2-3-2' },\n          { prop: 'prop-2-3-3' }\n        ]\n      }\n    ]\n  },\n  {\n    prop: 'prop-3',\n    items: [\n      {\n        prop: 'prop-3-1',\n        items: [\n          { prop: 'prop-3-1-1' },\n          { prop: 'prop-3-1-2' },\n          { prop: 'prop-3-1-3' }\n        ]\n      },\n      {\n        prop: 'prop-3-2',\n        items: [\n          { prop: 'prop-3-2-1' },\n          { prop: 'prop-3-2-2' },\n          { prop: 'prop-3-2-3' }\n        ]\n      },\n      {\n        prop: 'prop-3-3',\n        items: [\n          { prop: 'prop-3-3-1' },\n          { prop: 'prop-3-3-2' },\n          { prop: 'prop-3-3-3' }\n        ]\n      }\n    ]\n  }\n];\n\nPolymer({\n  _template: html`\n    <style>\n      :host {\n        display: block;\n        border: 1px solid black;\n        padding: 3px;\n        margin: 3px;\n      }\n    </style>\n    <span>{{itemaProp}}</span>\n    <span>{{itembProp}}</span>\n    <span>{{itemcProp}}</span>\n    <x-bar id=\"bar\" outer-prop=\"{{outerProp}}\" outer-item-prop=\"{{outerItemProp}}\" innera-prop=\"{{inneraProp}}\" itema-prop=\"{{itemaProp}}\" innerb-prop=\"{{innerbProp}}\" itemb-prop=\"{{itembProp}}\" innerc-prop=\"{{innercProp}}\" itemc-prop=\"{{itemcProp}}\" computed1=\"{{computed1}}\" computed2=\"{{computed2}}\" computed3=\"{{computed3}}\">\n    </x-bar>\n`,\n\n  is: 'x-foo',\n\n  properties: {\n    outerProp: {\n      notify: true\n    },\n    outerItemProp: {\n      notify: true\n    },\n    inneraProp: {\n      notify: true\n    },\n    itemaProp: {\n      notify: true\n    },\n    innerbProp: {\n      notify: true\n    },\n    itembProp: {\n      notify: true\n    },\n    innercProp: {\n      notify: true\n    },\n    itemcProp: {\n      notify: true\n    },\n    indexa: {\n      notify: true\n    },\n    indexb: {\n      notify: true\n    },\n    indexc: {\n      notify: true\n    }\n  }\n});\nPolymer({\n  is: 'x-bar',\n  properties: {\n    outerProp: {\n      notify: true\n    },\n    outerItemProp: {\n      notify: true\n    },\n    inneraProp: {\n      notify: true\n    },\n    itemaProp: {\n      notify: true\n    },\n    innerbProp: {\n      notify: true\n    },\n    itembProp: {\n      notify: true\n    },\n    innercProp: {\n      notify: true\n    },\n    itemcProp: {\n      notify: true\n    },\n    indexa: {\n      notify: true\n    },\n    indexb: {\n      notify: true\n    },\n    indexc: {\n      notify: true\n    }\n  }\n});\nlet XNestedRepeat = Polymer({\n    _template: html`\n  <template id=\"repeater\" is=\"dom-repeat\" items=\"{{items}}\" as=\"itema\" index-as=\"indexa\" on-dom-change=\"domUpdateHandler\">\n    <x-foo on-test1=\"testHandler1\"\n           innera-prop=\"{{innera.prop}}\"\n           itema-prop=\"{{itema.prop}}\"\n           outer-prop=\"{{prop}}\"\n           outer-item-prop=\"{{item.prop}}\"\n           indexa=\"{{indexa}}\">\n    </x-foo>\n    <template is=\"dom-repeat\" items=\"{{itema.items}}\" as=\"itemb\" index-as=\"indexb\">\n      <x-foo on-test2=\"testHandler2\"\n             innerb-prop=\"{{innerb.prop}}\"\n             itemb-prop=\"{{itemb.prop}}\"\n             innera-prop=\"{{innera.prop}}\"\n             itema-prop=\"{{itema.prop}}\"\n             outer-prop=\"{{prop}}\"\n             outer-item-prop=\"{{item.prop}}\"\n             indexa=\"{{indexa}}\"\n             indexb=\"{{indexb}}\">\n      </x-foo>\n      <template is=\"dom-repeat\" items=\"{{itemb.items}}\" as=\"itemc\" index-as=\"indexc\">\n        <x-foo on-test3=\"testHandler3\"\n               innerc-prop=\"{{innerc.prop}}\"\n               itemc-prop=\"{{itemc.prop}}\"\n               innerb-prop=\"{{innerb.prop}}\"\n               itemb-prop=\"{{itemb.prop}}\"\n               innera-prop=\"{{innera.prop}}\"\n               itema-prop=\"{{itema.prop}}\"\n               outer-prop=\"{{prop}}\"\n               outer-item-prop=\"{{item.prop}}\"\n               indexa=\"{{indexa}}\"\n               indexb=\"{{indexb}}\"\n               indexc=\"{{indexc}}\">\n       </x-foo>\n      </template>\n    </template>\n  </template>\n`,\n  is: 'x-nested-repeat',\n  testHandler1Count: 0,\n  testHandler2Count: 0,\n  testHandler3Count: 0,\n  domUpdateHandlerCount: 0,\n  testHandler1: function() {\n    this.testHandler1Count++;\n  },\n  testHandler2: function() {\n    this.testHandler2Count++;\n  },\n  testHandler3: function() {\n    this.testHandler3Count++;\n  },\n  domUpdateHandler: function() {\n    this.domUpdateHandlerCount++;\n  }\n});\nclass XNestedRepeatMutable extends MutableData(XNestedRepeat) {\n  static get template() {\n    if (!this._templateEl) {\n      this._templateEl = XNestedRepeat.template.cloneNode(true);\n    }\n    return this.makeRepeatsMutable(this._templateEl.cloneNode(true));\n  }\n  static makeRepeatsMutable(template) {\n    Array.from(template.content.querySelectorAll('[is=dom-repeat]')).forEach(e => {\n      e.setAttribute('mutable-data', '');\n      this.makeRepeatsMutable(e);\n    });\n    return template;\n  }\n}\ncustomElements.define('x-nested-repeat-mutable', XNestedRepeatMutable);\nPolymer({\n  _template: html`\n    <template id=\"repeater\" is=\"dom-repeat\" items=\"{{items}}\" as=\"itema\" index-as=\"indexa\" observe=\"prop\">\n      <x-foo innera-prop=\"{{innera.prop}}\" itema-prop=\"{{itema.prop}}\" outer-prop=\"{{prop}}\" outer-item-prop=\"{{item.prop}}\" indexa=\"{{indexa}}\" computeda=\"{{concat(itema.prop, itemForComputedA.prop)}}\">\n      </x-foo>\n      <template is=\"dom-repeat\" items=\"{{itema.items}}\" as=\"itemb\" index-as=\"indexb\">\n        <x-foo innerb-prop=\"{{innerb.prop}}\" itemb-prop=\"{{itemb.prop}}\" innera-prop=\"{{innera.prop}}\" itema-prop=\"{{itema.prop}}\" outer-prop=\"{{prop}}\" outer-item-prop=\"{{item.prop}}\" indexa=\"{{indexa}}\" indexb=\"{{indexb}}\" computedb=\"{{concat(itemb.prop, itemForComputedB.prop)}}\">\n        </x-foo>\n        <template is=\"dom-repeat\" items=\"{{itemb.items}}\" as=\"itemc\" index-as=\"indexc\">\n          <x-foo innerc-prop=\"{{innerc.prop}}\" itemc-prop=\"{{itemc.prop}}\" innerb-prop=\"{{innerb.prop}}\" itemb-prop=\"{{itemb.prop}}\" innera-prop=\"{{innera.prop}}\" itema-prop=\"{{itema.prop}}\" outer-prop=\"{{prop}}\" outer-item-prop=\"{{item.prop}}\" indexa=\"{{indexa}}\" indexb=\"{{indexb}}\" indexc=\"{{indexc}}\" computedc=\"{{concat(itemc.prop, itemForComputedC.prop)}}\">\n          </x-foo>\n        </template>\n      </template>\n    </template>\n`,\n\n  is: 'x-nested-repeat-configured',\n\n  properties: {\n    items: {\n      value: window.getData()\n    },\n    prop: {\n      value: 'outer'\n    },\n    item: {\n      value: function() { return {prop: 'outerItem'}; }\n    },\n    itemForComputedA: {\n      value: function() { return {prop: 'itemForComputedA'}; }\n    },\n    itemForComputedB: {\n      value: function() { return {prop: 'itemForComputedB'}; }\n    },\n    itemForComputedC: {\n      value: function() { return {prop: 'itemForComputedC'}; }\n    },\n    _testHost: {\n      value: function() { return this; }\n    }\n  },\n\n  sortDesc: function(a, b) {\n    assert.equal(this, this._testHost);\n    return b.prop.localeCompare(a.prop);\n  },\n\n  filter2nd: function(o) {\n    assert.equal(this, this._testHost);\n    return o.prop.indexOf('2') < 0;\n  },\n\n  concat: function(a, b) {\n    return a + '+' + b;\n  }\n});\nPolymer({\n  _template: html`\n      <template id=\"repeater\" is=\"dom-repeat\" items=\"{{items}}\">\n        <x-foo itema-prop=\"{{item.prop.nestedProp}}\"></x-foo>\n      </template>\n`,\n\n  is: 'x-repeat-filter-and-sort-by-nested-property',\n\n  properties: {\n    items: {\n      value () {\n        return [\n          { prop: { nestedProp: 0 } },\n          { prop: { nestedProp: 1 } },\n          { prop: { nestedProp: 2 } },\n          { prop: { nestedProp: 3 } },\n          { prop: { nestedProp: 4 } },\n        ];\n      }\n    }\n  }\n});\nPolymer({\n  _template: html`\n    <template id=\"repeat\" is=\"dom-repeat\" items=\"{{items}}\">\n      <x-foo itema-prop=\"{{item.prop}}\"></x-foo>\n    </template>\n`,\n\n  is: 'x-simple-repeat',\n\n  properties: {\n    items: {\n      value: window.getData()\n    }\n  }\n});\nPolymer({\n  _template: html`\n    <div id=\"container1\">\n      <template is=\"dom-repeat\" items=\"{{items}}\" id=\"repeater1\">\n        <x-foo itema-prop=\"{{item}}\"></x-foo>\n      </template>\n    </div>\n    <div id=\"container2\">\n      <template is=\"dom-repeat\" items=\"{{items}}\" id=\"repeater2\">\n        <x-foo itema-prop=\"{{item}}\"></x-foo>\n      </template>\n    </div>\n`,\n\n  is: 'x-primitive-repeat',\n\n  properties: {\n    items: {\n      value: function() {\n        return ['a', 'b', 'c', 'd', 'e'];\n      }\n    }\n  }\n});\nPolymer({\n  _template: html`\n    <template id=\"repeater\" is=\"dom-repeat\" items=\"{{items}}\">\n      <div>{{item}}</div>\n    </template>\n`,\n\n  is: 'x-primitive-large',\n\n  properties: {\n    items: {\n      value: function() {\n        var ar = [];\n        for (var i = 0; i < 11; i++) {\n          ar.push(i);\n        }\n        return ar;\n      }\n    }\n  }\n});\nPolymer({\n  _template: html`\n    <template id=\"repeater\" is=\"dom-repeat\" items=\"{{items}}\">\n      <div prop=\"{{outerProp.prop}}\">{{item.prop}}</div>\n    </template>\n`,\n\n  is: 'x-repeat-limit',\n\n  properties: {\n    preppedItems: {\n      value: function() {\n        var ar = [];\n        for (var i = 0; i < 20; i++) {\n          ar.push({prop: i});\n        }\n        return ar;\n      }\n    },\n    outerProp: {\n      value: function() {\n        return {prop: 'outer'};\n      }\n    }\n  }\n});\nPolymer({\n  _template: html`\n    <template id=\"repeater\" is=\"dom-repeat\" items=\"{{items}}\" initial-count=\"10\" target-framerate=\"25\">\n      <x-wait>{{item.prop}}</x-wait>\n    </template>\n`,\n\n  is: 'x-repeat-chunked',\n\n  properties: {\n    preppedItems: {\n      value: function() {\n        var ar = [];\n        for (var i = 0; i < 100; i++) {\n          ar.push({prop: i});\n        }\n        return ar;\n      }\n    }\n  }\n});\nPolymer({\n  is: 'x-wait',\n  created: function() {\n    var time = performance.now();\n    time += 4;\n    while (performance.now() < time) {} //eslint-disable-line no-empty\n  }\n});\nPolymer({\n  _template: html`\n    <template is=\"dom-repeat\" items=\"{{items}}\" id=\"outer\">\n      <template is=\"dom-if\" if=\"\" name=\"outerIf\">\n        <template is=\"dom-repeat\" items=\"{{item.items}}\" id=\"inner\">\n          <template is=\"dom-if\" if=\"\" name=\"innerIf\">\n            <button on-click=\"handleClick\">{{item.prop}}</button>\n          </template>\n        </template>\n      </template>\n    </template>\n`,\n\n  is: 'x-repeat-with-if',\n\n  properties: {\n    items: {\n      value: () => [\n        {items: [{prop:'a'}, {prop: 'b'}]},\n        {items: [{prop:'c'}, {prop: 'd'}]}\n      ]\n    }\n  },\n\n  created() {\n    // cache target so it's available in spy after event stack returns\n    this.handleClick = sinon.spy((event) => event._target = event.target);\n  }\n});\n"
  },
  {
    "path": "test/unit/dom-repeat.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\">\n    import { setRemoveNestedTemplates } from '../../lib/utils/settings.js';\n    setRemoveNestedTemplates(location.search.match(/removeNestedTemplates/));\n  </script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n  <script type=\"module\" src=\"./dom-repeat-elements.js\"></script>\n  <style>\n    /* makes painting faster when testing on IOS simulator */\n    x-repeat-chunked {\n      display: none;\n    }\n  </style>\n</head>\n<body>\n\n  <test-fixture id=\"simple\">\n    <template>\n      <x-simple-repeat></x-simple-repeat>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"primitive\">\n    <template>\n      <x-primitive-repeat></x-primitive-repeat>\n    </template>\n  </test-fixture>\n\n\n  <test-fixture id=\"configured\">\n    <template>\n      <x-nested-repeat-configured></x-nested-repeat-configured>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"filter-and-sort-by-nested-property\">\n    <template>\n      <x-repeat-filter-and-sort-by-nested-property></x-repeat-filter-and-sort-by-nested-property>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"unconfigured\">\n    <template>\n      <dom-bind>\n        <template>\n          <x-nested-repeat id=\"el1\" items=\"{{items}}\"></x-nested-repeat>\n          <x-nested-repeat id=\"el2\" items=\"{{items}}\"></x-nested-repeat>\n        </template>\n      </dom-bind>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"unconfigured-mutable\">\n    <template>\n      <dom-bind mutable-data>\n        <template>\n          <x-nested-repeat-mutable id=\"el1\" items=\"{{items}}\"></x-nested-repeat-mutable>\n          <x-nested-repeat-mutable id=\"el2\" items=\"{{items}}\"></x-nested-repeat-mutable>\n        </template>\n      </dom-bind>\n    </template>\n  </test-fixture>\n\n  <h4>inDocumentRepeater</h4>\n  <div id=\"inDocumentContainerOrig\">\n    <dom-repeat id=\"inDocumentRepeater\" as=\"itema\" index-as=\"indexa\">\n      <template>\n        <x-foo\n               innera-prop=\"{{innera.prop}}\"\n               itema-prop=\"{{itema.prop}}\"\n               indexa=\"{{indexa}}\">\n        </x-foo>\n        <template is=\"dom-repeat\" items=\"{{itema.items}}\" as=\"itemb\" index-as=\"indexb\">\n          <x-foo\n                 innerb-prop=\"{{innerb.prop}}\"\n                 itemb-prop=\"{{itemb.prop}}\"\n                 innera-prop=\"{{innera.prop}}\"\n                 itema-prop=\"{{itema.prop}}\"\n                 indexa=\"{{indexa}}\"\n                 indexb=\"{{indexb}}\">\n          </x-foo>\n          <template is=\"dom-repeat\" items=\"{{itemb.items}}\" as=\"itemc\" index-as=\"indexc\">\n            <x-foo\n                   innerc-prop=\"{{innerc.prop}}\"\n                   itemc-prop=\"{{itemc.prop}}\"\n                   innerb-prop=\"{{innerb.prop}}\"\n                   itemb-prop=\"{{itemb.prop}}\"\n                   innera-prop=\"{{innera.prop}}\"\n                   itema-prop=\"{{itema.prop}}\"\n                   indexa=\"{{indexa}}\"\n                   indexb=\"{{indexb}}\"\n                   indexc=\"{{indexc}}\">\n            </x-foo>\n          </template>\n        </template>\n      </template>\n    </dom-repeat>\n  </div>\n\n  <test-fixture id=\"primitiveLarge\">\n    <template>\n      <x-primitive-large></x-primitive-large>\n    </template>\n  </test-fixture>\n\n  <h4>x-repeat-limit</h4>\n  <x-repeat-limit id=\"limited\"></x-repeat-limit>\n\n  <div id=\"inDocumentContainer\">\n  </div>\n\n  <script type=\"module\">\nimport './dom-repeat-elements.js';\n</script>\n\n  <div id=\"nonUpgrade\">\n    <dom-repeat items='[{\"prop\": \"stamped\"}]'>\n      <template>{{item.prop}}</template>\n    </dom-repeat>\n  </div>\n\n  <script type=\"module\">\nimport './dom-repeat-elements.js';\nimport { flush } from '../../lib/utils/flush.js';\nimport { calculateSplices } from '../../lib/utils/array-splice.js';\n/* global limited inDocumentRepeater inDocumentContainer inDocumentContainerOrig nonUpgrade*/\n\n/*\n  Expected:\n\n  stamped[0] ... 1\n  stamped[1] ... 1-1\n  stamped[2] ... 1-1-1\n  stamped[3] ... 1-1-2\n  stamped[4] ... 1-1-3\n  stamped[5] ... 1-2\n  ...\n  stamped[13] .. 2\n  ...\n  stamped[36] .. 3-3-1\n  stamped[37] .. 3-3-2\n  stamped[38] .. 3-3-3\n*/\n\nfunction arrayDelete(el, path, item) {\n  var array = el.get(path);\n  var idx = array.indexOf(item);\n  el.splice(path, idx, 1);\n}\n\nsuite('errors', function() {\n\n  test('items must be array', function() {\n    sinon.spy(console, 'warn');\n    inDocumentRepeater.items = {};\n    assert.isTrue(console.warn.calledOnce, 'should warn when items is not array');\n    assert.match(console.warn.firstCall.args[0], /expected array/);\n    console.warn.restore();\n  });\n\n});\n\nsuite('nested pre-configured dom-repeat', function() {\n\n  let configured;\n\n  setup(function() {\n    configured = fixture('configured');\n    flush();\n  });\n\n  test('basic rendering, downward item binding', function() {\n    var stamped = configured.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n    assert.equal(configured.$.repeater.renderedItemCount, 3, 'rendered item count incorrect');\n    assert.equal(stamped[0].itemaProp, 'prop-1');\n    assert.equal(stamped[0].computeda, 'prop-1+itemForComputedA');\n    assert.equal(stamped[0].indexa, 0);\n    assert.equal(stamped[0].$.bar.itemaProp, 'prop-1');\n    assert.equal(stamped[1].itembProp, 'prop-1-1');\n    assert.equal(stamped[1].computedb, 'prop-1-1+itemForComputedB');\n    assert.equal(stamped[1].indexa, 0);\n    assert.equal(stamped[1].indexb, 0);\n    assert.equal(stamped[1].$.bar.itembProp, 'prop-1-1');\n    assert.equal(stamped[2].itemcProp, 'prop-1-1-1');\n    assert.equal(stamped[2].computedc, 'prop-1-1-1+itemForComputedC');\n    assert.equal(stamped[2].indexa, 0);\n    assert.equal(stamped[2].indexb, 0);\n    assert.equal(stamped[2].indexc, 0);\n    assert.equal(stamped[2].$.bar.itemcProp, 'prop-1-1-1');\n    assert.equal(stamped[3].itemcProp, 'prop-1-1-2');\n    assert.equal(stamped[3].indexa, 0);\n    assert.equal(stamped[3].indexb, 0);\n    assert.equal(stamped[3].indexc, 1);\n    assert.equal(stamped[3].$.bar.itemcProp, 'prop-1-1-2');\n    assert.equal(stamped[4].itemcProp, 'prop-1-1-3');\n    assert.equal(stamped[4].indexa, 0);\n    assert.equal(stamped[4].indexb, 0);\n    assert.equal(stamped[4].indexc, 2);\n    assert.equal(stamped[4].$.bar.itemcProp, 'prop-1-1-3');\n    assert.equal(stamped[13].itemaProp, 'prop-2');\n    assert.equal(stamped[13].indexa, 1);\n    assert.equal(stamped[13].$.bar.itemaProp, 'prop-2');\n    assert.equal(stamped[36].itemcProp, 'prop-3-3-1');\n    assert.equal(stamped[36].indexa, 2);\n    assert.equal(stamped[36].indexb, 2);\n    assert.equal(stamped[36].indexc, 0);\n    assert.equal(stamped[36].$.bar.itemcProp, 'prop-3-3-1');\n    assert.equal(stamped[37].itemcProp, 'prop-3-3-2');\n    assert.equal(stamped[37].indexa, 2);\n    assert.equal(stamped[37].indexb, 2);\n    assert.equal(stamped[37].indexc, 1);\n    assert.equal(stamped[37].$.bar.itemcProp, 'prop-3-3-2');\n    assert.equal(stamped[38].itemcProp, 'prop-3-3-3');\n    assert.equal(stamped[38].indexa, 2);\n    assert.equal(stamped[38].indexb, 2);\n    assert.equal(stamped[38].indexc, 2);\n    assert.equal(stamped[38].$.bar.itemcProp, 'prop-3-3-3');\n  });\n\n  test('parent scope binding', function() {\n    var stamped = configured.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped[0].outerProp, 'outer');\n    assert.equal(stamped[0].outerItemProp, 'outerItem');\n    assert.equal(stamped[1].itemaProp, 'prop-1');\n    assert.equal(stamped[1].indexa, 0);\n    assert.equal(stamped[1].outerProp, 'outer');\n    assert.equal(stamped[1].outerItemProp, 'outerItem');\n    assert.equal(stamped[2].itembProp, 'prop-1-1');\n    assert.equal(stamped[2].indexa, 0);\n    assert.equal(stamped[2].indexb, 0);\n    assert.equal(stamped[2].itemaProp, 'prop-1');\n    assert.equal(stamped[2].indexa, 0);\n    assert.equal(stamped[2].outerProp, 'outer');\n    assert.equal(stamped[2].outerItemProp, 'outerItem');\n    assert.equal(stamped[38].itembProp, 'prop-3-3');\n    assert.equal(stamped[38].indexa, 2);\n    assert.equal(stamped[38].indexb, 2);\n    assert.equal(stamped[38].itemaProp, 'prop-3');\n    assert.equal(stamped[38].indexa, 2);\n    assert.equal(stamped[38].outerProp, 'outer');\n    assert.equal(stamped[38].outerItemProp, 'outerItem');\n  });\n\n  test('parent scope downward notification', function() {\n    var stamped = configured.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    configured.prop = 'yes';\n    assert.equal(stamped[0].outerProp, 'yes');\n    assert.equal(stamped[1].outerProp, 'yes');\n    assert.equal(stamped[2].outerProp, 'yes');\n    assert.equal(stamped[38].outerProp, 'yes');\n    configured.set('item.prop', 'yay');\n    assert.equal(stamped[0].outerItemProp, 'yay');\n    assert.equal(stamped[1].outerItemProp, 'yay');\n    assert.equal(stamped[2].outerItemProp, 'yay');\n    assert.equal(stamped[38].outerItemProp, 'yay');\n  });\n\n  test('parent scope upward notification', function() {\n    var stamped = configured.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    stamped[38].outerProp = 'nice';\n    assert.equal(configured.prop, 'nice');\n    assert.equal(stamped[0].outerProp, 'nice');\n    assert.equal(stamped[1].outerProp, 'nice');\n    assert.equal(stamped[2].outerProp, 'nice');\n    assert.equal(stamped[37].outerProp, 'nice');\n    stamped[38].outerItemProp = 'cool';\n    assert.equal(configured.item.prop, 'cool');\n    assert.equal(stamped[0].outerItemProp, 'cool');\n    assert.equal(stamped[1].outerItemProp, 'cool');\n    assert.equal(stamped[2].outerItemProp, 'cool');\n    assert.equal(stamped[37].outerItemProp, 'cool');\n  });\n\n  // Anonymous inner scope feature removed for time being\n  // test('anonymous scope binding', function() {\n  //   var stamped = configured.root.querySelectorAll('*:not(template):not(dom-repeat)');\n  //   stamped[1].$.bar.inneraProp = 'changed';\n  //   assert.equal(stamped[1].inneraProp, 'changed');\n  //   assert.equal(stamped[2].inneraProp, 'changed');\n  //   assert.equal(stamped[3].inneraProp, 'changed');\n  //   assert.equal(stamped[4].inneraProp, 'changed');\n  // });\n\n  test('sort function by name on host', function() {\n    // set sort fn\n    configured.$.repeater.sort = 'sortDesc';\n    configured.$.repeater.render();\n    var stamped = configured.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n    assert.equal(stamped[0].itemaProp, 'prop-3');\n    assert.equal(stamped[0].indexa, 0);\n    assert.equal(stamped[13].itemaProp, 'prop-2');\n    assert.equal(stamped[13].indexa, 1);\n    assert.equal(stamped[26].itemaProp, 'prop-1');\n    assert.equal(stamped[26].indexa, 2);\n    // reset sort fn\n    configured.$.repeater.sort = null;\n    configured.$.repeater.render();\n    assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n    assert.equal(stamped[0].itemaProp, 'prop-1');\n    assert.equal(stamped[0].indexa, 0);\n    assert.equal(stamped[13].itemaProp, 'prop-2');\n    assert.equal(stamped[13].indexa, 1);\n    assert.equal(stamped[26].itemaProp, 'prop-3');\n    assert.equal(stamped[26].indexa, 2);\n  });\n\n  test('sort function imperative', function() {\n    // set sort fn\n    configured.$.repeater.sort = function(a, b) {\n      return b.prop.localeCompare(a.prop);\n    };\n    configured.$.repeater.render();\n    var stamped = configured.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n    assert.equal(stamped[0].itemaProp, 'prop-3');\n    assert.equal(stamped[0].indexa, 0);\n    assert.equal(stamped[13].itemaProp, 'prop-2');\n    assert.equal(stamped[13].indexa, 1);\n    assert.equal(stamped[26].itemaProp, 'prop-1');\n    assert.equal(stamped[26].indexa, 2);\n    // reset sort fn\n    configured.$.repeater.sort = null;\n    configured.$.repeater.render();\n    assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n    assert.equal(stamped[0].itemaProp, 'prop-1');\n    assert.equal(stamped[0].indexa, 0);\n    assert.equal(stamped[13].itemaProp, 'prop-2');\n    assert.equal(stamped[13].indexa, 1);\n    assert.equal(stamped[26].itemaProp, 'prop-3');\n    assert.equal(stamped[26].indexa, 2);\n  });\n\n  test('filter function by name on host', function() {\n    // set filter fn\n    configured.$.repeater.filter = 'filter2nd';\n    configured.$.repeater.render();\n    var stamped = configured.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n    assert.equal(configured.$.repeater.renderedItemCount, 2, 'rendered item count incorrect');\n    assert.equal(stamped[0].itemaProp, 'prop-1');\n    assert.equal(stamped[0].indexa, 0);\n    assert.equal(stamped[13].itemaProp, 'prop-3');\n    assert.equal(stamped[13].indexa, 1);\n    // reset filter fn\n    configured.$.repeater.filter = null;\n    configured.$.repeater.render();\n    stamped = configured.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n    assert.equal(stamped[0].itemaProp, 'prop-1');\n    assert.equal(stamped[0].indexa, 0);\n    assert.equal(stamped[13].itemaProp, 'prop-2');\n    assert.equal(stamped[13].indexa, 1);\n    assert.equal(stamped[26].itemaProp, 'prop-3');\n    assert.equal(stamped[26].indexa, 2);\n  });\n\n  test('filter function imperative', function() {\n    // set filter fn\n    configured.$.repeater.filter = function(o) {\n      return o.prop.indexOf('2') < 0;\n    };\n    configured.$.repeater.render();\n    var stamped = configured.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n    assert.equal(stamped[0].itemaProp, 'prop-1');\n    assert.equal(stamped[0].indexa, 0);\n    assert.equal(stamped[13].itemaProp, 'prop-3');\n    assert.equal(stamped[13].indexa, 1);\n    // reset filter fn\n    configured.$.repeater.filter = null;\n    configured.$.repeater.render();\n    stamped = configured.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n    assert.equal(stamped[0].itemaProp, 'prop-1');\n    assert.equal(stamped[0].indexa, 0);\n    assert.equal(stamped[13].itemaProp, 'prop-2');\n    assert.equal(stamped[13].indexa, 1);\n    assert.equal(stamped[26].itemaProp, 'prop-3');\n    assert.equal(stamped[26].indexa, 2);\n  });\n\n  test('sort and filter function by name on host', function() {\n    // set filter fn\n    configured.$.repeater.sort = 'sortDesc';\n    configured.$.repeater.filter = 'filter2nd';\n    configured.$.repeater.render();\n    var stamped = configured.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n    assert.equal(stamped[0].itemaProp, 'prop-3');\n    assert.equal(stamped[0].indexa, 0);\n    assert.equal(stamped[13].itemaProp, 'prop-1');\n    assert.equal(stamped[13].indexa, 1);\n    // reset filter fn\n    configured.$.repeater.sort = null;\n    configured.$.repeater.filter = null;\n    configured.$.repeater.render();\n    stamped = configured.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n    assert.equal(stamped[0].itemaProp, 'prop-1');\n    assert.equal(stamped[0].indexa, 0);\n    assert.equal(stamped[13].itemaProp, 'prop-2');\n    assert.equal(stamped[13].indexa, 1);\n    assert.equal(stamped[26].itemaProp, 'prop-3');\n    assert.equal(stamped[26].indexa, 2);\n  });\n\n  test('observe refreshes sort and filter', function(done) {\n    // set filter fn\n    configured.$.repeater.sort = 'sortDesc';\n    configured.$.repeater.filter = 'filter2nd';\n    configured.$.repeater.render();\n    var stamped = configured.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n    assert.equal(stamped[0].itemaProp, 'prop-3');\n    assert.equal(stamped[0].indexa, 0);\n    assert.equal(stamped[13].itemaProp, 'prop-1');\n    assert.equal(stamped[13].indexa, 1);\n\n    // Update observed prop to be in filter\n    configured.set(['items', 1, 'prop'], 'prop-0');\n    // avoid imperative/synchronous refresh() since that forces a full refresh\n    setTimeout(function() {\n      stamped = configured.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n      assert.equal(stamped[0].itemaProp, 'prop-3');\n      assert.equal(stamped[0].indexa, 0);\n      assert.equal(stamped[13].itemaProp, 'prop-1');\n      assert.equal(stamped[13].indexa, 1);\n      assert.equal(stamped[26].itemaProp, 'prop-0');\n      assert.equal(stamped[26].indexa, 2);\n\n      // Update observed prop back to be out of the filter\n      configured.set(['items', 1, 'prop'], 'prop-2');\n      setTimeout(function() {\n        var stamped = configured.root.querySelectorAll('*:not(template):not(dom-repeat)');\n        assert.equal(stamped.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n        assert.equal(stamped[0].itemaProp, 'prop-3');\n        assert.equal(stamped[0].indexa, 0);\n        assert.equal(stamped[13].itemaProp, 'prop-1');\n        assert.equal(stamped[13].indexa, 1);\n\n        // reset filter fn\n        configured.$.repeater.sort = null;\n        configured.$.repeater.filter = null;\n        configured.$.repeater.render();\n        stamped = configured.root.querySelectorAll('*:not(template):not(dom-repeat)');\n        assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n        assert.equal(stamped[0].itemaProp, 'prop-1');\n        assert.equal(stamped[0].indexa, 0);\n        assert.equal(stamped[13].itemaProp, 'prop-2');\n        assert.equal(stamped[13].indexa, 1);\n        assert.equal(stamped[26].itemaProp, 'prop-3');\n        assert.equal(stamped[26].indexa, 2);\n\n        done();\n      });\n    });\n  });\n\n  test('item change refreshes sort and filter', function(done) {\n    // set filter fn\n    configured.$.repeater.sort = 'sortDesc';\n    configured.$.repeater.filter = 'filter2nd';\n    configured.$.repeater.render();\n    var stamped = configured.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n    assert.equal(stamped[0].itemaProp, 'prop-3');\n    assert.equal(stamped[0].indexa, 0);\n    assert.equal(stamped[13].itemaProp, 'prop-1');\n    assert.equal(stamped[13].indexa, 1);\n\n    // Update observed prop to be in filter (set new object)\n    configured.set(['items', 1], Object.assign({}, configured.items[1], {prop: 'prop-0'}));\n    // avoid imperative/synchronous refresh() since that forces a full refresh\n    setTimeout(function() {\n      stamped = configured.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n      assert.equal(stamped[0].itemaProp, 'prop-3');\n      assert.equal(stamped[0].indexa, 0);\n      assert.equal(stamped[13].itemaProp, 'prop-1');\n      assert.equal(stamped[13].indexa, 1);\n      assert.equal(stamped[26].itemaProp, 'prop-0');\n      assert.equal(stamped[26].indexa, 2);\n\n      // Update observed prop back to be out of the filter (set new object)\n      configured.set(['items', 1], Object.assign({}, configured.items[1], {prop: 'prop-2'}));\n      setTimeout(function() {\n        var stamped = configured.root.querySelectorAll('*:not(template):not(dom-repeat)');\n        assert.equal(stamped.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n        assert.equal(stamped[0].itemaProp, 'prop-3');\n        assert.equal(stamped[0].indexa, 0);\n        assert.equal(stamped[13].itemaProp, 'prop-1');\n        assert.equal(stamped[13].indexa, 1);\n\n        // reset filter fn\n        configured.$.repeater.sort = null;\n        configured.$.repeater.filter = null;\n        configured.$.repeater.render();\n        stamped = configured.root.querySelectorAll('*:not(template):not(dom-repeat)');\n        assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n        assert.equal(stamped[0].itemaProp, 'prop-1');\n        assert.equal(stamped[0].indexa, 0);\n        assert.equal(stamped[13].itemaProp, 'prop-2');\n        assert.equal(stamped[13].indexa, 1);\n        assert.equal(stamped[26].itemaProp, 'prop-3');\n        assert.equal(stamped[26].indexa, 2);\n\n        done();\n      });\n    });\n  });\n});\n\nsuite('filter and sort by nested property', function () {\n  let fixtureInstance;\n\n  setup(function() {\n    fixtureInstance = fixture('filter-and-sort-by-nested-property');\n    flush();\n  });\n\n  test('change of item nested-property refreshes sort and filter', function(done) {\n    // Original values for `item.prop.nestedProp` are numbers 0 through 4\n    const repeater = fixtureInstance.$.repeater;\n    repeater.sort = (a, b) => b.prop.nestedProp - a.prop.nestedProp; // Desc order\n    repeater.filter = (a) => a.prop.nestedProp >= 1; // => Just 1 through 4\n    repeater.observe = 'prop.nestedProp';\n    repeater.render();\n\n    const stamped = fixtureInstance.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped.length, 4, 'total stamped count incorrect');\n    assert.equal(stamped[0].itemaProp, 4);\n    assert.equal(stamped[1].itemaProp, 3);\n    assert.equal(stamped[2].itemaProp, 2);\n    assert.equal(stamped[3].itemaProp, 1);\n\n    // Update observed nested prop\n    for (let i = 0; i < 5; i++) {\n      const x = fixtureInstance.get(['items', i, 'prop', 'nestedProp']);\n      fixtureInstance.set(['items', i, 'prop', 'nestedProp'], (x + 10) * 2);\n    }\n\n    // Wait for changes to be reflected to the DOM\n    setTimeout(function() {\n      const stamped = fixtureInstance.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 5, 'total stamped count incorrect');\n      assert.equal(stamped[0].itemaProp, 28);\n      assert.equal(stamped[1].itemaProp, 26);\n      assert.equal(stamped[2].itemaProp, 24);\n      assert.equal(stamped[3].itemaProp, 22);\n      assert.equal(stamped[4].itemaProp, 20);\n\n      done();\n    });\n  });\n});\n\nsuite('nested un-configured dom-repeat in document', function() {\n\n  test('basic rendering, downward item binding', function() {\n    inDocumentRepeater.items = window.getData();\n    inDocumentRepeater.render();\n    var stamped = inDocumentContainerOrig.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n    assert.equal(stamped[0].itemaProp, 'prop-1');\n    assert.equal(stamped[0].indexa, 0);\n    assert.equal(stamped[0].$.bar.itemaProp, 'prop-1');\n    assert.equal(stamped[1].itembProp, 'prop-1-1');\n    assert.equal(stamped[1].indexa, 0);\n    assert.equal(stamped[1].indexb, 0);\n    assert.equal(stamped[1].$.bar.itembProp, 'prop-1-1');\n    assert.equal(stamped[2].itemcProp, 'prop-1-1-1');\n    assert.equal(stamped[2].indexa, 0);\n    assert.equal(stamped[2].indexb, 0);\n    assert.equal(stamped[2].indexc, 0);\n    assert.equal(stamped[2].$.bar.itemcProp, 'prop-1-1-1');\n    assert.equal(stamped[3].itemcProp, 'prop-1-1-2');\n    assert.equal(stamped[3].indexa, 0);\n    assert.equal(stamped[3].indexb, 0);\n    assert.equal(stamped[3].indexc, 1);\n    assert.equal(stamped[3].$.bar.itemcProp, 'prop-1-1-2');\n    assert.equal(stamped[4].itemcProp, 'prop-1-1-3');\n    assert.equal(stamped[4].indexa, 0);\n    assert.equal(stamped[4].indexb, 0);\n    assert.equal(stamped[4].indexc, 2);\n    assert.equal(stamped[4].$.bar.itemcProp, 'prop-1-1-3');\n    assert.equal(stamped[13].itemaProp, 'prop-2');\n    assert.equal(stamped[13].indexa, 1);\n    assert.equal(stamped[13].$.bar.itemaProp, 'prop-2');\n    assert.equal(stamped[36].itemcProp, 'prop-3-3-1');\n    assert.equal(stamped[36].indexa, 2);\n    assert.equal(stamped[36].indexb, 2);\n    assert.equal(stamped[36].indexc, 0);\n    assert.equal(stamped[36].$.bar.itemcProp, 'prop-3-3-1');\n    assert.equal(stamped[37].itemcProp, 'prop-3-3-2');\n    assert.equal(stamped[37].indexa, 2);\n    assert.equal(stamped[37].indexb, 2);\n    assert.equal(stamped[37].indexc, 1);\n    assert.equal(stamped[37].$.bar.itemcProp, 'prop-3-3-2');\n    assert.equal(stamped[38].itemcProp, 'prop-3-3-3');\n    assert.equal(stamped[38].indexa, 2);\n    assert.equal(stamped[38].indexb, 2);\n    assert.equal(stamped[38].indexc, 2);\n    assert.equal(stamped[38].$.bar.itemcProp, 'prop-3-3-3');\n  });\n\n  test('move to different container', function() {\n    var repeater = inDocumentRepeater;\n    inDocumentContainer.appendChild(repeater);\n    var stamped = inDocumentContainer.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n    assert.equal(stamped[0].itemaProp, 'prop-1');\n    assert.equal(stamped[0].indexa, 0);\n    assert.equal(stamped[0].$.bar.itemaProp, 'prop-1');\n    assert.equal(stamped[1].itembProp, 'prop-1-1');\n    assert.equal(stamped[1].indexa, 0);\n    assert.equal(stamped[1].indexb, 0);\n    assert.equal(stamped[1].$.bar.itembProp, 'prop-1-1');\n    assert.equal(stamped[2].itemcProp, 'prop-1-1-1');\n    assert.equal(stamped[2].indexa, 0);\n    assert.equal(stamped[2].indexb, 0);\n    assert.equal(stamped[2].indexc, 0);\n    assert.equal(stamped[2].$.bar.itemcProp, 'prop-1-1-1');\n    assert.equal(stamped[3].itemcProp, 'prop-1-1-2');\n    assert.equal(stamped[3].indexa, 0);\n    assert.equal(stamped[3].indexb, 0);\n    assert.equal(stamped[3].indexc, 1);\n    assert.equal(stamped[3].$.bar.itemcProp, 'prop-1-1-2');\n    assert.equal(stamped[4].itemcProp, 'prop-1-1-3');\n    assert.equal(stamped[4].indexa, 0);\n    assert.equal(stamped[4].indexb, 0);\n    assert.equal(stamped[4].indexc, 2);\n    assert.equal(stamped[4].$.bar.itemcProp, 'prop-1-1-3');\n    assert.equal(stamped[13].itemaProp, 'prop-2');\n    assert.equal(stamped[13].indexa, 1);\n    assert.equal(stamped[13].$.bar.itemaProp, 'prop-2');\n    assert.equal(stamped[36].itemcProp, 'prop-3-3-1');\n    assert.equal(stamped[36].indexa, 2);\n    assert.equal(stamped[36].indexb, 2);\n    assert.equal(stamped[36].indexc, 0);\n    assert.equal(stamped[36].$.bar.itemcProp, 'prop-3-3-1');\n    assert.equal(stamped[37].itemcProp, 'prop-3-3-2');\n    assert.equal(stamped[37].indexa, 2);\n    assert.equal(stamped[37].indexb, 2);\n    assert.equal(stamped[37].indexc, 1);\n    assert.equal(stamped[37].$.bar.itemcProp, 'prop-3-3-2');\n    assert.equal(stamped[38].itemcProp, 'prop-3-3-3');\n    assert.equal(stamped[38].indexa, 2);\n    assert.equal(stamped[38].indexb, 2);\n    assert.equal(stamped[38].indexc, 2);\n    assert.equal(stamped[38].$.bar.itemcProp, 'prop-3-3-3');\n  });\n\n  test('basic rendering, downward item binding', function() {\n    var r = inDocumentRepeater;\n    r.parentElement.removeChild(r);\n    inDocumentContainer.appendChild(r);\n\n    var stamped = inDocumentContainer.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n    assert.equal(stamped[0].itemaProp, 'prop-1');\n    assert.equal(stamped[0].indexa, 0);\n    assert.equal(stamped[0].$.bar.itemaProp, 'prop-1');\n    assert.equal(stamped[1].itembProp, 'prop-1-1');\n    assert.equal(stamped[1].indexa, 0);\n    assert.equal(stamped[1].indexb, 0);\n    assert.equal(stamped[1].$.bar.itembProp, 'prop-1-1');\n    assert.equal(stamped[2].itemcProp, 'prop-1-1-1');\n    assert.equal(stamped[2].indexa, 0);\n    assert.equal(stamped[2].indexb, 0);\n    assert.equal(stamped[2].indexc, 0);\n    assert.equal(stamped[2].$.bar.itemcProp, 'prop-1-1-1');\n    assert.equal(stamped[3].itemcProp, 'prop-1-1-2');\n    assert.equal(stamped[3].indexa, 0);\n    assert.equal(stamped[3].indexb, 0);\n    assert.equal(stamped[3].indexc, 1);\n    assert.equal(stamped[3].$.bar.itemcProp, 'prop-1-1-2');\n    assert.equal(stamped[4].itemcProp, 'prop-1-1-3');\n    assert.equal(stamped[4].indexa, 0);\n    assert.equal(stamped[4].indexb, 0);\n    assert.equal(stamped[4].indexc, 2);\n    assert.equal(stamped[4].$.bar.itemcProp, 'prop-1-1-3');\n    assert.equal(stamped[13].itemaProp, 'prop-2');\n    assert.equal(stamped[13].indexa, 1);\n    assert.equal(stamped[13].$.bar.itemaProp, 'prop-2');\n    assert.equal(stamped[36].itemcProp, 'prop-3-3-1');\n    assert.equal(stamped[36].indexa, 2);\n    assert.equal(stamped[36].indexb, 2);\n    assert.equal(stamped[36].indexc, 0);\n    assert.equal(stamped[36].$.bar.itemcProp, 'prop-3-3-1');\n    assert.equal(stamped[37].itemcProp, 'prop-3-3-2');\n    assert.equal(stamped[37].indexa, 2);\n    assert.equal(stamped[37].indexb, 2);\n    assert.equal(stamped[37].indexc, 1);\n    assert.equal(stamped[37].$.bar.itemcProp, 'prop-3-3-2');\n    assert.equal(stamped[38].itemcProp, 'prop-3-3-3');\n    assert.equal(stamped[38].indexa, 2);\n    assert.equal(stamped[38].indexb, 2);\n    assert.equal(stamped[38].indexc, 2);\n    assert.equal(stamped[38].$.bar.itemcProp, 'prop-3-3-3');\n  });\n\n  test('parent scope binding', function() {\n    var stamped = inDocumentContainer.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped[1].itemaProp, 'prop-1');\n    assert.equal(stamped[1].indexa, 0);\n    assert.equal(stamped[2].itembProp, 'prop-1-1');\n    assert.equal(stamped[2].indexa, 0);\n    assert.equal(stamped[2].indexb, 0);\n    assert.equal(stamped[2].itemaProp, 'prop-1');\n    assert.equal(stamped[2].indexa, 0);\n    assert.equal(stamped[38].itembProp, 'prop-3-3');\n    assert.equal(stamped[38].indexa, 2);\n    assert.equal(stamped[38].indexb, 2);\n    assert.equal(stamped[38].itemaProp, 'prop-3');\n    assert.equal(stamped[38].indexa, 2);\n  });\n\n  // Anonymous inner scope feature removed for time being\n  // test('anonymous scope binding', function() {\n  //   var stamped = inDocumentContainer.querySelectorAll('*:not(template):not(dom-repeat)');\n  //   stamped[1].$.bar.inneraProp = 'changed';\n  //   assert.equal(stamped[1].inneraProp, 'changed');\n  //   assert.equal(stamped[2].inneraProp, 'changed');\n  //   assert.equal(stamped[3].inneraProp, 'changed');\n  //   assert.equal(stamped[4].inneraProp, 'changed');\n  // });\n\n});\n\nsuite('nested un-configured dom-repeat', function() {\n\n  let unconfigured;\n\n  setup(function() {\n    unconfigured = fixture('unconfigured');\n    unconfigured.items = window.getData();\n    unconfigured.$.el1.prop = 'outer';\n    unconfigured.$.el1.item = {prop: 'outerItem'};\n    flush();\n  });\n\n  test('basic rendering, downward item binding', function() {\n    var stamped = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n    assert.equal(stamped[0].itemaProp, 'prop-1');\n    assert.equal(stamped[0].indexa, 0);\n    assert.equal(stamped[0].$.bar.itemaProp, 'prop-1');\n    assert.equal(stamped[1].itembProp, 'prop-1-1');\n    assert.equal(stamped[1].indexa, 0);\n    assert.equal(stamped[1].indexb, 0);\n    assert.equal(stamped[1].$.bar.itembProp, 'prop-1-1');\n    assert.equal(stamped[2].itemcProp, 'prop-1-1-1');\n    assert.equal(stamped[2].indexa, 0);\n    assert.equal(stamped[2].indexb, 0);\n    assert.equal(stamped[2].indexc, 0);\n    assert.equal(stamped[2].$.bar.itemcProp, 'prop-1-1-1');\n    assert.equal(stamped[3].itemcProp, 'prop-1-1-2');\n    assert.equal(stamped[3].indexa, 0);\n    assert.equal(stamped[3].indexb, 0);\n    assert.equal(stamped[3].indexc, 1);\n    assert.equal(stamped[3].$.bar.itemcProp, 'prop-1-1-2');\n    assert.equal(stamped[4].itemcProp, 'prop-1-1-3');\n    assert.equal(stamped[4].indexa, 0);\n    assert.equal(stamped[4].indexb, 0);\n    assert.equal(stamped[4].indexc, 2);\n    assert.equal(stamped[4].$.bar.itemcProp, 'prop-1-1-3');\n    assert.equal(stamped[13].itemaProp, 'prop-2');\n    assert.equal(stamped[13].indexa, 1);\n    assert.equal(stamped[13].$.bar.itemaProp, 'prop-2');\n    assert.equal(stamped[36].itemcProp, 'prop-3-3-1');\n    assert.equal(stamped[36].indexa, 2);\n    assert.equal(stamped[36].indexb, 2);\n    assert.equal(stamped[36].indexc, 0);\n    assert.equal(stamped[36].$.bar.itemcProp, 'prop-3-3-1');\n    assert.equal(stamped[37].itemcProp, 'prop-3-3-2');\n    assert.equal(stamped[37].indexa, 2);\n    assert.equal(stamped[37].indexb, 2);\n    assert.equal(stamped[37].indexc, 1);\n    assert.equal(stamped[37].$.bar.itemcProp, 'prop-3-3-2');\n    assert.equal(stamped[38].itemcProp, 'prop-3-3-3');\n    assert.equal(stamped[38].indexa, 2);\n    assert.equal(stamped[38].indexb, 2);\n    assert.equal(stamped[38].indexc, 2);\n    assert.equal(stamped[38].$.bar.itemcProp, 'prop-3-3-3');\n  });\n\n  test('parent scope binding', function() {\n    var stamped = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped[0].outerProp, 'outer');\n    assert.equal(stamped[0].outerItemProp, 'outerItem');\n    assert.equal(stamped[1].itemaProp, 'prop-1');\n    assert.equal(stamped[1].indexa, 0);\n    assert.equal(stamped[1].outerProp, 'outer');\n    assert.equal(stamped[1].outerItemProp, 'outerItem');\n    assert.equal(stamped[2].itembProp, 'prop-1-1');\n    assert.equal(stamped[2].indexa, 0);\n    assert.equal(stamped[2].indexb, 0);\n    assert.equal(stamped[2].itemaProp, 'prop-1');\n    assert.equal(stamped[2].indexa, 0);\n    assert.equal(stamped[2].outerProp, 'outer');\n    assert.equal(stamped[2].outerItemProp, 'outerItem');\n    assert.equal(stamped[38].itembProp, 'prop-3-3');\n    assert.equal(stamped[38].indexa, 2);\n    assert.equal(stamped[38].indexb, 2);\n    assert.equal(stamped[38].itemaProp, 'prop-3');\n    assert.equal(stamped[38].indexa, 2);\n    assert.equal(stamped[38].outerProp, 'outer');\n    assert.equal(stamped[38].outerItemProp, 'outerItem');\n  });\n\n  test('parent scope downward notification', function() {\n    var stamped = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    unconfigured.$.el1.prop = 'yes';\n    assert.equal(stamped[0].outerProp, 'yes');\n    assert.equal(stamped[1].outerProp, 'yes');\n    assert.equal(stamped[2].outerProp, 'yes');\n    assert.equal(stamped[38].outerProp, 'yes');\n    unconfigured.$.el1.set('item.prop', 'yay');\n    assert.equal(stamped[0].outerItemProp, 'yay');\n    assert.equal(stamped[1].outerItemProp, 'yay');\n    assert.equal(stamped[2].outerItemProp, 'yay');\n    assert.equal(stamped[38].outerItemProp, 'yay');\n  });\n\n  test('parent scope upward notification', function() {\n    var stamped = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    stamped[38].outerProp = 'nice';\n    assert.equal(unconfigured.$.el1.prop, 'nice');\n    assert.equal(stamped[0].outerProp, 'nice');\n    assert.equal(stamped[1].outerProp, 'nice');\n    assert.equal(stamped[2].outerProp, 'nice');\n    assert.equal(stamped[37].outerProp, 'nice');\n    stamped[38].outerItemProp = 'cool';\n    assert.equal(unconfigured.$.el1.item.prop, 'cool');\n    assert.equal(stamped[0].outerItemProp, 'cool');\n    assert.equal(stamped[1].outerItemProp, 'cool');\n    assert.equal(stamped[2].outerItemProp, 'cool');\n    assert.equal(stamped[37].outerItemProp, 'cool');\n  });\n\n  // Anonymous inner scope feature removed for time being\n  // test('anonymous scope binding', function() {\n  //   var stamped = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n  //   stamped[1].$.bar.inneraProp = 'changed';\n  //   assert.equal(stamped[1].inneraProp, 'changed');\n  //   assert.equal(stamped[2].inneraProp, 'changed');\n  //   assert.equal(stamped[3].inneraProp, 'changed');\n  //   assert.equal(stamped[4].inneraProp, 'changed');\n  // });\n\n  test('event handlers', function() {\n    var stamped = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    stamped[0].fire('test1');\n    assert.equal(unconfigured.$.el1.testHandler1Count, 1);\n    stamped[1].fire('test2');\n    assert.equal(unconfigured.$.el1.testHandler2Count, 1);\n    stamped[2].fire('test3');\n    assert.equal(unconfigured.$.el1.testHandler3Count, 1);\n  });\n\n});\n\nsuite('array notification between two dom-repeats', function() {\n\n  let unconfigured;\n\n  setup(function() {\n    unconfigured = fixture('unconfigured');\n    unconfigured.items = window.getData();\n    flush();\n  });\n\n  test('change to item from one dom-repeat to other', function() {\n    var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    var stamped2 = unconfigured.$.el2.root.querySelectorAll('*:not(template):not(dom-repeat)');\n\n    assert.equal(stamped1[0].itemaProp, 'prop-1');\n    assert.equal(stamped1[0].indexa, 0);\n    assert.equal(stamped2[0].itemaProp, 'prop-1');\n    assert.equal(stamped2[0].indexa, 0);\n    stamped1[0].$.bar.itemaProp = 'changed';\n    assert.equal(stamped2[0].itemaProp, 'changed');\n    stamped2[0].$.bar.itemaProp = 'prop-1';\n    assert.equal(stamped1[0].itemaProp, 'prop-1');\n    assert.equal(stamped1[0].indexa, 0);\n\n    assert.equal(stamped1[1].itembProp, 'prop-1-1');\n    assert.equal(stamped1[1].indexa, 0);\n    assert.equal(stamped1[1].indexb, 0);\n    assert.equal(stamped2[1].itembProp, 'prop-1-1');\n    assert.equal(stamped2[1].indexa, 0);\n    assert.equal(stamped2[1].indexb, 0);\n    stamped1[1].$.bar.itembProp = 'changed';\n    assert.equal(stamped2[1].itembProp, 'changed');\n    stamped2[1].$.bar.itembProp = 'prop-1-1';\n    assert.equal(stamped1[1].itembProp, 'prop-1-1');\n    assert.equal(stamped1[1].indexa, 0);\n    assert.equal(stamped1[1].indexb, 0);\n\n    assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');\n    assert.equal(stamped1[2].indexa, 0);\n    assert.equal(stamped1[2].indexb, 0);\n    assert.equal(stamped1[2].indexc, 0);\n    assert.equal(stamped2[2].itemcProp, 'prop-1-1-1');\n    assert.equal(stamped2[2].indexa, 0);\n    assert.equal(stamped2[2].indexb, 0);\n    assert.equal(stamped2[2].indexc, 0);\n    stamped1[2].$.bar.itemcProp = 'changed';\n    assert.equal(stamped2[2].itemcProp, 'changed');\n    stamped2[2].$.bar.itemcProp = 'prop-1-1-1';\n    assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');\n    assert.equal(stamped1[2].indexa, 0);\n    assert.equal(stamped1[2].indexb, 0);\n    assert.equal(stamped1[2].indexc, 0);\n\n    assert.equal(stamped1[38].itemcProp, 'prop-3-3-3');\n    assert.equal(stamped1[38].indexa, 2);\n    assert.equal(stamped1[38].indexb, 2);\n    assert.equal(stamped1[38].indexc, 2);\n    assert.equal(stamped2[38].itemcProp, 'prop-3-3-3');\n    assert.equal(stamped2[38].indexa, 2);\n    assert.equal(stamped2[38].indexb, 2);\n    assert.equal(stamped2[38].indexc, 2);\n    stamped1[38].$.bar.itemcProp = 'changed';\n    assert.equal(stamped2[38].itemcProp, 'changed');\n    stamped2[38].$.bar.itemcProp = 'prop-3-3-3';\n    assert.equal(stamped1[38].itemcProp, 'prop-3-3-3');\n    assert.equal(stamped1[38].indexa, 2);\n    assert.equal(stamped1[38].indexb, 2);\n    assert.equal(stamped1[38].indexc, 2);\n  });\n\n  test('change to non-item scope doesn\\'t affect other dom-repeat', function() {\n    var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    var stamped2 = unconfigured.$.el2.root.querySelectorAll('*:not(template):not(dom-repeat)');\n\n    unconfigured.$.el1.prop = 'foo';\n    unconfigured.$.el2.prop = 'bar';\n    assert.equal(stamped1[0].outerProp, 'foo');\n    assert.equal(stamped1[1].outerProp, 'foo');\n    assert.equal(stamped1[2].outerProp, 'foo');\n    assert.equal(stamped2[0].outerProp, 'bar');\n    assert.equal(stamped2[1].outerProp, 'bar');\n    assert.equal(stamped2[2].outerProp, 'bar');\n\n    stamped1[1].$.bar.inneraProp = 'bar';\n  });\n\n});\n\nsuite('reacting to changes, array sort', function() {\n\n  let unconfigured;\n\n  setup(function() {\n    unconfigured = fixture('unconfigured');\n    unconfigured.items = window.getData();\n    flush();\n    unconfigured.$.el1.domUpdateHandlerCount = 0;\n  });\n\n  test('push', function(done) {\n    unconfigured.push('items', {prop: 'new-1'}, {prop: 'new-2'});\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      var stamped2 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n      assert.equal(stamped2.length, 2 + 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[38].itemcProp, 'prop-3-3-3');\n      assert.equal(stamped1[38].indexa, 2);\n      assert.equal(stamped1[38].indexb, 2);\n      assert.equal(stamped1[38].indexc, 2);\n      assert.equal(stamped1[39].itemaProp, 'new-1');\n      assert.equal(stamped1[40].itemaProp, 'new-2');\n      assert.equal(stamped1[41], undefined);\n      assert.equal(stamped2[38].itemcProp, 'prop-3-3-3');\n      assert.equal(stamped2[38].indexa, 2);\n      assert.equal(stamped2[38].indexb, 2);\n      assert.equal(stamped2[38].indexc, 2);\n      assert.equal(stamped2[39].itemaProp, 'new-1');\n      assert.equal(stamped2[40].itemaProp, 'new-2');\n      assert.equal(stamped2[41], undefined);\n      assert.equal(unconfigured.$.el1.domUpdateHandlerCount, 1);\n      done();\n    });\n  });\n\n  test('pop', function(done) {\n    unconfigured.pop('items');\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      var stamped2 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped2.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[25].itemcProp, 'prop-2-3-3');\n      assert.equal(stamped1[25].indexa, 1);\n      assert.equal(stamped1[25].indexb, 2);\n      assert.equal(stamped1[25].indexc, 2);\n      assert.equal(stamped1[26], undefined);\n      assert.equal(stamped2[25].itemcProp, 'prop-2-3-3');\n      assert.equal(stamped2[25].indexa, 1);\n      assert.equal(stamped2[25].indexb, 2);\n      assert.equal(stamped2[25].indexc, 2);\n      assert.equal(stamped2[26], undefined);\n      done();\n    });\n  });\n\n  test('unshift', function(done) {\n    unconfigured.unshift('items', {prop: 'new-1'}, {prop: 'new-2'});\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      var stamped2 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n      assert.equal(stamped2.length, 2 + 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'new-1');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itemaProp, 'new-2');\n      assert.equal(stamped1[1].indexa, 1);\n      assert.equal(stamped1[2].itemaProp, 'prop-1');\n      assert.equal(stamped1[2].indexa, 2);\n      assert.equal(stamped2[0].itemaProp, 'new-1');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped2[1].itemaProp, 'new-2');\n      assert.equal(stamped1[1].indexa, 1);\n      assert.equal(stamped2[2].itemaProp, 'prop-1');\n      assert.equal(stamped2[2].indexa, 2);\n      done();\n    });\n  });\n\n  test('shift', function(done) {\n    unconfigured.shift('items');\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      var stamped2 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped2.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-2');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-2-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-2-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped2[0].itemaProp, 'prop-2');\n      assert.equal(stamped2[0].indexa, 0);\n      assert.equal(stamped2[1].itembProp, 'prop-2-1');\n      assert.equal(stamped2[1].indexa, 0);\n      assert.equal(stamped2[1].indexb, 0);\n      assert.equal(stamped2[2].itemcProp, 'prop-2-1-1');\n      assert.equal(stamped2[2].indexa, 0);\n      assert.equal(stamped2[2].indexb, 0);\n      assert.equal(stamped2[2].indexc, 0);\n      done();\n    });\n  });\n\n  test('splice - remove from middle', function(done) {\n    unconfigured.splice('items', 1, 1)[0];\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      var stamped2 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped2.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-1');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-1-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[13].itemaProp, 'prop-3');\n      assert.equal(stamped1[13].indexa, 1);\n      assert.equal(stamped1[14].itembProp, 'prop-3-1');\n      assert.equal(stamped1[14].indexa, 1);\n      assert.equal(stamped1[14].indexb, 0);\n      assert.equal(stamped1[15].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped1[15].indexa, 1);\n      assert.equal(stamped1[15].indexb, 0);\n      assert.equal(stamped1[15].indexc, 0);\n      assert.equal(stamped2[0].itemaProp, 'prop-1');\n      assert.equal(stamped2[0].indexa, 0);\n      assert.equal(stamped2[1].itembProp, 'prop-1-1');\n      assert.equal(stamped2[1].indexa, 0);\n      assert.equal(stamped2[1].indexb, 0);\n      assert.equal(stamped2[2].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped2[2].indexa, 0);\n      assert.equal(stamped2[2].indexb, 0);\n      assert.equal(stamped2[2].indexc, 0);\n      assert.equal(stamped2[13].itemaProp, 'prop-3');\n      assert.equal(stamped2[13].indexa, 1);\n      assert.equal(stamped2[14].itembProp, 'prop-3-1');\n      assert.equal(stamped2[14].indexa, 1);\n      assert.equal(stamped2[14].indexb, 0);\n      assert.equal(stamped2[15].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped2[15].indexa, 1);\n      assert.equal(stamped2[15].indexb, 0);\n      assert.equal(stamped2[15].indexc, 0);\n      done();\n    });\n  });\n\n  test('splice - add to middle', function(done) {\n    unconfigured.splice('items', 1, 0, {prop: 'new-1'}, {prop: 'new-2'});\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      var stamped2 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n      assert.equal(stamped2.length, 2 + 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-1');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-1-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[13].itemaProp, 'new-1');\n      assert.equal(stamped1[13].indexa, 1);\n      assert.equal(stamped1[14].itemaProp, 'new-2');\n      assert.equal(stamped1[14].indexa, 2);\n      assert.equal(stamped1[15].itemaProp, 'prop-2');\n      assert.equal(stamped1[15].indexa, 3);\n      assert.equal(stamped1[16].itembProp, 'prop-2-1');\n      assert.equal(stamped1[16].indexa, 3);\n      assert.equal(stamped1[16].indexb, 0);\n      assert.equal(stamped1[17].itemcProp, 'prop-2-1-1');\n      assert.equal(stamped1[17].indexa, 3);\n      assert.equal(stamped1[17].indexb, 0);\n      assert.equal(stamped1[17].indexc, 0);\n      assert.equal(stamped2[0].itemaProp, 'prop-1');\n      assert.equal(stamped2[0].indexa, 0);\n      assert.equal(stamped2[1].itembProp, 'prop-1-1');\n      assert.equal(stamped2[1].indexa, 0);\n      assert.equal(stamped2[1].indexb, 0);\n      assert.equal(stamped2[2].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped2[2].indexa, 0);\n      assert.equal(stamped2[2].indexb, 0);\n      assert.equal(stamped2[2].indexc, 0);\n      assert.equal(stamped2[13].itemaProp, 'new-1');\n      assert.equal(stamped2[13].indexa, 1);\n      assert.equal(stamped2[14].itemaProp, 'new-2');\n      assert.equal(stamped2[14].indexa, 2);\n      assert.equal(stamped2[15].itemaProp, 'prop-2');\n      assert.equal(stamped2[15].indexa, 3);\n      assert.equal(stamped2[16].itembProp, 'prop-2-1');\n      assert.equal(stamped2[16].indexa, 3);\n      assert.equal(stamped2[16].indexb, 0);\n      assert.equal(stamped2[17].itemcProp, 'prop-2-1-1');\n      assert.equal(stamped2[17].indexa, 3);\n      assert.equal(stamped2[17].indexb, 0);\n      assert.equal(stamped2[17].indexc, 0);\n      done();\n    });\n  });\n\n  test('splice - replace in middle', function(done) {\n    unconfigured.splice('items', 1, 2, {prop: 'new-1'}, {prop: 'new-2'});\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      var stamped2 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 1 + 1*3 + 1*3*3, 'total stamped count incorrect');\n      assert.equal(stamped2.length, 2 + 1 + 1*3 + 1*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-1');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-1-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[13].itemaProp, 'new-1');\n      assert.equal(stamped1[13].indexa, 1);\n      assert.equal(stamped1[14].itemaProp, 'new-2');\n      assert.equal(stamped1[14].indexa, 2);\n      assert.equal(stamped1[15], undefined);\n      assert.equal(stamped2[0].itemaProp, 'prop-1');\n      assert.equal(stamped2[0].indexa, 0);\n      assert.equal(stamped2[1].itembProp, 'prop-1-1');\n      assert.equal(stamped2[1].indexa, 0);\n      assert.equal(stamped2[1].indexb, 0);\n      assert.equal(stamped2[2].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped2[2].indexa, 0);\n      assert.equal(stamped2[2].indexb, 0);\n      assert.equal(stamped2[2].indexc, 0);\n      assert.equal(stamped2[13].itemaProp, 'new-1');\n      assert.equal(stamped2[13].indexa, 1);\n      assert.equal(stamped2[14].itemaProp, 'new-2');\n      assert.equal(stamped2[14].indexa, 2);\n      assert.equal(stamped2[15], undefined);\n      done();\n    });\n  });\n\n});\n\nsuite('reacting to changes, array sort with filter', function() {\n\n  let unconfigured;\n\n  setup(function() {\n    unconfigured = fixture('unconfigured');\n    unconfigured.items = window.getData();\n    unconfigured.$.el1.$.repeater.filter = function(o) {\n      return o.prop.indexOf('2') < 0;\n    };\n    flush();\n  });\n\n  test('push', function(done) {\n    unconfigured.push('items', {prop: 'new-1'}, {prop: 'new-2'});\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 1 + 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-1');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-1-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[23].itemcProp, 'prop-3-3-1');\n      assert.equal(stamped1[23].indexa, 1);\n      assert.equal(stamped1[23].indexb, 2);\n      assert.equal(stamped1[23].indexc, 0);\n      assert.equal(stamped1[24].itemcProp, 'prop-3-3-2');\n      assert.equal(stamped1[24].indexa, 1);\n      assert.equal(stamped1[24].indexb, 2);\n      assert.equal(stamped1[24].indexc, 1);\n      assert.equal(stamped1[25].itemcProp, 'prop-3-3-3');\n      assert.equal(stamped1[25].indexa, 1);\n      assert.equal(stamped1[25].indexb, 2);\n      assert.equal(stamped1[25].indexc, 2);\n      assert.equal(stamped1[26].itemaProp, 'new-1');\n      assert.equal(stamped1[26].indexa, 2);\n      assert.equal(stamped1[27], undefined);\n      done();\n    });\n  });\n\n  test('pop', function(done) {\n    unconfigured.pop('items');\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 1 + 1*3 + 1*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-1');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-1-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[10].itemcProp, 'prop-1-3-1');\n      assert.equal(stamped1[10].indexa, 0);\n      assert.equal(stamped1[10].indexb, 2);\n      assert.equal(stamped1[10].indexc, 0);\n      assert.equal(stamped1[11].itemcProp, 'prop-1-3-2');\n      assert.equal(stamped1[11].indexa, 0);\n      assert.equal(stamped1[11].indexb, 2);\n      assert.equal(stamped1[11].indexc, 1);\n      assert.equal(stamped1[12].itemcProp, 'prop-1-3-3');\n      assert.equal(stamped1[12].indexa, 0);\n      assert.equal(stamped1[12].indexb, 2);\n      assert.equal(stamped1[12].indexc, 2);\n      assert.equal(stamped1[13], undefined);\n      done();\n    });\n  });\n\n  test('unshift', function(done) {\n    unconfigured.unshift('items', {prop: 'new-1'}, {prop: 'new-2'});\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 1 + 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'new-1');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itemaProp, 'prop-1');\n      assert.equal(stamped1[1].indexa, 1);\n      assert.equal(stamped1[2].itembProp, 'prop-1-1');\n      assert.equal(stamped1[2].indexa, 1);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[3].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[3].indexa, 1);\n      assert.equal(stamped1[3].indexb, 0);\n      assert.equal(stamped1[3].indexc, 0);\n      done();\n    });\n  });\n\n  test('shift', function(done) {\n    unconfigured.shift('items');\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 1 + 1*3 + 1*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-3');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-3-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[10].itemcProp, 'prop-3-3-1');\n      assert.equal(stamped1[10].indexa, 0);\n      assert.equal(stamped1[10].indexb, 2);\n      assert.equal(stamped1[10].indexc, 0);\n      assert.equal(stamped1[11].itemcProp, 'prop-3-3-2');\n      assert.equal(stamped1[11].indexa, 0);\n      assert.equal(stamped1[11].indexb, 2);\n      assert.equal(stamped1[11].indexc, 1);\n      assert.equal(stamped1[12].itemcProp, 'prop-3-3-3');\n      assert.equal(stamped1[12].indexa, 0);\n      assert.equal(stamped1[12].indexb, 2);\n      assert.equal(stamped1[12].indexc, 2);\n      assert.equal(stamped1[13], undefined);\n      done();\n    });\n  });\n\n  test('splice - remove from middle', function(done) {\n    unconfigured.splice('items', 1, 1)[0];\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-1');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-1-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[23].itemcProp, 'prop-3-3-1');\n      assert.equal(stamped1[23].indexa, 1);\n      assert.equal(stamped1[23].indexb, 2);\n      assert.equal(stamped1[23].indexc, 0);\n      assert.equal(stamped1[24].itemcProp, 'prop-3-3-2');\n      assert.equal(stamped1[24].indexa, 1);\n      assert.equal(stamped1[24].indexb, 2);\n      assert.equal(stamped1[24].indexc, 1);\n      assert.equal(stamped1[25].itemcProp, 'prop-3-3-3');\n      assert.equal(stamped1[25].indexa, 1);\n      assert.equal(stamped1[25].indexb, 2);\n      assert.equal(stamped1[25].indexc, 2);\n      assert.equal(stamped1[26], undefined);\n      done();\n    });\n  });\n\n  test('splice - add to middle', function(done) {\n    unconfigured.splice('items', 1, 0, {prop: 'new-1'}, {prop: 'new-2'});\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 1 + 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-1');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-1-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[13].itemaProp, 'new-1');\n      assert.equal(stamped1[13].indexa, 1);\n      assert.equal(stamped1[14].itemaProp, 'prop-3');\n      assert.equal(stamped1[14].indexa, 2);\n      assert.equal(stamped1[15].itembProp, 'prop-3-1');\n      assert.equal(stamped1[15].indexa, 2);\n      assert.equal(stamped1[15].indexb, 0);\n      assert.equal(stamped1[16].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped1[16].indexa, 2);\n      assert.equal(stamped1[16].indexb, 0);\n      assert.equal(stamped1[16].indexc, 0);\n      done();\n    });\n  });\n\n  test('splice - replace in middle', function(done) {\n    unconfigured.splice('items', 1, 2, {prop: 'new-1'}, {prop: 'new-2'});\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 1 + 1 + 1*3 + 1*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-1');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-1-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[13].itemaProp, 'new-1');\n      assert.equal(stamped1[14], undefined);\n      done();\n    });\n  });\n\n});\n\nsuite('reacting to changes, view sort', function() {\n\n  let unconfigured;\n\n  setup(function() {\n    unconfigured = fixture('unconfigured');\n    unconfigured.items = window.getData();\n    unconfigured.$.el1.$.repeater.sort = function(a, b) {\n      return b.prop == a.prop ? 0 : b.prop < a.prop ? -1 : 1;\n    };\n    flush();\n  });\n\n  test('push', function(done) {\n    unconfigured.push('items', {prop: 'a'}, {prop: 'prop-1*'}, {prop: 'z'});\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 3 + 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'z');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itemaProp, 'prop-3');\n      assert.equal(stamped1[1].indexa, 1);\n      assert.equal(stamped1[2].itembProp, 'prop-3-1');\n      assert.equal(stamped1[2].indexa, 1);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[3].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped1[3].indexa, 1);\n      assert.equal(stamped1[3].indexb, 0);\n      assert.equal(stamped1[3].indexc, 0);\n      assert.equal(stamped1[27].itemaProp, 'prop-1*');\n      assert.equal(stamped1[27].indexa, 3);\n      assert.equal(stamped1[40].itemcProp, 'prop-1-3-3');\n      assert.equal(stamped1[40].indexa, 4);\n      assert.equal(stamped1[40].indexb, 2);\n      assert.equal(stamped1[40].indexc, 2);\n      assert.equal(stamped1[41].itemaProp, 'a');\n      assert.equal(stamped1[41].indexa, 5);\n      done();\n    });\n  });\n\n  test('pop', function(done) {\n    unconfigured.pop('items');\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[25].itemcProp, 'prop-1-3-3');\n      assert.equal(stamped1[25].indexa, 1);\n      assert.equal(stamped1[25].indexb, 2);\n      assert.equal(stamped1[25].indexc, 2);\n      assert.equal(stamped1[26], undefined);\n      done();\n    });\n  });\n\n  test('unshift', function(done) {\n    unconfigured.unshift('items', {prop: 'a'}, {prop: 'prop-1*'}, {prop: 'z'});\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 3 + 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'z');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itemaProp, 'prop-3');\n      assert.equal(stamped1[1].indexa, 1);\n      assert.equal(stamped1[2].itembProp, 'prop-3-1');\n      assert.equal(stamped1[2].indexa, 1);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[3].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped1[3].indexa, 1);\n      assert.equal(stamped1[3].indexb, 0);\n      assert.equal(stamped1[3].indexc, 0);\n      assert.equal(stamped1[27].itemaProp, 'prop-1*');\n      assert.equal(stamped1[27].indexa, 3);\n      assert.equal(stamped1[40].itemcProp, 'prop-1-3-3');\n      assert.equal(stamped1[40].indexa, 4);\n      assert.equal(stamped1[40].indexb, 2);\n      assert.equal(stamped1[40].indexc, 2);\n      assert.equal(stamped1[41].itemaProp, 'a');\n      assert.equal(stamped1[41].indexa, 5);\n      done();\n    });\n  });\n\n  test('shift', function(done) {\n    unconfigured.shift('items');\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-3');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-3-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[23].itemcProp, 'prop-2-3-1');\n      assert.equal(stamped1[23].indexa, 1);\n      assert.equal(stamped1[23].indexb, 2);\n      assert.equal(stamped1[23].indexc, 0);\n      assert.equal(stamped1[24].itemcProp, 'prop-2-3-2');\n      assert.equal(stamped1[24].indexa, 1);\n      assert.equal(stamped1[24].indexb, 2);\n      assert.equal(stamped1[24].indexc, 1);\n      assert.equal(stamped1[25].itemcProp, 'prop-2-3-3');\n      assert.equal(stamped1[25].indexa, 1);\n      assert.equal(stamped1[25].indexb, 2);\n      assert.equal(stamped1[25].indexc, 2);\n      assert.equal(stamped1[26], undefined);\n      done();\n    });\n  });\n\n  test('splice - remove from middle', function(done) {\n    unconfigured.splice('items', 1, 1)[0];\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-3');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-3-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[13].itemaProp, 'prop-1');\n      assert.equal(stamped1[13].indexa, 1);\n      assert.equal(stamped1[14].itembProp, 'prop-1-1');\n      assert.equal(stamped1[14].indexa, 1);\n      assert.equal(stamped1[14].indexb, 0);\n      assert.equal(stamped1[15].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[15].indexa, 1);\n      assert.equal(stamped1[15].indexb, 0);\n      assert.equal(stamped1[15].indexc, 0);\n      assert.equal(stamped1[23].itemcProp, 'prop-1-3-1');\n      assert.equal(stamped1[23].indexa, 1);\n      assert.equal(stamped1[23].indexb, 2);\n      assert.equal(stamped1[23].indexc, 0);\n      assert.equal(stamped1[24].itemcProp, 'prop-1-3-2');\n      assert.equal(stamped1[24].indexa, 1);\n      assert.equal(stamped1[24].indexb, 2);\n      assert.equal(stamped1[24].indexc, 1);\n      assert.equal(stamped1[25].itemcProp, 'prop-1-3-3');\n      assert.equal(stamped1[25].indexa, 1);\n      assert.equal(stamped1[25].indexb, 2);\n      assert.equal(stamped1[25].indexc, 2);\n      assert.equal(stamped1[26], undefined);\n      done();\n    });\n  });\n\n  test('splice - add to middle', function(done) {\n    unconfigured.splice('items', 1, 0, {prop: 'a'}, {prop: 'prop-1*'}, {prop: 'z'});\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 3 + 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'z');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itemaProp, 'prop-3');\n      assert.equal(stamped1[1].indexa, 1);\n      assert.equal(stamped1[2].itembProp, 'prop-3-1');\n      assert.equal(stamped1[2].indexa, 1);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[3].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped1[3].indexa, 1);\n      assert.equal(stamped1[3].indexb, 0);\n      assert.equal(stamped1[3].indexc, 0);\n      assert.equal(stamped1[27].itemaProp, 'prop-1*');\n      assert.equal(stamped1[27].indexa, 3);\n      assert.equal(stamped1[40].itemcProp, 'prop-1-3-3');\n      assert.equal(stamped1[40].indexa, 4);\n      assert.equal(stamped1[40].indexb, 2);\n      assert.equal(stamped1[40].indexc, 2);\n      assert.equal(stamped1[41].itemaProp, 'a');\n      assert.equal(stamped1[41].indexa, 5);\n      done();\n    });\n  });\n\n  test('splice - replace in middle', function(done) {\n    unconfigured.splice('items', 1, 2, {prop: 'a'}, {prop: 'prop-1*'}, {prop: 'z'});\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 3 + 1 + 1*3 + 1*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'z');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itemaProp, 'prop-1*');\n      assert.equal(stamped1[1].indexa, 1);\n      assert.equal(stamped1[2].itemaProp, 'prop-1');\n      assert.equal(stamped1[2].indexa, 2);\n      assert.equal(stamped1[3].itembProp, 'prop-1-1');\n      assert.equal(stamped1[3].indexa, 2);\n      assert.equal(stamped1[3].indexb, 0);\n      assert.equal(stamped1[4].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[4].indexa, 2);\n      assert.equal(stamped1[4].indexb, 0);\n      assert.equal(stamped1[4].indexc, 0);\n      assert.equal(stamped1[15].itemaProp, 'a');\n      assert.equal(stamped1[15].indexa, 3);\n      assert.equal(stamped1[16], undefined);\n      done();\n    });\n  });\n\n});\n\nsuite('reacting to changes, view sort with filter', function() {\n\n  var unconfigured;\n\n  setup(function() {\n    unconfigured = fixture('unconfigured');\n    unconfigured.items = window.getData();\n    unconfigured.$.el1.$.repeater.sort = function(a, b) {\n      return b.prop == a.prop ? 0 : b.prop < a.prop ? -1 : 1;\n    };\n    unconfigured.$.el1.$.repeater.filter = function(o) {\n      return o.prop.indexOf('2') < 0;\n    };\n    flush();\n  });\n\n  test('push', function(done) {\n    unconfigured.push('items', {prop: 'a'}, {prop: 'item*2'}, {prop: 'z'});\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'z');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itemaProp, 'prop-3');\n      assert.equal(stamped1[1].indexa, 1);\n      assert.equal(stamped1[2].itembProp, 'prop-3-1');\n      assert.equal(stamped1[2].indexa, 1);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[3].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped1[3].indexa, 1);\n      assert.equal(stamped1[3].indexb, 0);\n      assert.equal(stamped1[3].indexc, 0);\n      assert.equal(stamped1[26].itemcProp, 'prop-1-3-3');\n      assert.equal(stamped1[26].indexa, 2);\n      assert.equal(stamped1[26].indexb, 2);\n      assert.equal(stamped1[26].indexc, 2);\n      assert.equal(stamped1[27].itemaProp, 'a');\n      assert.equal(stamped1[27].indexa, 3);\n      assert.equal(stamped1[28], undefined);\n      done();\n    });\n  });\n\n  test('pop', function(done) {\n    unconfigured.pop('items');\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 1 + 1*3 + 1*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-1');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-1-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[12].itemcProp, 'prop-1-3-3');\n      assert.equal(stamped1[12].indexa, 0);\n      assert.equal(stamped1[12].indexb, 2);\n      assert.equal(stamped1[12].indexc, 2);\n      assert.equal(stamped1[13], undefined);\n      done();\n    });\n  });\n\n  test('unshift', function(done) {\n    unconfigured.unshift('items', {prop: 'a'}, {prop: 'item*2'}, {prop: 'z'});\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'z');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itemaProp, 'prop-3');\n      assert.equal(stamped1[1].indexa, 1);\n      assert.equal(stamped1[2].itembProp, 'prop-3-1');\n      assert.equal(stamped1[2].indexa, 1);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[3].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped1[3].indexa, 1);\n      assert.equal(stamped1[3].indexb, 0);\n      assert.equal(stamped1[3].indexc, 0);\n      assert.equal(stamped1[26].itemcProp, 'prop-1-3-3');\n      assert.equal(stamped1[26].indexa, 2);\n      assert.equal(stamped1[26].indexb, 2);\n      assert.equal(stamped1[26].indexc, 2);\n      assert.equal(stamped1[27].itemaProp, 'a');\n      assert.equal(stamped1[27].indexa, 3);\n      assert.equal(stamped1[28], undefined);\n      done();\n    });\n  });\n\n  test('shift', function(done) {\n    unconfigured.shift('items');\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 1 + 1*3 + 1*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-3');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-3-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[12].itemcProp, 'prop-3-3-3');\n      assert.equal(stamped1[12].indexa, 0);\n      assert.equal(stamped1[12].indexb, 2);\n      assert.equal(stamped1[12].indexc, 2);\n      assert.equal(stamped1[13], undefined);\n      done();\n    });\n  });\n\n  test('splice - remove from middle', function(done) {\n    unconfigured.splice('items', 1, 1)[0];\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-3');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-3-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[13].itemaProp, 'prop-1');\n      assert.equal(stamped1[13].indexa, 1);\n      assert.equal(stamped1[14].itembProp, 'prop-1-1');\n      assert.equal(stamped1[14].indexa, 1);\n      assert.equal(stamped1[14].indexb, 0);\n      assert.equal(stamped1[15].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[15].indexa, 1);\n      assert.equal(stamped1[15].indexb, 0);\n      assert.equal(stamped1[15].indexc, 0);\n      done();\n    });\n  });\n\n  test('splice - add to middle', function(done) {\n    unconfigured.splice('items', 1, 0, {prop: 'a'}, {prop: 'item*2'}, {prop: 'z'});\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'z');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itemaProp, 'prop-3');\n      assert.equal(stamped1[1].indexa, 1);\n      assert.equal(stamped1[2].itembProp, 'prop-3-1');\n      assert.equal(stamped1[2].indexa, 1);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[3].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped1[3].indexa, 1);\n      assert.equal(stamped1[3].indexb, 0);\n      assert.equal(stamped1[3].indexc, 0);\n      assert.equal(stamped1[26].itemcProp, 'prop-1-3-3');\n      assert.equal(stamped1[26].indexa, 2);\n      assert.equal(stamped1[26].indexb, 2);\n      assert.equal(stamped1[26].indexc, 2);\n      assert.equal(stamped1[27].itemaProp, 'a');\n      assert.equal(stamped1[27].indexa, 3);\n      assert.equal(stamped1[28], undefined);\n      done();\n    });\n  });\n\n  test('splice - replace in middle', function(done) {\n    unconfigured.splice('items', 1, 2, {prop: 'a'}, {prop: 'item*2'}, {prop: 'z'});\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 1 + 1*3 + 1*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'z');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itemaProp, 'prop-1');\n      assert.equal(stamped1[1].indexa, 1);\n      assert.equal(stamped1[2].itembProp, 'prop-1-1');\n      assert.equal(stamped1[2].indexa, 1);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[3].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[3].indexa, 1);\n      assert.equal(stamped1[3].indexb, 0);\n      assert.equal(stamped1[3].indexc, 0);\n      assert.equal(stamped1[13].itemcProp, 'prop-1-3-3');\n      assert.equal(stamped1[13].indexa, 1);\n      assert.equal(stamped1[13].indexb, 2);\n      assert.equal(stamped1[13].indexc, 2);\n      assert.equal(stamped1[14].itemaProp, 'a');\n      assert.equal(stamped1[14].indexa, 2);\n      assert.equal(stamped1[15], undefined);\n      done();\n    });\n  });\n\n});\n\nsuite('reacting to changes, array sort (direct mutation)', function() {\n\n  let unconfigured;\n\n  setup(function() {\n    unconfigured = fixture('unconfigured-mutable');\n    unconfigured.items = window.getData();\n    flush();\n  });\n\n  test('push', function(done) {\n    unconfigured.$.el1.domUpdateHandlerCount = 0;\n    unconfigured.items.push({prop: 'new-1'}, {prop: 'new-2'});\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      var stamped2 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n      assert.equal(stamped2.length, 2 + 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[38].itemcProp, 'prop-3-3-3');\n      assert.equal(stamped1[38].indexa, 2);\n      assert.equal(stamped1[38].indexb, 2);\n      assert.equal(stamped1[38].indexc, 2);\n      assert.equal(stamped1[39].itemaProp, 'new-1');\n      assert.equal(stamped1[40].itemaProp, 'new-2');\n      assert.equal(stamped1[41], undefined);\n      assert.equal(stamped2[38].itemcProp, 'prop-3-3-3');\n      assert.equal(stamped2[38].indexa, 2);\n      assert.equal(stamped2[38].indexb, 2);\n      assert.equal(stamped2[38].indexc, 2);\n      assert.equal(stamped2[39].itemaProp, 'new-1');\n      assert.equal(stamped2[40].itemaProp, 'new-2');\n      assert.equal(stamped2[41], undefined);\n      assert.equal(unconfigured.$.el1.domUpdateHandlerCount, 1);\n      done();\n    });\n  });\n\n  test('pop', function(done) {\n    unconfigured.items.pop();\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      var stamped2 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped2.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[25].itemcProp, 'prop-2-3-3');\n      assert.equal(stamped1[25].indexa, 1);\n      assert.equal(stamped1[25].indexb, 2);\n      assert.equal(stamped1[25].indexc, 2);\n      assert.equal(stamped1[26], undefined);\n      assert.equal(stamped2[25].itemcProp, 'prop-2-3-3');\n      assert.equal(stamped2[25].indexa, 1);\n      assert.equal(stamped2[25].indexb, 2);\n      assert.equal(stamped2[25].indexc, 2);\n      assert.equal(stamped2[26], undefined);\n      done();\n    });\n  });\n\n  test('unshift', function(done) {\n    unconfigured.items.unshift({prop: 'new-1'}, {prop: 'new-2'});\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      var stamped2 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n      assert.equal(stamped2.length, 2 + 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'new-1');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itemaProp, 'new-2');\n      assert.equal(stamped1[1].indexa, 1);\n      assert.equal(stamped1[2].itemaProp, 'prop-1');\n      assert.equal(stamped1[2].indexa, 2);\n      assert.equal(stamped2[0].itemaProp, 'new-1');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped2[1].itemaProp, 'new-2');\n      assert.equal(stamped1[1].indexa, 1);\n      assert.equal(stamped2[2].itemaProp, 'prop-1');\n      assert.equal(stamped2[2].indexa, 2);\n      done();\n    });\n  });\n\n  test('shift', function(done) {\n    unconfigured.items.shift();\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      var stamped2 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped2.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-2');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-2-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-2-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped2[0].itemaProp, 'prop-2');\n      assert.equal(stamped2[0].indexa, 0);\n      assert.equal(stamped2[1].itembProp, 'prop-2-1');\n      assert.equal(stamped2[1].indexa, 0);\n      assert.equal(stamped2[1].indexb, 0);\n      assert.equal(stamped2[2].itemcProp, 'prop-2-1-1');\n      assert.equal(stamped2[2].indexa, 0);\n      assert.equal(stamped2[2].indexb, 0);\n      assert.equal(stamped2[2].indexc, 0);\n      done();\n    });\n  });\n\n  test('splice - remove from middle', function(done) {\n    unconfigured.items.splice(1, 1)[0];\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      var stamped2 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped2.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-1');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-1-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[13].itemaProp, 'prop-3');\n      assert.equal(stamped1[13].indexa, 1);\n      assert.equal(stamped1[14].itembProp, 'prop-3-1');\n      assert.equal(stamped1[14].indexa, 1);\n      assert.equal(stamped1[14].indexb, 0);\n      assert.equal(stamped1[15].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped1[15].indexa, 1);\n      assert.equal(stamped1[15].indexb, 0);\n      assert.equal(stamped1[15].indexc, 0);\n      assert.equal(stamped2[0].itemaProp, 'prop-1');\n      assert.equal(stamped2[0].indexa, 0);\n      assert.equal(stamped2[1].itembProp, 'prop-1-1');\n      assert.equal(stamped2[1].indexa, 0);\n      assert.equal(stamped2[1].indexb, 0);\n      assert.equal(stamped2[2].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped2[2].indexa, 0);\n      assert.equal(stamped2[2].indexb, 0);\n      assert.equal(stamped2[2].indexc, 0);\n      assert.equal(stamped2[13].itemaProp, 'prop-3');\n      assert.equal(stamped2[13].indexa, 1);\n      assert.equal(stamped2[14].itembProp, 'prop-3-1');\n      assert.equal(stamped2[14].indexa, 1);\n      assert.equal(stamped2[14].indexb, 0);\n      assert.equal(stamped2[15].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped2[15].indexa, 1);\n      assert.equal(stamped2[15].indexb, 0);\n      assert.equal(stamped2[15].indexc, 0);\n      done();\n    });\n  });\n\n  test('splice - add to middle', function(done) {\n    unconfigured.items.splice(1, 0, {prop: 'new-1'}, {prop: 'new-2'});\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      var stamped2 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n      assert.equal(stamped2.length, 2 + 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-1');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-1-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[13].itemaProp, 'new-1');\n      assert.equal(stamped1[13].indexa, 1);\n      assert.equal(stamped1[14].itemaProp, 'new-2');\n      assert.equal(stamped1[14].indexa, 2);\n      assert.equal(stamped1[15].itemaProp, 'prop-2');\n      assert.equal(stamped1[15].indexa, 3);\n      assert.equal(stamped1[16].itembProp, 'prop-2-1');\n      assert.equal(stamped1[16].indexa, 3);\n      assert.equal(stamped1[16].indexb, 0);\n      assert.equal(stamped1[17].itemcProp, 'prop-2-1-1');\n      assert.equal(stamped1[17].indexa, 3);\n      assert.equal(stamped1[17].indexb, 0);\n      assert.equal(stamped1[17].indexc, 0);\n      assert.equal(stamped2[0].itemaProp, 'prop-1');\n      assert.equal(stamped2[0].indexa, 0);\n      assert.equal(stamped2[1].itembProp, 'prop-1-1');\n      assert.equal(stamped2[1].indexa, 0);\n      assert.equal(stamped2[1].indexb, 0);\n      assert.equal(stamped2[2].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped2[2].indexa, 0);\n      assert.equal(stamped2[2].indexb, 0);\n      assert.equal(stamped2[2].indexc, 0);\n      assert.equal(stamped2[13].itemaProp, 'new-1');\n      assert.equal(stamped2[13].indexa, 1);\n      assert.equal(stamped2[14].itemaProp, 'new-2');\n      assert.equal(stamped2[14].indexa, 2);\n      assert.equal(stamped2[15].itemaProp, 'prop-2');\n      assert.equal(stamped2[15].indexa, 3);\n      assert.equal(stamped2[16].itembProp, 'prop-2-1');\n      assert.equal(stamped2[16].indexa, 3);\n      assert.equal(stamped2[16].indexb, 0);\n      assert.equal(stamped2[17].itemcProp, 'prop-2-1-1');\n      assert.equal(stamped2[17].indexa, 3);\n      assert.equal(stamped2[17].indexb, 0);\n      assert.equal(stamped2[17].indexc, 0);\n      done();\n    });\n  });\n\n  test('splice - replace in middle', function(done) {\n    unconfigured.items.splice(1, 2, {prop: 'new-1'}, {prop: 'new-2'});\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      var stamped2 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 1 + 1*3 + 1*3*3, 'total stamped count incorrect');\n      assert.equal(stamped2.length, 2 + 1 + 1*3 + 1*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-1');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-1-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[13].itemaProp, 'new-1');\n      assert.equal(stamped1[13].indexa, 1);\n      assert.equal(stamped1[14].itemaProp, 'new-2');\n      assert.equal(stamped1[14].indexa, 2);\n      assert.equal(stamped1[15], undefined);\n      assert.equal(stamped2[0].itemaProp, 'prop-1');\n      assert.equal(stamped2[0].indexa, 0);\n      assert.equal(stamped2[1].itembProp, 'prop-1-1');\n      assert.equal(stamped2[1].indexa, 0);\n      assert.equal(stamped2[1].indexb, 0);\n      assert.equal(stamped2[2].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped2[2].indexa, 0);\n      assert.equal(stamped2[2].indexb, 0);\n      assert.equal(stamped2[2].indexc, 0);\n      assert.equal(stamped2[13].itemaProp, 'new-1');\n      assert.equal(stamped2[13].indexa, 1);\n      assert.equal(stamped2[14].itemaProp, 'new-2');\n      assert.equal(stamped2[14].indexa, 2);\n      assert.equal(stamped2[15], undefined);\n      done();\n    });\n  });\n\n  test('change graph', function(done) {\n    unconfigured.items[2].items[2].items[2].prop = 'changed!';\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      var stamped2 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n      assert.equal(stamped2.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-1');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-1-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped2[0].itemaProp, 'prop-1');\n      assert.equal(stamped2[0].indexa, 0);\n      assert.equal(stamped2[1].itembProp, 'prop-1-1');\n      assert.equal(stamped2[1].indexa, 0);\n      assert.equal(stamped2[1].indexb, 0);\n      assert.equal(stamped2[2].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped2[2].indexa, 0);\n      assert.equal(stamped2[2].indexb, 0);\n      assert.equal(stamped2[2].indexc, 0);\n      assert.equal(stamped1[38].itemcProp, 'changed!');\n      assert.equal(stamped1[38].indexa, 2);\n      assert.equal(stamped1[38].indexb, 2);\n      assert.equal(stamped1[38].indexc, 2);\n      assert.equal(stamped1[39], undefined);\n      assert.equal(stamped2[38].itemcProp, 'changed!');\n      assert.equal(stamped2[38].indexa, 2);\n      assert.equal(stamped2[38].indexb, 2);\n      assert.equal(stamped2[38].indexc, 2);\n      assert.equal(stamped2[39], undefined);\n      done();\n    });\n  });\n\n});\n\nsuite('reacting to changes, array sort with filter (direct mutation)', function() {\n\n  let unconfigured;\n\n  setup(function() {\n    unconfigured = fixture('unconfigured-mutable');\n    unconfigured.items = window.getData();\n    unconfigured.$.el1.$.repeater.filter = function(o) {\n      return o.prop.indexOf('2') < 0;\n    };\n    flush();\n  });\n\n  test('push', function(done) {\n    unconfigured.items.push({prop: 'new-1'}, {prop: 'new-2'});\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 1 + 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-1');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-1-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[23].itemcProp, 'prop-3-3-1');\n      assert.equal(stamped1[23].indexa, 1);\n      assert.equal(stamped1[23].indexb, 2);\n      assert.equal(stamped1[23].indexc, 0);\n      assert.equal(stamped1[24].itemcProp, 'prop-3-3-2');\n      assert.equal(stamped1[24].indexa, 1);\n      assert.equal(stamped1[24].indexb, 2);\n      assert.equal(stamped1[24].indexc, 1);\n      assert.equal(stamped1[25].itemcProp, 'prop-3-3-3');\n      assert.equal(stamped1[25].indexa, 1);\n      assert.equal(stamped1[25].indexb, 2);\n      assert.equal(stamped1[25].indexc, 2);\n      assert.equal(stamped1[26].itemaProp, 'new-1');\n      assert.equal(stamped1[26].indexa, 2);\n      assert.equal(stamped1[27], undefined);\n      done();\n    });\n  });\n\n  test('pop', function(done) {\n    unconfigured.items.pop();\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 1 + 1*3 + 1*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-1');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-1-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[10].itemcProp, 'prop-1-3-1');\n      assert.equal(stamped1[10].indexa, 0);\n      assert.equal(stamped1[10].indexb, 2);\n      assert.equal(stamped1[10].indexc, 0);\n      assert.equal(stamped1[11].itemcProp, 'prop-1-3-2');\n      assert.equal(stamped1[11].indexa, 0);\n      assert.equal(stamped1[11].indexb, 2);\n      assert.equal(stamped1[11].indexc, 1);\n      assert.equal(stamped1[12].itemcProp, 'prop-1-3-3');\n      assert.equal(stamped1[12].indexa, 0);\n      assert.equal(stamped1[12].indexb, 2);\n      assert.equal(stamped1[12].indexc, 2);\n      assert.equal(stamped1[13], undefined);\n      done();\n    });\n  });\n\n  test('unshift', function(done) {\n    unconfigured.items.unshift({prop: 'new-1'}, {prop: 'new-2'});\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 1 + 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'new-1');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itemaProp, 'prop-1');\n      assert.equal(stamped1[1].indexa, 1);\n      assert.equal(stamped1[2].itembProp, 'prop-1-1');\n      assert.equal(stamped1[2].indexa, 1);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[3].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[3].indexa, 1);\n      assert.equal(stamped1[3].indexb, 0);\n      assert.equal(stamped1[3].indexc, 0);\n      done();\n    });\n  });\n\n  test('shift', function(done) {\n    unconfigured.items.shift();\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 1 + 1*3 + 1*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-3');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-3-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[10].itemcProp, 'prop-3-3-1');\n      assert.equal(stamped1[10].indexa, 0);\n      assert.equal(stamped1[10].indexb, 2);\n      assert.equal(stamped1[10].indexc, 0);\n      assert.equal(stamped1[11].itemcProp, 'prop-3-3-2');\n      assert.equal(stamped1[11].indexa, 0);\n      assert.equal(stamped1[11].indexb, 2);\n      assert.equal(stamped1[11].indexc, 1);\n      assert.equal(stamped1[12].itemcProp, 'prop-3-3-3');\n      assert.equal(stamped1[12].indexa, 0);\n      assert.equal(stamped1[12].indexb, 2);\n      assert.equal(stamped1[12].indexc, 2);\n      assert.equal(stamped1[13], undefined);\n      done();\n    });\n  });\n\n  test('splice - remove from middle', function(done) {\n    unconfigured.items.splice(1, 1);\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-1');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-1-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[23].itemcProp, 'prop-3-3-1');\n      assert.equal(stamped1[23].indexa, 1);\n      assert.equal(stamped1[23].indexb, 2);\n      assert.equal(stamped1[23].indexc, 0);\n      assert.equal(stamped1[24].itemcProp, 'prop-3-3-2');\n      assert.equal(stamped1[24].indexa, 1);\n      assert.equal(stamped1[24].indexb, 2);\n      assert.equal(stamped1[24].indexc, 1);\n      assert.equal(stamped1[25].itemcProp, 'prop-3-3-3');\n      assert.equal(stamped1[25].indexa, 1);\n      assert.equal(stamped1[25].indexb, 2);\n      assert.equal(stamped1[25].indexc, 2);\n      assert.equal(stamped1[26], undefined);\n      done();\n    });\n  });\n\n  test('splice - add to middle', function(done) {\n    unconfigured.items.splice(1, 0, {prop: 'new-1'}, {prop: 'new-2'});\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 1 + 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-1');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-1-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[13].itemaProp, 'new-1');\n      assert.equal(stamped1[13].indexa, 1);\n      assert.equal(stamped1[14].itemaProp, 'prop-3');\n      assert.equal(stamped1[14].indexa, 2);\n      assert.equal(stamped1[15].itembProp, 'prop-3-1');\n      assert.equal(stamped1[15].indexa, 2);\n      assert.equal(stamped1[15].indexb, 0);\n      assert.equal(stamped1[16].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped1[16].indexa, 2);\n      assert.equal(stamped1[16].indexb, 0);\n      assert.equal(stamped1[16].indexc, 0);\n      done();\n    });\n  });\n\n  test('splice - replace in middle', function(done) {\n    unconfigured.items.splice(1, 2, {prop: 'new-1'}, {prop: 'new-2'});\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 1 + 1 + 1*3 + 1*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-1');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-1-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[13].itemaProp, 'new-1');\n      assert.equal(stamped1[14], undefined);\n      done();\n    });\n  });\n\n});\n\nsuite('reacting to changes, view sort (direct mutation)', function() {\n\n  let unconfigured;\n\n  setup(function() {\n    unconfigured = fixture('unconfigured-mutable');\n    unconfigured.items = window.getData();\n    unconfigured.$.el1.$.repeater.sort = function(a, b) {\n      return b.prop == a.prop ? 0 : b.prop < a.prop ? -1 : 1;\n    };\n    flush();\n  });\n\n  test('push', function(done) {\n    unconfigured.items.push({prop: 'a'}, {prop: 'prop-1*'}, {prop: 'z'});\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 3 + 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'z');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itemaProp, 'prop-3');\n      assert.equal(stamped1[1].indexa, 1);\n      assert.equal(stamped1[2].itembProp, 'prop-3-1');\n      assert.equal(stamped1[2].indexa, 1);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[3].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped1[3].indexa, 1);\n      assert.equal(stamped1[3].indexb, 0);\n      assert.equal(stamped1[3].indexc, 0);\n      assert.equal(stamped1[27].itemaProp, 'prop-1*');\n      assert.equal(stamped1[27].indexa, 3);\n      assert.equal(stamped1[40].itemcProp, 'prop-1-3-3');\n      assert.equal(stamped1[40].indexa, 4);\n      assert.equal(stamped1[40].indexb, 2);\n      assert.equal(stamped1[40].indexc, 2);\n      assert.equal(stamped1[41].itemaProp, 'a');\n      assert.equal(stamped1[41].indexa, 5);\n      done();\n    });\n  });\n\n  test('pop', function(done) {\n    unconfigured.items.pop();\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[25].itemcProp, 'prop-1-3-3');\n      assert.equal(stamped1[25].indexa, 1);\n      assert.equal(stamped1[25].indexb, 2);\n      assert.equal(stamped1[25].indexc, 2);\n      assert.equal(stamped1[26], undefined);\n      done();\n    });\n  });\n\n  test('unshift', function(done) {\n    unconfigured.items.unshift({prop: 'a'}, {prop: 'prop-1*'}, {prop: 'z'});\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 3 + 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'z');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itemaProp, 'prop-3');\n      assert.equal(stamped1[1].indexa, 1);\n      assert.equal(stamped1[2].itembProp, 'prop-3-1');\n      assert.equal(stamped1[2].indexa, 1);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[3].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped1[3].indexa, 1);\n      assert.equal(stamped1[3].indexb, 0);\n      assert.equal(stamped1[3].indexc, 0);\n      assert.equal(stamped1[27].itemaProp, 'prop-1*');\n      assert.equal(stamped1[27].indexa, 3);\n      assert.equal(stamped1[40].itemcProp, 'prop-1-3-3');\n      assert.equal(stamped1[40].indexa, 4);\n      assert.equal(stamped1[40].indexb, 2);\n      assert.equal(stamped1[40].indexc, 2);\n      assert.equal(stamped1[41].itemaProp, 'a');\n      assert.equal(stamped1[41].indexa, 5);\n      done();\n    });\n  });\n\n  test('shift', function(done) {\n    unconfigured.items.shift();\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-3');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-3-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[23].itemcProp, 'prop-2-3-1');\n      assert.equal(stamped1[23].indexa, 1);\n      assert.equal(stamped1[23].indexb, 2);\n      assert.equal(stamped1[23].indexc, 0);\n      assert.equal(stamped1[24].itemcProp, 'prop-2-3-2');\n      assert.equal(stamped1[24].indexa, 1);\n      assert.equal(stamped1[24].indexb, 2);\n      assert.equal(stamped1[24].indexc, 1);\n      assert.equal(stamped1[25].itemcProp, 'prop-2-3-3');\n      assert.equal(stamped1[25].indexa, 1);\n      assert.equal(stamped1[25].indexb, 2);\n      assert.equal(stamped1[25].indexc, 2);\n      assert.equal(stamped1[26], undefined);\n      done();\n    });\n  });\n\n  test('splice - remove from middle', function(done) {\n    unconfigured.items.splice(1, 1)[0];\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-3');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-3-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[13].itemaProp, 'prop-1');\n      assert.equal(stamped1[13].indexa, 1);\n      assert.equal(stamped1[14].itembProp, 'prop-1-1');\n      assert.equal(stamped1[14].indexa, 1);\n      assert.equal(stamped1[14].indexb, 0);\n      assert.equal(stamped1[15].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[15].indexa, 1);\n      assert.equal(stamped1[15].indexb, 0);\n      assert.equal(stamped1[15].indexc, 0);\n      assert.equal(stamped1[23].itemcProp, 'prop-1-3-1');\n      assert.equal(stamped1[23].indexa, 1);\n      assert.equal(stamped1[23].indexb, 2);\n      assert.equal(stamped1[23].indexc, 0);\n      assert.equal(stamped1[24].itemcProp, 'prop-1-3-2');\n      assert.equal(stamped1[24].indexa, 1);\n      assert.equal(stamped1[24].indexb, 2);\n      assert.equal(stamped1[24].indexc, 1);\n      assert.equal(stamped1[25].itemcProp, 'prop-1-3-3');\n      assert.equal(stamped1[25].indexa, 1);\n      assert.equal(stamped1[25].indexb, 2);\n      assert.equal(stamped1[25].indexc, 2);\n      assert.equal(stamped1[26], undefined);\n      done();\n    });\n  });\n\n  test('splice - add to middle', function(done) {\n    unconfigured.items.splice(1, 0, {prop: 'a'}, {prop: 'prop-1*'}, {prop: 'z'});\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 3 + 3 + 3*3 + 3*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'z');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itemaProp, 'prop-3');\n      assert.equal(stamped1[1].indexa, 1);\n      assert.equal(stamped1[2].itembProp, 'prop-3-1');\n      assert.equal(stamped1[2].indexa, 1);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[3].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped1[3].indexa, 1);\n      assert.equal(stamped1[3].indexb, 0);\n      assert.equal(stamped1[3].indexc, 0);\n      assert.equal(stamped1[27].itemaProp, 'prop-1*');\n      assert.equal(stamped1[27].indexa, 3);\n      assert.equal(stamped1[40].itemcProp, 'prop-1-3-3');\n      assert.equal(stamped1[40].indexa, 4);\n      assert.equal(stamped1[40].indexb, 2);\n      assert.equal(stamped1[40].indexc, 2);\n      assert.equal(stamped1[41].itemaProp, 'a');\n      assert.equal(stamped1[41].indexa, 5);\n      done();\n    });\n  });\n\n  test('splice - replace in middle', function(done) {\n    unconfigured.items.splice(1, 2, {prop: 'a'}, {prop: 'prop-1*'}, {prop: 'z'});\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 3 + 1 + 1*3 + 1*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'z');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itemaProp, 'prop-1*');\n      assert.equal(stamped1[1].indexa, 1);\n      assert.equal(stamped1[2].itemaProp, 'prop-1');\n      assert.equal(stamped1[2].indexa, 2);\n      assert.equal(stamped1[3].itembProp, 'prop-1-1');\n      assert.equal(stamped1[3].indexa, 2);\n      assert.equal(stamped1[3].indexb, 0);\n      assert.equal(stamped1[4].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[4].indexa, 2);\n      assert.equal(stamped1[4].indexb, 0);\n      assert.equal(stamped1[4].indexc, 0);\n      assert.equal(stamped1[15].itemaProp, 'a');\n      assert.equal(stamped1[15].indexa, 3);\n      assert.equal(stamped1[16], undefined);\n      done();\n    });\n  });\n\n});\n\nsuite('reacting to changes, view sort with filter (direct mutation)', function() {\n\n  let unconfigured;\n\n  setup(function() {\n    unconfigured = fixture('unconfigured-mutable');\n    unconfigured.items = window.getData();\n    unconfigured.$.el1.$.repeater.sort = function(a, b) {\n      return b.prop == a.prop ? 0 : b.prop < a.prop ? -1 : 1;\n    };\n    unconfigured.$.el1.$.repeater.filter = function(o) {\n      return o.prop.indexOf('2') < 0;\n    };\n    flush();\n  });\n\n  test('push', function(done) {\n    unconfigured.items.push({prop: 'a'}, {prop: 'item*2'}, {prop: 'z'});\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'z');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itemaProp, 'prop-3');\n      assert.equal(stamped1[1].indexa, 1);\n      assert.equal(stamped1[2].itembProp, 'prop-3-1');\n      assert.equal(stamped1[2].indexa, 1);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[3].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped1[3].indexa, 1);\n      assert.equal(stamped1[3].indexb, 0);\n      assert.equal(stamped1[3].indexc, 0);\n      assert.equal(stamped1[26].itemcProp, 'prop-1-3-3');\n      assert.equal(stamped1[26].indexa, 2);\n      assert.equal(stamped1[26].indexb, 2);\n      assert.equal(stamped1[26].indexc, 2);\n      assert.equal(stamped1[27].itemaProp, 'a');\n      assert.equal(stamped1[27].indexa, 3);\n      assert.equal(stamped1[28], undefined);\n      done();\n    });\n  });\n\n  test('pop', function(done) {\n    unconfigured.items.pop();\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 1 + 1*3 + 1*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-1');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-1-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[12].itemcProp, 'prop-1-3-3');\n      assert.equal(stamped1[12].indexa, 0);\n      assert.equal(stamped1[12].indexb, 2);\n      assert.equal(stamped1[12].indexc, 2);\n      assert.equal(stamped1[13], undefined);\n      done();\n    });\n  });\n\n  test('unshift', function(done) {\n    unconfigured.items.unshift({prop: 'a'}, {prop: 'item*2'}, {prop: 'z'});\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'z');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itemaProp, 'prop-3');\n      assert.equal(stamped1[1].indexa, 1);\n      assert.equal(stamped1[2].itembProp, 'prop-3-1');\n      assert.equal(stamped1[2].indexa, 1);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[3].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped1[3].indexa, 1);\n      assert.equal(stamped1[3].indexb, 0);\n      assert.equal(stamped1[3].indexc, 0);\n      assert.equal(stamped1[26].itemcProp, 'prop-1-3-3');\n      assert.equal(stamped1[26].indexa, 2);\n      assert.equal(stamped1[26].indexb, 2);\n      assert.equal(stamped1[26].indexc, 2);\n      assert.equal(stamped1[27].itemaProp, 'a');\n      assert.equal(stamped1[27].indexa, 3);\n      assert.equal(stamped1[28], undefined);\n      done();\n    });\n  });\n\n  test('shift', function(done) {\n    unconfigured.items.shift();\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 1 + 1*3 + 1*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-3');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-3-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[12].itemcProp, 'prop-3-3-3');\n      assert.equal(stamped1[12].indexa, 0);\n      assert.equal(stamped1[12].indexb, 2);\n      assert.equal(stamped1[12].indexc, 2);\n      assert.equal(stamped1[13], undefined);\n      done();\n    });\n  });\n\n  test('splice - remove from middle', function(done) {\n    unconfigured.items.splice(1, 1)[0];\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'prop-3');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itembProp, 'prop-3-1');\n      assert.equal(stamped1[1].indexa, 0);\n      assert.equal(stamped1[1].indexb, 0);\n      assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped1[2].indexa, 0);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[2].indexc, 0);\n      assert.equal(stamped1[13].itemaProp, 'prop-1');\n      assert.equal(stamped1[13].indexa, 1);\n      assert.equal(stamped1[14].itembProp, 'prop-1-1');\n      assert.equal(stamped1[14].indexa, 1);\n      assert.equal(stamped1[14].indexb, 0);\n      assert.equal(stamped1[15].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[15].indexa, 1);\n      assert.equal(stamped1[15].indexb, 0);\n      assert.equal(stamped1[15].indexc, 0);\n      done();\n    });\n  });\n\n  test('splice - add to middle', function(done) {\n    unconfigured.items.splice(1, 0, {prop: 'a'}, {prop: 'item*2'}, {prop: 'z'});\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 2 + 2*3 + 2*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'z');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itemaProp, 'prop-3');\n      assert.equal(stamped1[1].indexa, 1);\n      assert.equal(stamped1[2].itembProp, 'prop-3-1');\n      assert.equal(stamped1[2].indexa, 1);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[3].itemcProp, 'prop-3-1-1');\n      assert.equal(stamped1[3].indexa, 1);\n      assert.equal(stamped1[3].indexb, 0);\n      assert.equal(stamped1[3].indexc, 0);\n      assert.equal(stamped1[26].itemcProp, 'prop-1-3-3');\n      assert.equal(stamped1[26].indexa, 2);\n      assert.equal(stamped1[26].indexb, 2);\n      assert.equal(stamped1[26].indexc, 2);\n      assert.equal(stamped1[27].itemaProp, 'a');\n      assert.equal(stamped1[27].indexa, 3);\n      assert.equal(stamped1[28], undefined);\n      done();\n    });\n  });\n\n  test('splice - replace in middle', function(done) {\n    unconfigured.items.splice(1, 2, {prop: 'a'}, {prop: 'item*2'}, {prop: 'z'});\n    unconfigured.items = unconfigured.items;\n    setTimeout(function() {\n      var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1.length, 2 + 1 + 1*3 + 1*3*3, 'total stamped count incorrect');\n      assert.equal(stamped1[0].itemaProp, 'z');\n      assert.equal(stamped1[0].indexa, 0);\n      assert.equal(stamped1[1].itemaProp, 'prop-1');\n      assert.equal(stamped1[1].indexa, 1);\n      assert.equal(stamped1[2].itembProp, 'prop-1-1');\n      assert.equal(stamped1[2].indexa, 1);\n      assert.equal(stamped1[2].indexb, 0);\n      assert.equal(stamped1[3].itemcProp, 'prop-1-1-1');\n      assert.equal(stamped1[3].indexa, 1);\n      assert.equal(stamped1[3].indexb, 0);\n      assert.equal(stamped1[3].indexc, 0);\n      assert.equal(stamped1[13].itemcProp, 'prop-1-3-3');\n      assert.equal(stamped1[13].indexa, 1);\n      assert.equal(stamped1[13].indexb, 2);\n      assert.equal(stamped1[13].indexc, 2);\n      assert.equal(stamped1[14].itemaProp, 'a');\n      assert.equal(stamped1[14].indexa, 2);\n      assert.equal(stamped1[15], undefined);\n      done();\n    });\n  });\n\n});\n\nsuite('multiple mutations in same turn', function() {\n\n  let primitive;\n\n  setup(function() {\n    primitive = fixture('primitive');\n    flush();\n  });\n\n  test('array sort, no filter: unshift+pop', function(done) {\n    // repeater 1\n    var stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped1[0].itemaProp, 'a');\n    assert.equal(stamped1[1].itemaProp, 'b');\n    assert.equal(stamped1[2].itemaProp, 'c');\n    assert.equal(stamped1[3].itemaProp, 'd');\n    assert.equal(stamped1[4].itemaProp, 'e');\n    primitive.unshift('items', 'new1');\n    primitive.pop('items');\n    setTimeout(function() {\n      stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1[0].itemaProp, 'new1');\n      assert.equal(stamped1[1].itemaProp, 'a');\n      assert.equal(stamped1[2].itemaProp, 'b');\n      assert.equal(stamped1[3].itemaProp, 'c');\n      assert.equal(stamped1[4].itemaProp, 'd');\n      primitive.unshift('items', 'new2');\n      primitive.pop('items');\n      primitive.unshift('items', 'new3');\n      primitive.pop('items');\n      setTimeout(function() {\n        stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n        assert.equal(stamped1[0].itemaProp, 'new3');\n        assert.equal(stamped1[1].itemaProp, 'new2');\n        assert.equal(stamped1[2].itemaProp, 'new1');\n        assert.equal(stamped1[3].itemaProp, 'a');\n        assert.equal(stamped1[4].itemaProp, 'b');\n        primitive.shift('items');\n        primitive.push('items', 'c');\n        setTimeout(function() {\n          stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n          assert.equal(stamped1[0].itemaProp, 'new2');\n          assert.equal(stamped1[1].itemaProp, 'new1');\n          assert.equal(stamped1[2].itemaProp, 'a');\n          assert.equal(stamped1[3].itemaProp, 'b');\n          assert.equal(stamped1[4].itemaProp, 'c');\n          primitive.shift('items');\n          primitive.push('items', 'd');\n          primitive.shift('items');\n          primitive.push('items', 'e');\n          setTimeout(function() {\n            stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n            assert.equal(stamped1[0].itemaProp, 'a');\n            assert.equal(stamped1[1].itemaProp, 'b');\n            assert.equal(stamped1[2].itemaProp, 'c');\n            assert.equal(stamped1[3].itemaProp, 'd');\n            assert.equal(stamped1[4].itemaProp, 'e');\n            done();\n          });\n        });\n      });\n    });\n  });\n\n  test('array sort, no filter: insertions', function(done) {\n    // repeater 1\n    var stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped1[0].itemaProp, 'a');\n    assert.equal(stamped1[1].itemaProp, 'b');\n    assert.equal(stamped1[2].itemaProp, 'c');\n    assert.equal(stamped1[3].itemaProp, 'd');\n    assert.equal(stamped1[4].itemaProp, 'e');\n    primitive.splice('items', 1, 0, 'new2', 'new3');\n    primitive.splice('items', 0, 0, 'new1');\n    primitive.splice('items', 8, 0, 'new5');\n    primitive.splice('items', 5, 0, 'new4');\n    setTimeout(function() {\n      stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1[0].itemaProp, 'new1');\n      assert.equal(stamped1[1].itemaProp, 'a');\n      assert.equal(stamped1[2].itemaProp, 'new2');\n      assert.equal(stamped1[3].itemaProp, 'new3');\n      assert.equal(stamped1[4].itemaProp, 'b');\n      assert.equal(stamped1[5].itemaProp, 'new4');\n      assert.equal(stamped1[6].itemaProp, 'c');\n      assert.equal(stamped1[7].itemaProp, 'd');\n      assert.equal(stamped1[8].itemaProp, 'e');\n      assert.equal(stamped1[9].itemaProp, 'new5');\n      arrayDelete(primitive, 'items',  'new5');\n      arrayDelete(primitive, 'items',  'new3');\n      arrayDelete(primitive, 'items',  'new1');\n      arrayDelete(primitive, 'items',  'new2');\n      arrayDelete(primitive, 'items',  'new4');\n      setTimeout(function() {\n        stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n        assert.equal(stamped1[0].itemaProp, 'a');\n        assert.equal(stamped1[1].itemaProp, 'b');\n        assert.equal(stamped1[2].itemaProp, 'c');\n        assert.equal(stamped1[3].itemaProp, 'd');\n        assert.equal(stamped1[4].itemaProp, 'e');\n        done();\n      });\n    });\n  });\n\n  test('array sort, no filter: insert & remove', function(done) {\n    // repeater 1\n    var stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped1[0].itemaProp, 'a');\n    assert.equal(stamped1[1].itemaProp, 'b');\n    assert.equal(stamped1[2].itemaProp, 'c');\n    assert.equal(stamped1[3].itemaProp, 'd');\n    assert.equal(stamped1[4].itemaProp, 'e');\n    primitive.splice('items', 1, 0, 'new1', 'new2', 'new3');\n    primitive.splice('items', 3, 1);\n    primitive.splice('items', 4, 0, 'new4', 'new5', 'new6');\n    primitive.splice('items', 4, 2);\n    primitive.splice('items', 4, 1);\n    primitive.splice('items', 1, 2);\n    setTimeout(function() {\n      stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1[0].itemaProp, 'a');\n      assert.equal(stamped1[1].itemaProp, 'b');\n      assert.equal(stamped1[2].itemaProp, 'c');\n      assert.equal(stamped1[3].itemaProp, 'd');\n      assert.equal(stamped1[4].itemaProp, 'e');\n      done();\n    });\n  });\n\n  test('array sort, filtered: unshift+pop', function(done) {\n    primitive.$.repeater1.filter = function(s) {\n      return s.indexOf('new2') < 0;\n    };\n    flush();\n    // repeater 1\n    var stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped1[0].itemaProp, 'a');\n    assert.equal(stamped1[1].itemaProp, 'b');\n    assert.equal(stamped1[2].itemaProp, 'c');\n    assert.equal(stamped1[3].itemaProp, 'd');\n    assert.equal(stamped1[4].itemaProp, 'e');\n    primitive.unshift('items', 'new1');\n    primitive.pop('items');\n    setTimeout(function() {\n      stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1[0].itemaProp, 'new1');\n      assert.equal(stamped1[1].itemaProp, 'a');\n      assert.equal(stamped1[2].itemaProp, 'b');\n      assert.equal(stamped1[3].itemaProp, 'c');\n      assert.equal(stamped1[4].itemaProp, 'd');\n      primitive.unshift('items', 'new2');\n      primitive.pop('items');\n      primitive.unshift('items', 'new3');\n      primitive.pop('items');\n      setTimeout(function() {\n        stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n        assert.equal(stamped1[0].itemaProp, 'new3');\n        assert.equal(stamped1[1].itemaProp, 'new1');\n        assert.equal(stamped1[2].itemaProp, 'a');\n        assert.equal(stamped1[3].itemaProp, 'b');\n        primitive.shift('items');\n        primitive.push('items', 'c');\n        setTimeout(function() {\n          stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n          assert.equal(stamped1[0].itemaProp, 'new1');\n          assert.equal(stamped1[1].itemaProp, 'a');\n          assert.equal(stamped1[2].itemaProp, 'b');\n          assert.equal(stamped1[3].itemaProp, 'c');\n          primitive.shift('items');\n          primitive.push('items', 'd');\n          primitive.shift('items');\n          primitive.push('items', 'e');\n          setTimeout(function() {\n            stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n            assert.equal(stamped1[0].itemaProp, 'a');\n            assert.equal(stamped1[1].itemaProp, 'b');\n            assert.equal(stamped1[2].itemaProp, 'c');\n            assert.equal(stamped1[3].itemaProp, 'd');\n            assert.equal(stamped1[4].itemaProp, 'e');\n            done();\n          });\n        });\n      });\n    });\n  });\n\n  test('array sort, filtered: insertions', function(done) {\n    // repeater 1\n    primitive.$.repeater1.filter = function(s) {\n      return s.indexOf('new2') < 0;\n    };\n    flush();\n    var stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped1[0].itemaProp, 'a');\n    assert.equal(stamped1[1].itemaProp, 'b');\n    assert.equal(stamped1[2].itemaProp, 'c');\n    assert.equal(stamped1[3].itemaProp, 'd');\n    assert.equal(stamped1[4].itemaProp, 'e');\n    primitive.splice('items', 1, 0, 'new2', 'new3');\n    primitive.splice('items', 0, 0, 'new1');\n    primitive.splice('items', 8, 0, 'new5');\n    primitive.splice('items', 5, 0, 'new4');\n    setTimeout(function() {\n      stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1[0].itemaProp, 'new1');\n      assert.equal(stamped1[1].itemaProp, 'a');\n      assert.equal(stamped1[2].itemaProp, 'new3');\n      assert.equal(stamped1[3].itemaProp, 'b');\n      assert.equal(stamped1[4].itemaProp, 'new4');\n      assert.equal(stamped1[5].itemaProp, 'c');\n      assert.equal(stamped1[6].itemaProp, 'd');\n      assert.equal(stamped1[7].itemaProp, 'e');\n      assert.equal(stamped1[8].itemaProp, 'new5');\n      arrayDelete(primitive, 'items',  'new5');\n      arrayDelete(primitive, 'items',  'new3');\n      arrayDelete(primitive, 'items',  'new1');\n      arrayDelete(primitive, 'items',  'new2');\n      arrayDelete(primitive, 'items',  'new4');\n      setTimeout(function() {\n        stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n        assert.equal(stamped1[0].itemaProp, 'a');\n        assert.equal(stamped1[1].itemaProp, 'b');\n        assert.equal(stamped1[2].itemaProp, 'c');\n        assert.equal(stamped1[3].itemaProp, 'd');\n        assert.equal(stamped1[4].itemaProp, 'e');\n        done();\n      });\n    });\n  });\n\n  test('array sort, filtered: insert & remove', function(done) {\n    // repeater 1\n    primitive.$.repeater1.filter = function(s) {\n      return s.indexOf('new2') < 0;\n    };\n    flush();\n    var stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped1[0].itemaProp, 'a');\n    assert.equal(stamped1[1].itemaProp, 'b');\n    assert.equal(stamped1[2].itemaProp, 'c');\n    assert.equal(stamped1[3].itemaProp, 'd');\n    assert.equal(stamped1[4].itemaProp, 'e');\n    primitive.splice('items', 1, 0, 'new1', 'new2', 'new3');\n    primitive.splice('items', 3, 1);\n    primitive.splice('items', 4, 0, 'new4', 'new5', 'new6');\n    primitive.splice('items', 4, 2);\n    primitive.splice('items', 4, 1);\n    primitive.splice('items', 1, 2);\n    primitive.$.repeater1.filter = null;\n    setTimeout(function() {\n      stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1[0].itemaProp, 'a');\n      assert.equal(stamped1[1].itemaProp, 'b');\n      assert.equal(stamped1[2].itemaProp, 'c');\n      assert.equal(stamped1[3].itemaProp, 'd');\n      assert.equal(stamped1[4].itemaProp, 'e');\n      done();\n    });\n  });\n\n  test('view sort, no filter: unshift+pop', function(done) {\n    primitive.$.repeater1.sort = function(a, b) {\n      return b.localeCompare(a);\n    };\n    flush();\n    setTimeout(function() {\n      // repeater 1\n      var stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1[0].itemaProp, 'e');\n      assert.equal(stamped1[1].itemaProp, 'd');\n      assert.equal(stamped1[2].itemaProp, 'c');\n      assert.equal(stamped1[3].itemaProp, 'b');\n      assert.equal(stamped1[4].itemaProp, 'a');\n      primitive.unshift('items', 'new1');\n      primitive.pop('items');\n      setTimeout(function() {\n        stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n        assert.equal(stamped1[0].itemaProp, 'new1');\n        assert.equal(stamped1[1].itemaProp, 'd');\n        assert.equal(stamped1[2].itemaProp, 'c');\n        assert.equal(stamped1[3].itemaProp, 'b');\n        assert.equal(stamped1[4].itemaProp, 'a');\n        primitive.unshift('items', 'new2');\n        primitive.pop('items');\n        primitive.unshift('items', 'new3');\n        primitive.pop('items');\n        setTimeout(function() {\n          stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n          assert.equal(stamped1[0].itemaProp, 'new3');\n          assert.equal(stamped1[1].itemaProp, 'new2');\n          assert.equal(stamped1[2].itemaProp, 'new1');\n          assert.equal(stamped1[3].itemaProp, 'b');\n          assert.equal(stamped1[4].itemaProp, 'a');\n          primitive.shift('items');\n          primitive.push('items', 'c');\n          setTimeout(function() {\n            stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n            assert.equal(stamped1[0].itemaProp, 'new2');\n            assert.equal(stamped1[1].itemaProp, 'new1');\n            assert.equal(stamped1[2].itemaProp, 'c');\n            assert.equal(stamped1[3].itemaProp, 'b');\n            assert.equal(stamped1[4].itemaProp, 'a');\n            primitive.shift('items');\n            primitive.push('items', 'd');\n            primitive.shift('items');\n            primitive.push('items', 'e');\n            setTimeout(function() {\n              stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n              assert.equal(stamped1[0].itemaProp, 'e');\n              assert.equal(stamped1[1].itemaProp, 'd');\n              assert.equal(stamped1[2].itemaProp, 'c');\n              assert.equal(stamped1[3].itemaProp, 'b');\n              assert.equal(stamped1[4].itemaProp, 'a');\n              done();\n            });\n          });\n        });\n      });\n    });\n  });\n\n  test('view sort, no filter: insertions', function(done) {\n    // repeater 1\n    primitive.$.repeater1.sort = function(a, b) {\n      return b.localeCompare(a);\n    };\n    flush();\n    var stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped1[0].itemaProp, 'e');\n    assert.equal(stamped1[1].itemaProp, 'd');\n    assert.equal(stamped1[2].itemaProp, 'c');\n    assert.equal(stamped1[3].itemaProp, 'b');\n    assert.equal(stamped1[4].itemaProp, 'a');\n    primitive.splice('items', 1, 0, 'new2', 'new3');\n    primitive.splice('items', 0, 0, 'new1');\n    primitive.splice('items', 8, 0, 'new5');\n    primitive.splice('items', 5, 0, 'new4');\n    setTimeout(function() {\n      stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1[0].itemaProp, 'new5');\n      assert.equal(stamped1[1].itemaProp, 'new4');\n      assert.equal(stamped1[2].itemaProp, 'new3');\n      assert.equal(stamped1[3].itemaProp, 'new2');\n      assert.equal(stamped1[4].itemaProp, 'new1');\n      assert.equal(stamped1[5].itemaProp, 'e');\n      assert.equal(stamped1[6].itemaProp, 'd');\n      assert.equal(stamped1[7].itemaProp, 'c');\n      assert.equal(stamped1[8].itemaProp, 'b');\n      assert.equal(stamped1[9].itemaProp, 'a');\n      arrayDelete(primitive, 'items',  'new5');\n      arrayDelete(primitive, 'items',  'new3');\n      arrayDelete(primitive, 'items',  'new1');\n      arrayDelete(primitive, 'items',  'new2');\n      arrayDelete(primitive, 'items',  'new4');\n      setTimeout(function() {\n        stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n        assert.equal(stamped1[0].itemaProp, 'e');\n        assert.equal(stamped1[1].itemaProp, 'd');\n        assert.equal(stamped1[2].itemaProp, 'c');\n        assert.equal(stamped1[3].itemaProp, 'b');\n        assert.equal(stamped1[4].itemaProp, 'a');\n        done();\n      });\n    });\n  });\n\n  test('view sort, no filter: insert & remove', function(done) {\n    // repeater 1\n    primitive.$.repeater1.sort = function(a, b) {\n      return b.localeCompare(a);\n    };\n    flush();\n    var stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped1[0].itemaProp, 'e');\n    assert.equal(stamped1[1].itemaProp, 'd');\n    assert.equal(stamped1[2].itemaProp, 'c');\n    assert.equal(stamped1[3].itemaProp, 'b');\n    assert.equal(stamped1[4].itemaProp, 'a');\n    primitive.splice('items', 1, 0, 'new1', 'new2', 'new3');\n    primitive.splice('items', 3, 1);\n    primitive.splice('items', 4, 0, 'new4', 'new5', 'new6');\n    primitive.splice('items', 4, 2);\n    primitive.splice('items', 4, 1);\n    primitive.splice('items', 1, 2);\n    setTimeout(function() {\n      stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1[0].itemaProp, 'e');\n      assert.equal(stamped1[1].itemaProp, 'd');\n      assert.equal(stamped1[2].itemaProp, 'c');\n      assert.equal(stamped1[3].itemaProp, 'b');\n      assert.equal(stamped1[4].itemaProp, 'a');\n      done();\n    });\n  });\n\n  test('view sort, filtered: unshift+pop', function(done) {\n    primitive.$.repeater1.sort = function(a, b) {\n      return b.localeCompare(a);\n    };\n    primitive.$.repeater1.filter = function(s) {\n      return s.indexOf('new2') < 0;\n    };\n    flush();\n    setTimeout(function() {\n      // repeater 1\n      var stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1[0].itemaProp, 'e');\n      assert.equal(stamped1[1].itemaProp, 'd');\n      assert.equal(stamped1[2].itemaProp, 'c');\n      assert.equal(stamped1[3].itemaProp, 'b');\n      assert.equal(stamped1[4].itemaProp, 'a');\n      primitive.unshift('items', 'new1');\n      primitive.pop('items');\n      setTimeout(function() {\n        stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n        assert.equal(stamped1[0].itemaProp, 'new1');\n        assert.equal(stamped1[1].itemaProp, 'd');\n        assert.equal(stamped1[2].itemaProp, 'c');\n        assert.equal(stamped1[3].itemaProp, 'b');\n        assert.equal(stamped1[4].itemaProp, 'a');\n        primitive.unshift('items', 'new2');\n        primitive.pop('items');\n        primitive.unshift('items', 'new3');\n        primitive.pop('items');\n        setTimeout(function() {\n          stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n          assert.equal(stamped1[0].itemaProp, 'new3');\n          assert.equal(stamped1[1].itemaProp, 'new1');\n          assert.equal(stamped1[2].itemaProp, 'b');\n          assert.equal(stamped1[3].itemaProp, 'a');\n          primitive.shift('items');\n          primitive.push('items', 'c');\n          setTimeout(function() {\n            stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n            assert.equal(stamped1[0].itemaProp, 'new1');\n            assert.equal(stamped1[1].itemaProp, 'c');\n            assert.equal(stamped1[2].itemaProp, 'b');\n            assert.equal(stamped1[3].itemaProp, 'a');\n            primitive.shift('items');\n            primitive.push('items', 'd');\n            primitive.shift('items');\n            primitive.push('items', 'e');\n            setTimeout(function() {\n              stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n              assert.equal(stamped1[0].itemaProp, 'e');\n              assert.equal(stamped1[1].itemaProp, 'd');\n              assert.equal(stamped1[2].itemaProp, 'c');\n              assert.equal(stamped1[3].itemaProp, 'b');\n              assert.equal(stamped1[4].itemaProp, 'a');\n              done();\n            });\n          });\n        });\n      });\n    });\n  });\n\n  test('view sort, filtered: insertions', function(done) {\n    // repeater 1\n    primitive.$.repeater1.sort = function(a, b) {\n      return b.localeCompare(a);\n    };\n    primitive.$.repeater1.filter = function(s) {\n      return s.indexOf('new2') < 0;\n    };\n    flush();\n    var stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped1[0].itemaProp, 'e');\n    assert.equal(stamped1[1].itemaProp, 'd');\n    assert.equal(stamped1[2].itemaProp, 'c');\n    assert.equal(stamped1[3].itemaProp, 'b');\n    assert.equal(stamped1[4].itemaProp, 'a');\n    primitive.splice('items', 1, 0, 'new2', 'new3');\n    primitive.splice('items', 0, 0, 'new1');\n    primitive.splice('items', 8, 0, 'new5');\n    primitive.splice('items', 5, 0, 'new4');\n    setTimeout(function() {\n      stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1[0].itemaProp, 'new5');\n      assert.equal(stamped1[1].itemaProp, 'new4');\n      assert.equal(stamped1[2].itemaProp, 'new3');\n      assert.equal(stamped1[3].itemaProp, 'new1');\n      assert.equal(stamped1[4].itemaProp, 'e');\n      assert.equal(stamped1[5].itemaProp, 'd');\n      assert.equal(stamped1[6].itemaProp, 'c');\n      assert.equal(stamped1[7].itemaProp, 'b');\n      assert.equal(stamped1[8].itemaProp, 'a');\n      arrayDelete(primitive, 'items',  'new5');\n      arrayDelete(primitive, 'items',  'new3');\n      arrayDelete(primitive, 'items',  'new1');\n      arrayDelete(primitive, 'items',  'new2');\n      arrayDelete(primitive, 'items',  'new4');\n      setTimeout(function() {\n        stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n        assert.equal(stamped1[0].itemaProp, 'e');\n        assert.equal(stamped1[1].itemaProp, 'd');\n        assert.equal(stamped1[2].itemaProp, 'c');\n        assert.equal(stamped1[3].itemaProp, 'b');\n        assert.equal(stamped1[4].itemaProp, 'a');\n        done();\n      });\n    });\n  });\n\n  test('view sort, no filter: insert & remove', function(done) {\n    // repeater 1\n    primitive.$.repeater1.sort = function(a, b) {\n      return b.localeCompare(a);\n    };\n    flush();\n    var stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped1[0].itemaProp, 'e');\n    assert.equal(stamped1[1].itemaProp, 'd');\n    assert.equal(stamped1[2].itemaProp, 'c');\n    assert.equal(stamped1[3].itemaProp, 'b');\n    assert.equal(stamped1[4].itemaProp, 'a');\n    primitive.splice('items', 1, 0, 'new1', 'new2', 'new3');\n    primitive.splice('items', 3, 1);\n    primitive.splice('items', 4, 0, 'new4', 'new5', 'new6');\n    primitive.splice('items', 4, 2);\n    primitive.splice('items', 4, 1);\n    primitive.splice('items', 1, 2);\n    setTimeout(function() {\n      stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped1[0].itemaProp, 'e');\n      assert.equal(stamped1[1].itemaProp, 'd');\n      assert.equal(stamped1[2].itemaProp, 'c');\n      assert.equal(stamped1[3].itemaProp, 'b');\n      assert.equal(stamped1[4].itemaProp, 'a');\n      primitive.$.repeater1.filter = null;\n      primitive.$.repeater1.sort = null;\n      setTimeout(function() {\n        stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n        assert.equal(stamped1[0].itemaProp, 'a');\n        assert.equal(stamped1[1].itemaProp, 'b');\n        assert.equal(stamped1[2].itemaProp, 'c');\n        assert.equal(stamped1[3].itemaProp, 'd');\n        assert.equal(stamped1[4].itemaProp, 'e');\n        done();\n      });\n    });\n  });\n\n});\n\nsuite('item changing on instance', function() {\n\n  let primitive;\n\n  setup(function() {\n    primitive = fixture('primitive');\n    flush();\n  });\n\n  test('primitive values - initial stamping', function() {\n    // repeater 1\n    var stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped1[0].itemaProp, 'a');\n    assert.equal(stamped1[1].itemaProp, 'b');\n    assert.equal(stamped1[2].itemaProp, 'c');\n    assert.equal(stamped1[3].itemaProp, 'd');\n    assert.equal(stamped1[4].itemaProp, 'e');\n    // repeater 2\n    var stamped2 = primitive.$.container2.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped2[0].itemaProp, 'a');\n    assert.equal(stamped2[1].itemaProp, 'b');\n    assert.equal(stamped2[2].itemaProp, 'c');\n    assert.equal(stamped2[3].itemaProp, 'd');\n    assert.equal(stamped2[4].itemaProp, 'e');\n  });\n\n  test('primitive values - change from inside', function() {\n    var stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n    var stamped2 = primitive.$.container2.querySelectorAll('*:not(template):not(dom-repeat)');\n    var old = stamped1[2].itemaProp;\n    // Change middle item\n    stamped1[2].itemaProp = 'change!';\n    assert.equal(primitive.items[2], 'change!');\n    assert.equal(stamped2[2].itemaProp, 'change!');\n    // Revert\n    stamped2[2].itemaProp = old;\n    assert.equal(primitive.items[2], 'c');\n    assert.equal(stamped1[2].itemaProp, 'c');\n  });\n\n  test('primitive values - sorted', function() {\n    // Apply sort\n    primitive.$.repeater1.sort = function(a, b) {\n      return b.localeCompare(a);\n    };\n    primitive.$.repeater1.render();\n    var stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n    var stamped2 = primitive.$.container2.querySelectorAll('*:not(template):not(dom-repeat)');\n    var old = stamped1[0].itemaProp;\n    // Change last item (first rendered in #1, last rendered in #2)\n    stamped1[0].itemaProp = 'change!';\n    assert.equal(primitive.items[4], 'change!');\n    assert.equal(stamped2[4].itemaProp, 'change!');\n    // Revert\n    stamped2[4].itemaProp = old;\n    assert.equal(primitive.items[4], 'e');\n    assert.equal(stamped1[0].itemaProp, 'e');\n    primitive.$.repeater1.sort = null;\n    primitive.$.repeater1.render();\n  });\n\n  test('structured values - initial stamping', function() {\n    let unconfigured = fixture('unconfigured');\n    unconfigured.items = window.getData();\n    flush();\n    var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    var stamped2 = unconfigured.$.el2.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped1[0].itemaProp, 'prop-1');\n    assert.equal(stamped2[0].itemaProp, 'prop-1');\n  });\n\n  test('structured values - change from inside', function() {\n    let unconfigured = fixture('unconfigured');\n    unconfigured.items = window.getData();\n    flush();\n    var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    var stamped2 = unconfigured.$.el2.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    var old = unconfigured.items[0];\n    // Change first item\n    unconfigured.$.el1.$.repeater.__instances[0].itema = {prop: 'change!'};\n    assert.equal(stamped1[0].itemaProp, 'change!');\n    assert.equal(stamped2[0].itemaProp, 'change!');\n    // Revert\n    unconfigured.$.el2.$.repeater.__instances[0].itema = old;\n    assert.equal(stamped1[0].itemaProp, 'prop-1');\n    assert.equal(stamped2[0].itemaProp, 'prop-1');\n  });\n\n  test('structured values - sorted', function() {\n    let unconfigured = fixture('unconfigured');\n    unconfigured.items = window.getData();\n    flush();\n    unconfigured.$.el1.$.repeater.sort = function(a, b) {\n      return b.prop == a.prop ? 0 : b.prop < a.prop ? -1 : 1;\n    };\n    unconfigured.$.el1.$.repeater.render();\n    var stamped1 = unconfigured.$.el1.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    var stamped2 = unconfigured.$.el2.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped1[26].itemaProp, 'prop-1');\n    assert.equal(stamped2[26].itemaProp, 'prop-3');\n    var old = unconfigured.items[2];\n    // Change last item (first rendered in #1, last rendered in #2)\n    // (but only because `observe` doesn't catch this and cause the list to\n    // re-sort; if it was, stamped1[26] should change)\n    unconfigured.$.el1.$.repeater.__instances[0].itema = {prop: 'change!'};\n    assert.equal(stamped1[0].itemaProp, 'change!');\n    assert.equal(stamped2[26].itemaProp, 'change!');\n    // Revert\n    unconfigured.$.el2.$.repeater.__instances[2].itema = old;\n    assert.equal(stamped1[0].itemaProp, 'prop-3');\n    assert.equal(stamped2[26].itemaProp, 'prop-3');\n    unconfigured.$.el1.$.repeater.sort = null;\n    unconfigured.$.el1.$.repeater.render();\n  });\n\n});\n\nsuite('external change & notification', function() {\n\n  test('in-place sort', function(done) {\n    var items = [\n      173, 166, 145, 755, 907,\n      836, 564, 721, 540, 372,\n      244, 145, 525, 958, 595,\n      207, 103, 602, 769, 190];\n    let primitive = fixture('primitive');\n    primitive.items = items;\n    setTimeout(function() {\n      var stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n      for (var i=0; i<items.length; i++) {\n        assert.equal(stamped1[i].itemaProp, items[i]);\n      }\n      var prev = items.slice();\n      items.sort();\n      var splices = calculateSplices(items, prev);\n      var change = {\n        indexSplices: splices\n      };\n      primitive.set('items.splices', change);\n      setTimeout(function() {\n        var stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n        for (var i=0; i<items.length; i++) {\n          assert.equal(stamped1[i].itemaProp, items[i]);\n        }\n        done();\n      });\n    });\n  });\n});\n\nsuite('repeater API', function() {\n\n  let unconfigured;\n\n  setup(function() {\n    unconfigured = fixture('unconfigured');\n    unconfigured.items = window.getData();\n    flush();\n  });\n\n  test('modelForElement', function() {\n    var dom = unconfigured.$.el1.root;\n    var stamped1 = dom.querySelectorAll('*:not(template):not(dom-repeat)');\n    var repeater1 = dom.querySelector('dom-repeat[as=itema]');\n    var repeater2 = dom.querySelector('dom-repeat[as=itemb]');\n    var repeater3 = dom.querySelector('dom-repeat[as=itemc]');\n\n    let model = repeater1.modelForElement(stamped1[4]);\n    assert.equal(model.itema.prop, 'prop-1');\n\n    model = repeater2.modelForElement(stamped1[4]);\n    assert.equal(model.itema.prop, 'prop-1');\n    assert.equal(model.itemb.prop, 'prop-1-1');\n\n    model = repeater3.modelForElement(stamped1[4]);\n    assert.equal(model.itema.prop, 'prop-1');\n    assert.equal(model.itemb.prop, 'prop-1-1');\n    assert.equal(model.itemc.prop, 'prop-1-1-3');\n  });\n\n  test('event.model && parentModel', function() {\n    let el = document.createElement('x-repeat-with-if');\n    document.body.appendChild(el);\n    flush();\n    let buttons = el.shadowRoot.querySelectorAll('button');\n    let outer = el.shadowRoot.querySelector('#outer');\n    let event;\n\n    // First\n    assert.equal(buttons[0].textContent, 'a');\n    buttons[0].dispatchEvent(new CustomEvent('click', {bubbles: true}));\n    assert.equal(el.handleClick.callCount, 1);\n    event = el.handleClick.getCalls()[0].args[0];\n    assert.equal(event._target, buttons[0]);\n    assert.equal(event.model.item, el.items[0].items[0]);\n    assert.equal(event.model.item.prop, 'a');\n    assert.equal(event.model.parentModel.item, el.items[0]);\n    assert.equal(event.model.parentModel.parentModel, el);\n    assert.equal(outer.modelForElement(event._target).item, el.items[0]);\n\n    // Second\n    assert.equal(buttons[1].textContent, 'b');\n    buttons[1].dispatchEvent(new CustomEvent('click', {bubbles: true}));\n    assert.equal(el.handleClick.callCount, 2);\n    event = el.handleClick.getCalls()[1].args[0];\n    assert.equal(event._target, buttons[1]);\n    assert.equal(event.model.item, el.items[0].items[1]);\n    assert.equal(event.model.item.prop, 'b');\n    assert.equal(event.model.parentModel.item, el.items[0]);\n    assert.equal(event.model.parentModel.parentModel, el);\n    assert.equal(outer.modelForElement(event._target).item, el.items[0]);\n\n    // Third\n    assert.equal(buttons[2].textContent, 'c');\n    buttons[2].dispatchEvent(new CustomEvent('click', {bubbles: true}));\n    assert.equal(el.handleClick.callCount, 3);\n    event = el.handleClick.getCalls()[2].args[0];\n    assert.equal(event._target, buttons[2]);\n    assert.equal(event.model.item, el.items[1].items[0]);\n    assert.equal(event.model.item.prop, 'c');\n    assert.equal(event.model.parentModel.item, el.items[1]);\n    assert.equal(event.model.parentModel.parentModel, el);\n    assert.equal(outer.modelForElement(event._target).item, el.items[1]);\n\n    // Fourth\n    assert.equal(buttons[3].textContent, 'd');\n    buttons[3].dispatchEvent(new CustomEvent('click', {bubbles: true}));\n    assert.equal(el.handleClick.callCount, 4);\n    event = el.handleClick.getCalls()[3].args[0];\n    assert.equal(event._target, buttons[3]);\n    assert.equal(event.model.item, el.items[1].items[1]);\n    assert.equal(event.model.item.prop, 'd');\n    assert.equal(event.model.parentModel.item, el.items[1]);\n    assert.equal(event.model.parentModel.parentModel, el);\n    assert.equal(outer.modelForElement(event._target).item, el.items[1]);\n\n    document.body.removeChild(el);\n  });\n\n  test('indexForElement', function() {\n    var dom = unconfigured.$.el1.root;\n    var stamped1 = dom.querySelectorAll('*:not(template):not(dom-repeat)');\n    var repeater1 = dom.querySelector('dom-repeat[as=itema]');\n    var repeater2 = dom.querySelector('dom-repeat[as=itemb]');\n    var repeater3 = dom.querySelector('dom-repeat[as=itemc]');\n\n    assert.equal(repeater1.indexForElement(stamped1[4]), 0);\n    assert.equal(repeater2.indexForElement(stamped1[4]), 0);\n    assert.equal(repeater3.indexForElement(stamped1[4]), 2);\n  });\n\n  test('indexForElement', function() {\n    var dom = unconfigured.$.el1.root;\n    var stamped1 = dom.querySelectorAll('*:not(template):not(dom-repeat)');\n    var repeater1 = dom.querySelector('dom-repeat[as=itema]');\n    var repeater2 = dom.querySelector('dom-repeat[as=itemb]');\n    var repeater3 = dom.querySelector('dom-repeat[as=itemc]');\n\n    assert.equal(repeater1.itemForElement(stamped1[4]).prop, 'prop-1');\n    assert.equal(repeater2.itemForElement(stamped1[4]).prop, 'prop-1-1');\n    assert.equal(repeater3.itemForElement(stamped1[4]).prop, 'prop-1-1-3');\n  });\n\n  test('renderedItemCount', function() {\n    let primitive = fixture('primitive');\n    flush();\n    var repeater1 = primitive.$.repeater1;\n    primitive.items = [ 'a', 'b', 'c', 'd', 'e' ];\n    repeater1.render();\n    assert.equal(repeater1.renderedItemCount, 5, 'renderedItemCount is incorrect');\n    repeater1.renderedItemCount = 0;\n    assert.equal(repeater1.renderedItemCount, 5, 'renderedItemCount is writable');\n    repeater1.filter = function(item) {\n     return (item != 'a' && item != 'e');\n    };\n    repeater1.render();\n    assert.equal(repeater1.renderedItemCount, 3, 'renderedItemCount incorrect after filter');\n    // reset repeater\n    repeater1.filter = undefined;\n    repeater1.render();\n  });\n\n  test('_showHideChildren', function() {\n    // Initially all showing\n    let primitive = fixture('primitive');\n    flush();\n    var stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(getComputedStyle(stamped1[0]).display, 'block');\n    assert.equal(getComputedStyle(stamped1[1]).display, 'block');\n    assert.equal(getComputedStyle(stamped1[2]).display, 'block');\n    assert.equal(getComputedStyle(stamped1[3]).display, 'block');\n    assert.equal(getComputedStyle(stamped1[4]).display, 'block');\n\n    // Hide all\n    primitive.$.repeater1.__hideTemplateChildren__ = true;\n    primitive.$.repeater1._showHideChildren(true);\n    assert.equal(getComputedStyle(stamped1[0]).display, 'none');\n    assert.equal(getComputedStyle(stamped1[1]).display, 'none');\n    assert.equal(getComputedStyle(stamped1[2]).display, 'none');\n    assert.equal(getComputedStyle(stamped1[3]).display, 'none');\n    assert.equal(getComputedStyle(stamped1[4]).display, 'none');\n\n    // Add one while hidden\n    primitive.push('items', 'new 1');\n    primitive.$.repeater1.render();\n    stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(getComputedStyle(stamped1[0]).display, 'none');\n    assert.equal(getComputedStyle(stamped1[1]).display, 'none');\n    assert.equal(getComputedStyle(stamped1[2]).display, 'none');\n    assert.equal(getComputedStyle(stamped1[3]).display, 'none');\n    assert.equal(getComputedStyle(stamped1[4]).display, 'none');\n    assert.equal(getComputedStyle(stamped1[5]).display, 'none');\n\n    // Add one then unhide\n    primitive.push('items', 'new 2');\n    primitive.$.repeater1.__hideTemplateChildren__ = false;\n    primitive.$.repeater1._showHideChildren(false);\n    primitive.$.repeater1.render();\n    stamped1 = primitive.$.container1.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(getComputedStyle(stamped1[0]).display, 'block');\n    assert.equal(getComputedStyle(stamped1[1]).display, 'block');\n    assert.equal(getComputedStyle(stamped1[2]).display, 'block');\n    assert.equal(getComputedStyle(stamped1[3]).display, 'block');\n    assert.equal(getComputedStyle(stamped1[4]).display, 'block');\n    assert.equal(getComputedStyle(stamped1[5]).display, 'block');\n    assert.equal(getComputedStyle(stamped1[6]).display, 'block');\n\n    // Revert\n    primitive.splice('items', 5, 2);\n    primitive.$.repeater1.render();\n  });\n\n});\n\n\nsuite('limit', function() {\n\n  // These tests verify correct operation of e.g. path notifications for a\n  // pertially rendered list; it does this by monkey-patching the internal\n  // `__calculateLimit` method to force the list to a certain length.\n  // While they rely on some internal implementation details, the tests are\n  // done this way because getting the list in a certain known state\n  // during live chunking is tricky due to the feedback-based throttling.\n\n  suiteSetup(() => {\n    limited.$.repeater.__calculateLimit = function() {\n      return this.__limit;\n    };\n  });\n\n  suite('basic', function() {\n\n    var checkItemOrder = function(stamped) {\n      for (var i=0; i<stamped.length; i++) {\n        assert.equal(parseInt(stamped[i].textContent), i);\n      }\n    };\n\n    test('initial limit', function() {\n      limited.items = limited.preppedItems;\n      limited.$.repeater.__limit = 2;\n      limited.$.repeater.render();\n      var stamped = limited.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 2);\n      checkItemOrder(stamped);\n    });\n\n    test('change item paths in & out of limit', function() {\n      var stamped = limited.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      limited.outerProp = {prop: 'changed'};\n      assert.equal(stamped[0].prop, 'changed');\n      limited.set('items.0.prop', '0-changed');\n      limited.set('items.3.prop', '3-changed');\n      assert.equal(stamped[0].textContent, '0-changed');\n      limited.set('outerProp.prop', 'changed again');\n      assert.equal(stamped[0].prop, 'changed again');\n    });\n\n    test('increase limit', function() {\n      // Increase limit\n      limited.$.repeater.__limit = 10;\n      limited.$.repeater.render();\n      var stamped = limited.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 10);\n      checkItemOrder(stamped);\n      assert.equal(stamped[3].prop, 'changed again');\n      assert.equal(stamped[3].textContent, '3-changed');\n      limited.set('items.0.prop', 0);\n      limited.set('items.3.prop', 3);\n      // Increase limit\n      limited.$.repeater.__limit = 20;\n      limited.$.repeater.render();\n      stamped = limited.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 20);\n      checkItemOrder(stamped);\n    });\n\n    test('decrease limit', function() {\n      // Decrease limit\n      limited.$.repeater.__limit = 15;\n      limited.$.repeater.render();\n      var stamped = limited.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 15);\n      checkItemOrder(stamped);\n      // Decrease limit\n      limited.$.repeater.__limit = 0;\n      limited.$.repeater.render();\n      stamped = limited.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 0);\n    });\n\n    test('negative limit', function() {\n      limited.$.repeater.__limit = -10;\n      limited.$.repeater.render();\n      var stamped = limited.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 0);\n    });\n\n  });\n\n  suite('limit with sort', function() {\n\n    var checkItemOrder = function(stamped) {\n      for (var i=0; i<stamped.length; i++) {\n        assert.equal(stamped[i].textContent, 19 - i);\n      }\n    };\n\n    test('initial limit', function() {\n      limited.$.repeater.__limit = 2;\n      limited.$.repeater.sort = function(a, b) {\n        return b.prop - a.prop;\n      };\n      limited.items = null;\n      limited.$.repeater.render();\n      limited.items = limited.preppedItems;\n      limited.$.repeater.render();\n      var stamped = limited.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 2);\n      checkItemOrder(stamped);\n    });\n\n    test('increase limit', function() {\n      // Increase limit\n      limited.$.repeater.__limit = 10;\n      limited.$.repeater.render();\n      var stamped = limited.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 10);\n      checkItemOrder(stamped);\n      // Increase limit\n      limited.$.repeater.__limit = 20;\n      limited.$.repeater.render();\n      stamped = limited.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 20);\n      checkItemOrder(stamped);\n    });\n\n    test('decrease limit', function() {\n      // Decrease limit\n      limited.$.repeater.__limit = 15;\n      limited.$.repeater.render();\n      var stamped = limited.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 15);\n      checkItemOrder(stamped);\n      // Decrease limit\n      limited.$.repeater.__limit = 0;\n      limited.$.repeater.render();\n      stamped = limited.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 0);\n    });\n\n    test('negative limit', function() {\n      limited.$.repeater.__limit = -10;\n      limited.$.repeater.render();\n      var stamped = limited.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 0);\n    });\n\n  });\n\n  suite('limit with filter', function() {\n\n    var checkItemOrder = function(stamped) {\n      for (var i=0; i<stamped.length; i++) {\n        assert.equal(stamped[i].textContent, i * 2);\n      }\n    };\n\n    test('initial limit', function() {\n      var items = limited.items;\n      limited.$.repeater.__limit = 2;\n      limited.$.repeater.sort = null;\n      limited.$.repeater.filter = function(a) {\n        return (a.prop % 2) === 0;\n      };\n      limited.items = null;\n      limited.$.repeater.render();\n      limited.items = items;\n      limited.$.repeater.render();\n      var stamped = limited.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 2);\n      checkItemOrder(stamped);\n    });\n\n    test('increase limit', function() {\n      // Increase limit\n      limited.$.repeater.__limit = 5;\n      limited.$.repeater.render();\n      var stamped = limited.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 5);\n      checkItemOrder(stamped);\n      // Increase limit\n      limited.$.repeater.__limit = 10;\n      limited.$.repeater.render();\n      stamped = limited.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 10);\n      checkItemOrder(stamped);\n    });\n\n    test('decrease limit', function() {\n      // Decrease limit\n      limited.$.repeater.__limit = 5;\n      limited.$.repeater.render();\n      var stamped = limited.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 5);\n      checkItemOrder(stamped);\n      // Decrease limit\n      limited.$.repeater.__limit = 0;\n      limited.$.repeater.render();\n      stamped = limited.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 0);\n    });\n\n    test('negative limit', function() {\n      limited.$.repeater.__limit = -10;\n      limited.$.repeater.render();\n      var stamped = limited.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 0);\n    });\n\n  });\n\n  suite('limit with sort & filter', function() {\n\n    var checkItemOrder = function(stamped) {\n      for (var i=0; i<stamped.length; i++) {\n        assert.equal(stamped[i].textContent, (9 - i) * 2);\n      }\n    };\n\n    test('initial limit', function() {\n      var items = limited.items;\n      limited.$.repeater.__limit = 2;\n      limited.$.repeater.sort = function(a, b) {\n        return b.prop - a.prop;\n      };\n      limited.$.repeater.filter = function(a) {\n        return (a.prop % 2) === 0;\n      };\n      limited.items = null;\n      limited.$.repeater.render();\n      limited.items = items;\n      limited.$.repeater.render();\n      var stamped = limited.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 2);\n      checkItemOrder(stamped);\n    });\n\n    test('increase limit', function() {\n      // Increase limit\n      limited.$.repeater.__limit = 5;\n      limited.$.repeater.render();\n      var stamped = limited.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 5);\n      checkItemOrder(stamped);\n      // Increase limit\n      limited.$.repeater.__limit = 10;\n      limited.$.repeater.render();\n      stamped = limited.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 10);\n      checkItemOrder(stamped);\n    });\n\n    test('decrease limit', function() {\n      // Decrease limit\n      limited.$.repeater.__limit = 5;\n      limited.$.repeater.render();\n      var stamped = limited.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 5);\n      checkItemOrder(stamped);\n      // Decrease limit\n      limited.$.repeater.__limit = 0;\n      limited.$.repeater.render();\n      stamped = limited.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 0);\n    });\n\n    test('negative limit', function() {\n      limited.$.repeater.__limit = -10;\n      limited.$.repeater.render();\n      var stamped = limited.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 0);\n    });\n\n  });\n\n});\n\nsuite('chunked rendering', function() {\n\n  let chunked;\n  let notifyChange;\n  let targetCount;\n  const handleChange = () => {\n    if (!targetCount || chunked.$.repeater.renderedItemCount >= targetCount) {\n      notifyChange(Array.from(chunked.root.querySelectorAll('*:not(template):not(dom-repeat)')));\n    }\n  };\n  const waitUntilRendered = async (count) => {\n    targetCount = count;\n    return await new Promise(r => notifyChange = r);\n  };\n  const expectNoChanges = async () => {\n    targetCount = null;\n    notifyChange = () => {\n      assert.fail('no changes were expected');\n    };\n    // Ensure no changes happen in the next rAF+sT\n    await new Promise(r => requestAnimationFrame(() => setTimeout(() => r())));\n  };\n  setup(() => {\n    chunked = document.createElement('x-repeat-chunked');\n    chunked.addEventListener('dom-change', handleChange);\n    document.body.appendChild(chunked);\n  });\n  teardown(() => {\n    chunked.removeEventListener('dom-change', handleChange);\n    document.body.removeChild(chunked);\n    chunked = null;\n  });\n\n  // Framerate=25, element cost = 4ms: should never make more than\n  // (1000/25) / 4 = 10 elements per frame\n  const MAX_PER_FRAME = (1000 / 25) / 4;\n\n  test('basic chunked rendering', async () => {\n\n    var checkItemOrder = function(stamped) {\n      for (var i=0; i<stamped.length; i++) {\n        assert.equal(stamped[i].textContent, i);\n      }\n    };\n\n    // Set items to chunk\n    chunked.items = chunked.preppedItems.slice();\n\n    let stamped = [];\n    let lastStamped;\n    let frameCount = 0;\n    // Loop until chunking is complete\n    while (stamped.length < chunked.items.length) {\n      frameCount++;\n      stamped = await waitUntilRendered();\n      checkItemOrder(stamped);\n      if (!lastStamped) {\n        // Initial rendering of initial count\n        assert.equal(stamped.length, 10);\n      } else {\n        // Remaining rendering increments\n        assert.isTrue(stamped.length > lastStamped.length,\n          'list instance count should increase each frame');\n        assert.deepEqual(lastStamped, stamped.slice(0, lastStamped.length),\n          'list should not re-render instances during mutation');\n        assert.isAtMost((stamped.length - lastStamped.length), MAX_PER_FRAME,\n          `list should not render more than ${MAX_PER_FRAME} per frame`);\n      }\n      lastStamped = stamped;\n    }\n    // Final rendering at exact item count\n    assert.equal(stamped.length, 100, 'final count wrong');\n    assert.isAtLeast(frameCount, 10, 'should have taken at least 10 frames to render');\n    \n    // Set less than initial count, should trim list in one frame\n    chunked.items = chunked.preppedItems.slice(0, 5);\n    stamped = await waitUntilRendered();\n    assert.equal(stamped.length, 5, 'final count wrong');\n    assert.deepEqual(lastStamped.slice(0, stamped.length), stamped,\n      'list should not re-render instances during mutation');\n    lastStamped = stamped;\n\n    // Set at initial count, should render in one frame\n    chunked.items = chunked.preppedItems.slice(0, 10);\n    stamped = await waitUntilRendered();\n    assert.equal(stamped.length, 10, 'final count wrong');\n    assert.deepEqual(lastStamped, stamped.slice(0, lastStamped.length),\n      'list should not re-render instances during mutation');\n    lastStamped = stamped;\n\n    // Set over initial count, should render in more than one frame\n    chunked.items = chunked.preppedItems.slice(0, 10 + MAX_PER_FRAME * 2);\n    stamped = await waitUntilRendered();\n    assert.deepEqual(lastStamped, stamped.slice(0, 10),\n      'list should not re-render instances during mutation');\n    frameCount = 0;\n    while (stamped.length < chunked.items.length) {\n      stamped = await waitUntilRendered();\n      frameCount++;\n    }\n    assert.isAtLeast(frameCount, 2, 'should have taken at least 2 frames to render');\n    assert.equal(stamped.length, chunked.items.length, 'final count wrong');\n\n  });\n\n  test('mutations during chunked rendering', async () => {\n\n    var checkItemOrder = function(stamped) {\n      var last = -1;\n      for (var i=0; i<stamped.length; i++) {\n        var curr = parseFloat(stamped[i].textContent);\n        assert.isTrue(curr > last);\n        last = curr;\n      }\n    };\n\n    var mutateArray = function(repeater, renderedCount) {\n      // The goal here is to remove & add some, and do it over\n      // the threshold of where we have currently rendered items, and\n      // ensure that the prop values of the newly inserted items are in\n      // ascending order so we can do a simple check in checkItemOrder\n      var overlap = 2;\n      var remove = 4;\n      var add = 6;\n      var start = renderedCount.length - overlap;\n      if (start + add < repeater.items.length) {\n        var end = start + remove;\n        var args = ['items', start, remove];\n        var startVal = repeater.items[start].prop;\n        var endVal = repeater.items[end].prop;\n        var delta = (endVal - startVal) / add;\n        for (var i=0; i<add; i++) {\n          args.push({prop: startVal + i*delta});\n        }\n        repeater.splice.apply(repeater, args);\n      }\n    };\n\n    // Set items to chunk\n    chunked.items = chunked.preppedItems.slice();\n\n    let stamped = [];\n    let lastStamped;\n    let frameCount = 0;\n    // Loop until chunking is complete\n    while (stamped.length < chunked.items.length) {\n      stamped = await waitUntilRendered();\n      checkItemOrder(stamped);\n      if (!lastStamped) {\n        // Initial rendering of initial count\n        assert.equal(stamped.length, 10);\n      } else {\n        // Remaining rendering increments\n        assert.isTrue(stamped.length > lastStamped.length,\n          'list instance count should increase each frame');\n        assert.deepEqual(lastStamped, stamped.slice(0, lastStamped.length),\n          'list should not re-render instances during mutation');\n        assert.isAtMost((stamped.length - lastStamped.length), MAX_PER_FRAME,\n          `list should not render more than ${MAX_PER_FRAME} per frame`);\n      }\n      if (stamped.length < chunked.items.length && frameCount < 5) {\n        mutateArray(chunked, stamped);\n      }\n      lastStamped = stamped;\n      frameCount++;\n    }\n    // Final rendering at exact item count\n    assert.equal(stamped.length, chunked.items.length, 'final count wrong');\n    assert.isAtLeast(frameCount, 10, 'should have taken at least 10 frames to render');\n\n  });\n\n\n  test('mutations during chunked rendering, sort & filtered', async () => {\n\n    var checkItemOrder = function(stamped) {\n      var last = Infinity;\n      for (var i=0; i<stamped.length; i++) {\n        var curr = parseFloat(stamped[i].textContent);\n        assert.isTrue(curr <= last);\n        assert.strictEqual(curr % 2, 0);\n        last = curr;\n      }\n    };\n\n    var mutateArray = function(repeater, stamped) {\n      var start = parseInt(stamped[0].textContent);\n      var end = parseInt(stamped[stamped.length-1].textContent);\n      var mid = (end-start)/2;\n      for (var i=0; i<5; i++) {\n        chunked.push('items', {prop: mid + 1});\n      }\n      chunked.splice('items', Math.round(stamped.length/2), 3);\n    };\n\n    // Set items to chunk\n    chunked.$.repeater.sort = function(a, b) {\n      return b.prop - a.prop;\n    };\n    chunked.$.repeater.filter = function(a) {\n      return (a.prop % 2) === 0;\n    };\n    chunked.items = chunked.preppedItems.slice();\n\n    let stamped = [];\n    let lastStamped;\n    let frameCount = 0;\n    let filteredLength = chunked.items.filter(chunked.$.repeater.filter).length;\n    // Loop until chunking is complete\n    while (stamped.length < filteredLength) {\n      stamped = await waitUntilRendered();\n      checkItemOrder(stamped);\n      if (!lastStamped) {\n        // Initial rendering of initial count\n        assert.equal(stamped.length, 10);\n      } else {\n        // Remaining rendering increments\n        assert.isTrue(stamped.length > lastStamped.length,\n          'list instance count should increase each frame');\n        assert.deepEqual(lastStamped, stamped.slice(0, lastStamped.length),\n          'list should not re-render instances during mutation');\n        assert.isAtMost((stamped.length - lastStamped.length), MAX_PER_FRAME,\n          `list should not render more than ${MAX_PER_FRAME} per frame`);\n      }\n      if (stamped.length < chunked.items.length && frameCount < 4) {\n        mutateArray(chunked, stamped);\n        filteredLength = chunked.items.filter(chunked.$.repeater.filter).length;\n      }\n      lastStamped = stamped;\n      frameCount++;\n    }\n    // Final rendering at exact item count\n    assert.equal(stamped.length, filteredLength, 'final count wrong');\n    assert.isAtLeast(frameCount, 5, 'should have taken at least 5 frames to render');\n  });\n\n  suite('resetting items array', () => {\n\n    [false, true].forEach(reuse => {\n\n      test(`reuseChunkedInstances=${reuse}`, async () => {\n\n        // Set items to chunk\n        chunked.$.repeater.reuseChunkedInstances = reuse;\n        chunked.items = chunked.preppedItems.slice();\n\n        let resetCount = 3;\n        let stamped = [];\n        let lastStamped;\n        let frameCount = 0;\n        // Loop until chunking is complete\n        while (stamped.length < chunked.items.length) {\n          stamped = await waitUntilRendered();\n          if (!lastStamped) {\n            // Initial rendering of initial count\n            assert.equal(stamped.length, 10);\n          } else {\n            // Remaining rendering increments\n            assert.isTrue(stamped.length > lastStamped.length,\n              'list instance count should increase each frame');\n            assert.deepEqual(lastStamped, stamped.slice(0, lastStamped.length),\n              'list should not re-render instances during mutation');\n            assert.isAtMost((stamped.length - lastStamped.length), MAX_PER_FRAME,\n              `list should not render more than ${MAX_PER_FRAME} per frame`);\n          }\n          lastStamped = stamped;\n          frameCount++;\n          if (--resetCount > 0) {\n            if (!reuse) {\n              lastStamped = null;\n            }\n            chunked.items = chunked.preppedItems.slice();\n          }\n        }\n        // Final rendering at exact item count\n        assert.equal(stamped.length, chunked.items.length, 'final count wrong');\n        assert.isAtLeast(frameCount, 5, 'should have taken at least 5 frames to render');\n        \n      });\n\n    });\n\n  });\n\n  test('changing to/from initialCount=0', async () => {\n    // Render all\n    chunked.items = chunked.preppedItems.slice();\n    let stamped = await waitUntilRendered(chunked.preppedItems.length);\n    assert.equal(stamped.length, chunked.preppedItems.length);\n    // Clear the list\n    chunked.items = [];\n    stamped = await waitUntilRendered(0);\n    assert.equal(stamped.length, 0);\n    // Disable chunking\n    chunked.$.repeater.initialCount = 0;\n    // Render all\n    chunked.items = chunked.preppedItems.slice();\n    stamped = await waitUntilRendered(chunked.preppedItems.length);\n    assert.equal(stamped.length, chunked.preppedItems.length);\n    // Clear the list\n    chunked.items = [];\n    stamped = await waitUntilRendered(0);\n    assert.equal(stamped.length, 0);\n    // Re-enable chunking\n    chunked.$.repeater.initialCount = 10;\n    // Render all; the initial render should have the initial count, and then\n    // chunk until the end of the list\n    let frameCount = 0;\n    chunked.items = chunked.preppedItems.slice();\n    while (stamped.length < chunked.items.length) {\n      stamped = await waitUntilRendered();\n      if (frameCount === 0) {\n        assert.equal(stamped.length, 10);\n      }\n      frameCount++;\n    }\n    assert.equal(stamped.length, chunked.preppedItems.length);\n    assert.isAtLeast(frameCount, 2);\n    // Disable chunking\n    chunked.$.repeater.initialCount = 0;\n    // Render some\n    chunked.items = chunked.preppedItems.slice(0, 20);\n    stamped = await waitUntilRendered();\n    assert.equal(stamped.length, chunked.items.length);\n    // Re-enable chunking\n    chunked.$.repeater.initialCount = 10;\n    // Push remaining; these should chunk out\n    frameCount = 0;\n    chunked.push('items', ...chunked.preppedItems.slice(20));\n    while (stamped.length < chunked.items.length) {\n      stamped = await waitUntilRendered();\n      frameCount++;\n    }\n    assert.equal(stamped.length, chunked.items.length);\n    assert.isAtLeast(frameCount, 2);\n  });\n\n  test('chunking stops after detaching, restarts after attaching', async () => {\n    chunked.items = chunked.preppedItems.slice();\n    const initialLength = (await waitUntilRendered()).length;\n    assert.isAbove(initialLength, 0);\n    assert.isBelow(initialLength, chunked.preppedItems.length);\n    document.body.removeChild(chunked);\n    await expectNoChanges();\n    const done = waitUntilRendered(chunked.preppedItems.length);\n    document.body.appendChild(chunked);\n    const endLength = (await done).length;\n    assert.equal(endLength, chunked.items.length);\n  });\n\n});\n\nsuite('misc', function() {\n\n  test('large splice', function(done) {\n    let primitiveLarge = fixture('primitiveLarge');\n    flush();\n    primitiveLarge.splice('items', 0, 10);\n    setTimeout(function() {\n      var stamped =\n        primitiveLarge.root.querySelectorAll('*:not(template):not(dom-repeat)');\n      assert.equal(stamped.length, 1, 'total stamped count incorrect');\n      assert.equal(stamped[0].textContent, '10');\n      done();\n    });\n  });\n\n  test('css scoping retained when re-ordering', function() {\n    if (!window.ShadyDOM) {\n      this.skip();\n    }\n    let simple = fixture('simple');\n    flush();\n    var removed;\n    // Confirm initial scoping\n    var stamped = simple.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped[0].itemaProp, 'prop-1');\n    assert(stamped[0].classList.contains('x-simple-repeat'), 'expected scoping');\n    assert.equal(stamped.length, 3, 'total stamped count incorrect');\n    // Move\n    removed = simple.splice('items', 0, 1);\n    simple.splice('items', 1, 0, removed[0]);\n    flush();\n    stamped = simple.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped.length, 3, 'total stamped count incorrect');\n    let movedItem = simple.$.repeat.modelForElement(stamped[1]).item;\n    assert.equal(removed[0], movedItem);\n    assert.equal(stamped[1].itemaProp, 'prop-1');\n    assert(stamped[1].classList.contains('x-simple-repeat'), 'expected scoping');\n    // Revert\n    removed = simple.splice('items', 1, 1);\n    simple.splice('items', 0, 0, removed[0]);\n    flush();\n    stamped = simple.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped.length, 3, 'total stamped count incorrect');\n    movedItem = simple.$.repeat.modelForElement(stamped[0]).item;\n    assert.equal(removed[0], movedItem);\n    assert.equal(stamped[0].itemaProp, 'prop-1');\n    assert(stamped[0].classList.contains('x-simple-repeat'), 'expected scoping');\n  });\n\n  test('paths update on observed properties', function() {\n    let simple = fixture('simple');\n    flush();\n    var stamped = simple.root.querySelectorAll('*:not(template):not(dom-repeat)');\n    assert.equal(stamped[0].itemaProp, 'prop-1');\n    simple.$.repeat.observe = 'prop';\n    flush();\n    simple.set('items.0.prop', {foo: 0});\n    flush();\n    assert.equal(stamped[0].get('itemaProp.foo'), 0);\n    simple.set('items.0.prop.foo', 1);\n    flush();\n    assert.equal(stamped[0].get('itemaProp.foo'), 1);\n    simple.set('items.0.prop.foo', 2);\n    flush();\n    assert.equal(stamped[0].get('itemaProp.foo'), 2);\n  });\n});\n\nsuite('timing', function() {\n\n  test('non-upgrade case finds template', function() {\n    assert.equal(nonUpgrade.textContent.trim(), 'stamped');\n  });\n\n});\n\nsuite('dom-change composed', function() {\n\n  test('dom-change event composed, bubbles outside dom-if scope', function() {\n    var el = fixture('simple');\n    var domChangeFired = 0;\n    el.addEventListener('dom-change', function() {\n      domChangeFired++;\n    });\n    el.push('items', {prop: 'added1'});\n    flush();\n    el.push('items', {prop: 'added2'});\n    flush();\n    assert.equal(domChangeFired, 2);\n  });\n});\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/dynamic-import.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"./dynamic-imports/dynamic-element.js\"></script>\n</head>\n<body>\n\n<dynamic-element></dynamic-element>\n\n<script type=\"module\">\nimport './dynamic-imports/dynamic-element.js';\nimport { Base } from '../../polymer-legacy.js';\n\nsuite('dynamic imports', function() {\n\n  test('use importHref to load and create an element', function(done) {\n    var d = document.querySelector('dynamic-element');\n    d.whenDynamicContentReady(function() {\n      assert.isTrue(d.isAttached, true, 'dynamic element not readied');\n      assert.ok(d.$.content, 'dynamic element does not have content');\n      assert.isTrue(d.$.outer.isAttached, true, 'dynamic sub-element not readied');\n      assert.ok(d.$.outer.$.content, 'dynamic sub-element does not have content');\n      assert.isTrue(d.$.outer.$.inner.isAttached, true, 'dynamic sub-element not readied');\n      assert.ok(d.$.outer.$.inner.$.content, 'dynamic sub-element does not have content');\n      done();\n    });\n  });\n\n  suite('async/sync loading', function() {\n\n    var url = 'dynamic-imports/dynamic-element.html';\n\n    test('importHref does not cache failed results', function(done) {\n      Base.importHref('does_not_exist.html', function() {\n        throw new Error('Load handler should not be called.');\n      }, function() {\n        var link = document.head\n            .querySelector('[href=\"does_not_exist.html\"]');\n        assert.isNotOk(link, 'The link should not exist');\n        done();\n      });\n    });\n\n    test('importHref caches successful results', function(done) {\n      var targetUrl = 'dynamic-imports/async-import.html';\n\n      Base.importHref(targetUrl, function(event) {\n        var targetOne = event.target;\n        Base.importHref(targetUrl, function(event) {\n          var targetTwo = event.target;\n\n          assert.isOk(targetOne, 'Event target should be available');\n          assert.strictEqual(targetOne, targetTwo,\n              'Link element references should be identical');\n          done();\n        }, done);\n      }, done);\n    });\n\n    test('importHref sync loads by default', function(done) {\n      Base.importHref(url, function(e) {\n        assert.isFalse(e.target.hasAttribute('async'),\n                      'sync load is default');\n        done();\n      });\n    });\n\n    test('importHref sync called again, triggers load', function(done) {\n      Base.importHref(url, function() {\n        Base.importHref(url, function() {\n          done();\n        });\n      });\n    });\n\n    test('importHref async loading', function(done) {\n      Base.importHref('dynamic-imports/async-import.html', function(e) {\n        assert.isTrue(window.asyncImportLoaded, 'flag not set from import');\n        assert.isTrue(e.target.hasAttribute('async'), 'async load');\n        assert.ok(e.target.import);\n        done();\n      }, null, true);\n    });\n\n    test('importHref does not leak event listeners on load', function(done) {\n      var errorSpy = sinon.spy();\n      var loadSpy = sinon.spy(function(e) {\n        var target = e.target;\n        target.dispatchEvent(new Event('error'));\n        assert.isFalse(errorSpy.called, 'doesn\\'t trigger the error event listener');\n        setTimeout(function() {\n          loadSpy.reset();\n          target.dispatchEvent(new Event('load'));\n          assert.isFalse(loadSpy.called, 'doesn\\'t trigger the load event listener');\n          done();\n        });\n      });\n\n      Base.importHref('dynamic-imports/async-import.html', loadSpy, errorSpy, true);\n    });\n\n    test('importHref does not leak event listeners on error', function(done) {\n      var loadSpy = sinon.spy();\n      var errorSpy = sinon.spy(function(e) {\n        var target = e.target;\n        target.dispatchEvent(new Event('load'));\n        assert.isFalse(loadSpy.called, 'doesn\\'t trigger the load event listener');\n        setTimeout(function() {\n          errorSpy.reset();\n          target.dispatchEvent(new Event('error'));\n          assert.isFalse(errorSpy.called, 'doesn\\'t trigger the error event listener');\n          done();\n        });\n      });\n\n      Base.importHref('dynamic-imports/async-import-invalid.html', loadSpy, errorSpy, true);\n    });\n\n  });\n\n});\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/dynamic-imports/async-import.html",
    "content": "<!DOCTYPE html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<script>\n  window.asyncImportLoaded = true;\n</script>"
  },
  {
    "path": "test/unit/dynamic-imports/async.html",
    "content": "<!DOCTYPE html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n"
  },
  {
    "path": "test/unit/dynamic-imports/dynamic-element.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport '../../../polymer-legacy.js';\n\nimport { Polymer } from '../../../lib/legacy/polymer-fn.js';\nimport { html } from '../../../lib/utils/html-tag.js';\nimport { dom } from '../../../lib/legacy/polymer.dom.js';\nPolymer({\n  _template: html`\n    <span id=\"content\">dynamic-element</span> :\n`,\n\n  is: 'dynamic-element',\n\n  ready: function() {\n    var url = this.resolveUrl('outer-element.html');\n    this.importHref(url, function() {\n      this.$.outer = document.createElement('outer-element');\n      dom(this.root).appendChild(this.$.outer);\n      this._hasContent = true;\n      if (this._callback) {\n        this._callback();\n      }\n    }, function() {\n      assert.fail('failed to load import', url);\n    });\n  },\n\n  whenDynamicContentReady: function(callback) {\n    this._callback = callback;\n    if (this._hasContent) {\n      this._callback();\n    }\n  }\n});\n"
  },
  {
    "path": "test/unit/dynamic-imports/inner-element.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport '../../../polymer-legacy.js';\n\nimport { Polymer } from '../../../lib/legacy/polymer-fn.js';\nimport { html } from '../../../lib/utils/html-tag.js';\nPolymer({\n  _template: html`\n    <span id=\"content\">inner-element</span>\n`,\n\n  is: 'inner-element'\n});\n"
  },
  {
    "path": "test/unit/dynamic-imports/outer-element.html",
    "content": "<!DOCTYPE html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n\n<script type=\"module\" src=\"../../../polymer-legacy.js\"></script>\n<script type=\"module\" src=\"./inner-element.js\"></script>\n\n<dom-module id=\"outer-element\">\n  <template>\n    <span id=\"content\">\n      outer-element : <inner-element id=\"inner\"></inner-element>\n    </span>\n  </template>\n</dom-module>\n\n<script type=\"module\">\nimport '../../../polymer-legacy.js';\nimport './inner-element.js';\nimport { Polymer } from '../../../lib/legacy/polymer-fn.js';\nPolymer({\n  is: 'outer-element'\n});\n</script>\n"
  },
  {
    "path": "test/unit/events-elements.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport { Base } from '../../polymer-legacy.js';\n\nimport { Polymer } from '../../lib/legacy/polymer-fn.js';\nimport { html } from '../../lib/utils/html-tag.js';\nvar EventLoggerImpl = {\n  created: function() {\n    this._handled = {};\n    this._removed = [];\n  },\n  handle: function(e) {\n    const order = e._handleOrder = e._handleOrder || [];\n    order.push(this.localName);\n    this._handled[e.currentTarget.localName] = e.type;\n  },\n  unlisten: function(node, eventName, handler) {\n    this._removed.push({target: node.localName, event: eventName});\n    Base.unlisten.call(this, node, eventName, handler);\n  }\n};\nPolymer({\n  is: 'x-listeners',\n  behaviors: [EventLoggerImpl],\n  listeners: {\n    foo: 'handle',\n    bar: 'missing'\n  }\n});\nPolymer({\n  _template: html`\n    <div id=\"inner\" on-foo=\"handle\" on-bar=\"missing\"></div>\n`,\n\n  is: 'x-on',\n  behaviors: [EventLoggerImpl]\n});\nPolymer({\n  _template: html`\n      <x-listeners id=\"inner\" on-foo=\"handle\"></x-listeners>\n`,\n\n  is: 'x-order',\n  behaviors: [EventLoggerImpl]\n});\nPolymer({\n  _template: html`\n    <div id=\"inner\"></div>\n`,\n\n  is: 'x-dynamic',\n  behaviors: [EventLoggerImpl],\n\n  setup: function() {\n    this.listen(this, 'foo', 'handle');\n    this.listen(this.$.inner, 'foo', 'handle');\n    this.listen(this, 'bar', 'missing');\n    this.listen(this.$.inner, 'bar', 'missing');\n  },\n\n  teardown: function() {\n    this.unlisten(this, 'foo', 'handle');\n    this.unlisten(this.$.inner, 'foo', 'handle');\n    this.unlisten(this, 'bar', 'missing');\n    this.unlisten(this.$.inner, 'bar', 'missing');\n  }\n});\nPolymer({\n  is: 'x-double',\n  behaviors: [EventLoggerImpl],\n  ready: function() {\n    this.fooChanged = sinon.spy();\n  },\n  setup: function() {\n    this.listen(this, 'foo', 'fooChanged');\n    this.listen(this, 'foo', 'fooChanged');\n  },\n  teardown: function() {\n    this.unlisten(this, 'foo', 'fooChanged');\n  }\n});\n"
  },
  {
    "path": "test/unit/events.html",
    "content": "<!DOCTYPE html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"UTF-8\">\n\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n  <script type=\"module\" src=\"./events-elements.js\"></script>\n</head>\n<body>\n\n  <script type=\"module\">\nimport './events-elements.js';\nimport { afterNextRender } from '../../lib/utils/render-status.js';\nsuite('Event Listeners', function() {\n  var el;\n\n  suite('listeners block', function() {\n    suiteSetup(function() {\n      el = document.createElement('x-listeners');\n      document.body.appendChild(el);\n    });\n\n    suiteTeardown(function() {\n      document.body.removeChild(el);\n    });\n\n    test('fire - method exists', function() {\n      el.fire('foo');\n      assert.equal(el._handled[el.localName], 'foo');\n    });\n\n    test('fire - method missing', function() {\n      sinon.spy(console, 'warn');\n      el.fire('bar');\n      assert.isTrue(console.warn.calledOnce);\n      assert.equal(console.warn.getCall(0).args[0], 'listener method `missing` not defined');\n      console.warn.restore();\n    });\n\n  });\n\n  suite('on-*', function() {\n\n    var options;\n    suiteSetup(function() {\n      el = document.createElement('x-on');\n      document.body.appendChild(el);\n      options = {node: el.$.inner};\n    });\n\n    suiteTeardown(function() {\n      document.body.removeChild(el);\n    });\n\n    test('fire - method exists', function() {\n      el.fire('foo', {}, options);\n      assert.equal(el._handled.div, 'foo');\n      assert(!el._handled[el.localName]);\n    });\n\n    test('fire - method missing', function() {\n      sinon.spy(console, 'warn');\n      el.fire('bar', {}, options);\n      assert.isTrue(console.warn.calledOnce);\n      assert.equal(console.warn.getCall(0).args[0], 'listener method `missing` not defined');\n      console.warn.restore();\n    });\n\n  });\n\n  suite('listeners + on-*', function() {\n    suiteSetup(function() {\n      el = document.createElement('x-order');\n      document.body.appendChild(el);\n    });\n\n    suiteTeardown(function() {\n      document.body.removeChild(el);\n    });\n\n    test('listeners handled before on-* events', function() {\n      const e = el.$.inner.fire('foo', {});\n      assert.deepEqual(e._handleOrder, ['x-listeners', 'x-order']);\n    });\n\n  });\n\n  suite('dynamic', function() {\n\n    var options;\n    suiteSetup(function(done) {\n      el = document.createElement('x-dynamic');\n      document.body.appendChild(el);\n      afterNextRender(null, function() {\n        options = {node: el.$.inner};\n        done();\n      });\n    });\n\n    suiteTeardown(function() {\n      document.body.removeChild(el);\n    });\n\n    test('setup', function() {\n      assert(!el.__boundListeners, 'listeners are not bound');\n      el.setup();\n      var boundListeners = el.__boundListeners;\n      assert(boundListeners, 'listeners are bound');\n      var outerMap = boundListeners.get(el);\n      assert(outerMap, 'element events have handlers');\n      var innerMap = boundListeners.get(el.$.inner);\n      assert(innerMap, 'inner div events have handlers');\n    });\n\n    test('fire - method exists', function() {\n      el.fire('foo', {}, options);\n      assert.equal(el._handled.div, 'foo', 'inner handler');\n      assert.equal(el._handled[el.localName], 'foo', 'outer handler');\n    });\n\n    test('fire - method missing', function() {\n      sinon.spy(console, 'warn');\n      el.fire('bar', {}, options);\n      assert.isTrue(console.warn.calledTwice);\n      assert.equal(console.warn.getCall(0).args[0], 'listener method `missing` not defined');\n      assert.equal(console.warn.getCall(1).args[0], 'listener method `missing` not defined');\n      console.warn.restore();\n    });\n\n    test('teardown', function() {\n      el.teardown();\n      assert.deepEqual(el._removed[0], {target: el.localName, event: 'foo'});\n      assert.deepEqual(el._removed[1], {target: 'div', event: 'foo'});\n      assert.deepEqual(el._removed[2], {target: el.localName, event: 'bar'});\n      assert.deepEqual(el._removed[3], {target: 'div', event: 'bar'});\n    });\n  });\n\n  suite('Event Listener Cache', function() {\n    suiteSetup(function() {\n      el = document.createElement('x-double');\n      el.setup();\n      document.body.appendChild(el);\n    });\n\n    suiteTeardown(function() {\n      document.body.removeChild(el);\n    });\n\n    test('Event handler fires only once', function() {\n      el.fire('foo');\n      assert.isTrue(el.fooChanged.calledOnce, 'event should fire only once');\n    });\n\n    test('once unlistened, no handler fire', function() {\n      el.teardown();\n      el.fire('foo');\n      assert.isTrue(el.fooChanged.calledOnce, 'event should not be handled anymore');\n    });\n  });\n});\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/flattened-nodes-observer.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-element.js\"></script>\n  <script type=\"module\" src=\"../../lib/utils/flattened-nodes-observer.js\"></script>\n</head>\n<body>\n\n  <dom-module id='test-self-observe'>\n    <template>\n      <slot id=\"slot\"></slot>\n    </template>\n    <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nimport { FlattenedNodesObserver } from '../../lib/utils/flattened-nodes-observer.js';\nclass TestSelfObserve extends PolymerElement {\n  static get is() { return 'test-self-observe';}\n\n  connectedCallback() {\n    super.connectedCallback();\n    this._observer = new FlattenedNodesObserver(this, (info) => {\n      this.info = info;\n    });\n  }\n  disconnectedCallback() {\n    super.disconnectedCallback();\n    this._observer.disconnect();\n  }\n}\ncustomElements.define(TestSelfObserve.is, TestSelfObserve);\n</script>\n  </dom-module>\n\n  <dom-module id='test-static'>\n    <template>\n      <div>static</div>\n    </template>\n    <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nimport '../../lib/utils/flattened-nodes-observer.js';\nclass TestStatic extends PolymerElement {\n  static get is() { return 'test-static'; }\n}\ncustomElements.define(TestStatic.is, TestStatic);\n</script>\n  </dom-module>\n\n  <dom-module id='test-slot'>\n    <template>\n      <span id=\"slotContainer\">[<slot id=\"slot\"></slot>]</span>\n    </template>\n    <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nimport '../../lib/utils/flattened-nodes-observer.js';\nclass TestSlot extends PolymerElement {\n  static get is() { return 'test-slot'; }\n}\ncustomElements.define(TestSlot.is, TestSlot);\n</script>\n  </dom-module>\n\n  <dom-module id='test-slot1'>\n    <template>\n      <test-slot id=\"slot\"><slot></slot></test-slot>\n    </template>\n    <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nimport '../../lib/utils/flattened-nodes-observer.js';\nclass TestSlot1 extends PolymerElement {\n  static get is() { return 'test-slot1'; }\n}\ncustomElements.define(TestSlot1.is, TestSlot1);\n</script>\n  </dom-module>\n\n  <dom-module id='test-slot2'>\n    <template>\n      <test-slot1 id=\"slot\"><slot></slot></test-slot1>\n    </template>\n    <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nimport '../../lib/utils/flattened-nodes-observer.js';\nclass TestSlot2 extends PolymerElement {\n  static get is() { return 'test-slot2'; }\n}\ncustomElements.define(TestSlot2.is, TestSlot2);\n</script>\n  </dom-module>\n\n  <dom-module id='test-slot3'>\n    <template>\n      <test-slot2 id=\"slot\"><slot></slot></test-slot2>\n    </template>\n    <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nimport '../../lib/utils/flattened-nodes-observer.js';\nclass TestSlot3 extends PolymerElement {\n  static get is() { return 'test-slot3'; }\n}\ncustomElements.define(TestSlot3.is, TestSlot3);\n</script>\n  </dom-module>\n\n  <dom-module id='test-slot-raw'>\n    <template>\n      <div id=\"slot\"><slot></slot></div>\n    </template>\n    <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nimport '../../lib/utils/flattened-nodes-observer.js';\nclass TestSlotRaw extends PolymerElement {\n  static get is() { return 'test-slot-raw'; }\n}\ncustomElements.define(TestSlotRaw.is, TestSlotRaw);\n</script>\n  </dom-module>\n\n  <dom-module id='test-slot-attr'>\n    <template>\n      [<slot id=\"slot\" name=\"d\"></slot>]\n    </template>\n    <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nimport '../../lib/utils/flattened-nodes-observer.js';\nclass El extends PolymerElement {\n  static get is() { return 'test-slot-attr'; }\n}\ncustomElements.define(El.is, El);\n</script>\n  </dom-module>\n\n  <dom-module id='test-slot-attr1'>\n    <template>\n      <test-slot-attr id=\"slot\"><slot name=\"c\" slot=\"d\"></slot></test-slot-attr>\n    </template>\n    <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nimport '../../lib/utils/flattened-nodes-observer.js';\nclass El extends PolymerElement {\n  static get is() { return 'test-slot-attr1'; }\n}\ncustomElements.define(El.is, El);\n</script>\n  </dom-module>\n\n  <dom-module id='test-slot-attr2'>\n    <template>\n      <test-slot-attr1 id=\"slot\"><slot name=\"b\" slot=\"c\"></slot></test-slot-attr1>\n    </template>\n    <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nimport '../../lib/utils/flattened-nodes-observer.js';\nclass El extends PolymerElement {\n  static get is() { return 'test-slot-attr2'; }\n}\ncustomElements.define(El.is, El);\n</script>\n  </dom-module>\n\n  <dom-module id='test-slot-attr3'>\n    <template>\n      <test-slot-attr2 id=\"slot\"><slot name=\"a\" slot=\"b\"></slot></test-slot-attr2>\n    </template>\n    <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nimport '../../lib/utils/flattened-nodes-observer.js';\nclass El extends PolymerElement {\n  static get is() { return 'test-slot-attr3'; }\n}\ncustomElements.define(El.is, El);\n</script>\n  </dom-module>\n\n  <dom-module id='test-slot-attr-inside'>\n    <template>\n      <test-slot-attr3 id=\"slot\"><slot name=\"a\" slot=\"a\"></slot></test-slot-attr3>\n    </template>\n    <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nimport '../../lib/utils/flattened-nodes-observer.js';\nclass El extends PolymerElement {\n  static get is() { return 'test-slot-attr-inside'; }\n}\ncustomElements.define(El.is, El);\n</script>\n  </dom-module>\n\n\n  <test-slot><div>A</div><div>B</div></test-slot>\n\n  <test-static><div>static A</div><div>static B</div></test-static>\n\n  <div id=\"staticDiv\"></div>\n\n<script type=\"module\">\nimport '../../polymer-element.js';\nimport { FlattenedNodesObserver } from '../../lib/utils/flattened-nodes-observer.js';\n\nsuite('observeNodes', function() {\n\n  test('observe initial state of distributing element', function() {\n    var recordedA;\n    var el = document.querySelector('test-slot');\n    var observer1 = new FlattenedNodesObserver(el, function(info) {\n      recordedA = info;\n    });\n    observer1.flush();\n    assert.equal(recordedA.addedNodes.length, 2);\n    recordedA = null;\n    var recordedB;\n    var observer2 = new FlattenedNodesObserver(el, function(info) {\n      recordedB = info;\n    });\n    observer2.flush();\n    assert.equal(recordedA, null);\n    assert.equal(recordedB.addedNodes.length, 2);\n    observer1.disconnect();\n    observer2.disconnect();\n  });\n\n  test('observe initial state of non-distributing element', function() {\n    var recordedA;\n    var el = document.querySelector('test-static');\n    var observer1 = new FlattenedNodesObserver(el, function(info) {\n      recordedA = info;\n    });\n    observer1.flush();\n    assert.equal(recordedA.addedNodes.length, 2);\n    recordedA = null;\n    var recordedB;\n    var observer2 = new FlattenedNodesObserver(el, function(info) {\n      recordedB = info;\n    });\n    observer2.flush();\n    assert.equal(recordedA, null);\n    assert.equal(recordedB.addedNodes.length, 2);\n    observer1.disconnect();\n    observer2.disconnect();\n  });\n\n  test('observeNodes called in observed node context', function(done) {\n    var el = document.createElement('test-slot');\n    document.body.appendChild(el);\n    var observer = new FlattenedNodesObserver(el, function() {\n      assert.equal(this, el);\n      done();\n    });\n    // add\n    var d = document.createElement('div');\n    el.appendChild(d);\n    observer.flush();\n  });\n\n  test('observe children changes to distributing element', function() {\n    var el = document.createElement('test-slot');\n    document.body.appendChild(el);\n\n    var recorded;\n    var observer = new FlattenedNodesObserver(el, function(info) {\n      recorded = info;\n    });\n    // add\n    var d = document.createElement('div');\n    var d1 = document.createElement('div');\n    el.appendChild(d);\n    el.appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 2);\n    assert.equal(recorded.removedNodes.length, 0);\n    assert.equal(recorded.addedNodes[0], d);\n    assert.equal(recorded.addedNodes[1], d1);\n    // remove\n    el.removeChild(d);\n    el.removeChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 0);\n    assert.equal(recorded.removedNodes.length, 2);\n    assert.equal(recorded.removedNodes[0], d);\n    assert.equal(recorded.removedNodes[1], d1);\n    // add\n    el.appendChild(d);\n    el.appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 2);\n    assert.equal(recorded.addedNodes[0], d);\n    assert.equal(recorded.addedNodes[1], d1);\n    // reset, unobserve and remove\n    recorded = null;\n    observer.disconnect();\n    el.removeChild(d);\n    el.removeChild(d1);\n    observer.flush();\n    assert.equal(recorded, null);\n    document.body.removeChild(el);\n  });\n\n  test('observe children changes to distributing element that provoke additional changes', function() {\n    var el = document.createElement('test-slot');\n    document.body.appendChild(el);\n\n    var recordedInfo, elAddedInObserver;\n    var observerCallCount = 0;\n    var observer = new FlattenedNodesObserver(el, function(info) {\n      observerCallCount++;\n      recordedInfo = info;\n      if (info.target.childNodes.length < 5) {\n        elAddedInObserver = document.createElement('div');\n        info.target.appendChild(elAddedInObserver);\n     }\n\n    });\n    // add\n    var d = document.createElement('div');\n    el.appendChild(d);\n    while (observer.flush()) {\n      // re-flush until done\n    }\n    assert.equal(observerCallCount, 5);\n    assert.equal(recordedInfo.addedNodes.length, 1);\n    assert.equal(recordedInfo.addedNodes[0], elAddedInObserver);\n    assert.equal(el.childNodes.length, 5);\n    document.body.removeChild(el);\n    observer.disconnect();\n  });\n\n  test('observe children changes to distributing element (async)', function(done) {\n    var el = document.createElement('test-slot');\n    document.body.appendChild(el);\n\n    var nodes = [];\n    var handle = new FlattenedNodesObserver(el, function(info) {\n      for (var i=0, at; i < info.removedNodes.length; i++) {\n        at = nodes.indexOf(info.removedNodes[i]);\n        assert.isAbove(at, -1);\n        nodes.splice(at, 1);\n      }\n      nodes = nodes.concat(info.addedNodes);\n    });\n    // add\n    var d = document.createElement('div');\n    var d1 = document.createElement('div');\n    el.appendChild(d);\n    el.appendChild(d1);\n    let getFlattenedNodes = FlattenedNodesObserver.getFlattenedNodes;\n    setTimeout(function() {\n      assert.sameMembers(getFlattenedNodes(el), nodes);\n      // remove\n      el.removeChild(d);\n      el.removeChild(d1);\n      setTimeout(function() {\n        assert.sameMembers(getFlattenedNodes(el), nodes);\n        // add\n        el.appendChild(d);\n        el.appendChild(d1);\n        setTimeout(function() {\n          assert.sameMembers(getFlattenedNodes(el), nodes);\n          handle.disconnect();\n          el.removeChild(d);\n          el.removeChild(d1);\n          setTimeout(function() {\n            assert.notEqual(nodes.length, getFlattenedNodes(el).length);\n            document.body.removeChild(el);\n            done();\n          });\n        });\n      });\n    });\n  });\n\n  test('observe children changes to non-distributing element', function() {\n    var el = document.createElement('test-static');\n    document.body.appendChild(el);\n\n    var recorded;\n    var observer = new FlattenedNodesObserver(el, function(info) {\n      recorded = info;\n    });\n    // add\n    var d = document.createElement('div');\n    var d1 = document.createElement('div');\n    el.appendChild(d);\n    el.appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 2);\n    assert.equal(recorded.removedNodes.length, 0);\n    assert.equal(recorded.addedNodes[0], d);\n    assert.equal(recorded.addedNodes[1], d1);\n    // remove\n    el.removeChild(d);\n    el.removeChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 0);\n    assert.equal(recorded.removedNodes.length, 2);\n    assert.equal(recorded.removedNodes[0], d);\n    assert.equal(recorded.removedNodes[1], d1);\n    // add\n    el.appendChild(d);\n    el.appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 2);\n    assert.equal(recorded.addedNodes[0], d);\n    assert.equal(recorded.addedNodes[1], d1);\n    // reset, unobserve and remove\n    recorded = null;\n    observer.disconnect();\n    el.removeChild(d);\n    el.removeChild(d1);\n    observer.flush();\n    assert.equal(recorded, null);\n    document.body.removeChild(el);\n  });\n\n  test('observe changes to inner node wrapping <slot>', function() {\n    var el = document.createElement('test-slot');\n    document.body.appendChild(el);\n\n    var observedInfo;\n    var observer = new FlattenedNodesObserver(el.$.slotContainer, function(info) {\n      observedInfo = info;\n    });\n    observer.flush();\n    // add\n    var d = document.createElement('div');\n    var d1 = document.createElement('div');\n    el.appendChild(d);\n    el.appendChild(d1);\n    observer.flush();\n    assert.equal(observedInfo.target, el.$.slotContainer);\n    assert.equal(observedInfo.addedNodes.length, 2);\n    assert.equal(observedInfo.removedNodes.length, 0);\n    // remove\n    el.removeChild(d);\n    el.removeChild(d1);\n    observer.flush();\n    assert.equal(observedInfo.addedNodes.length, 0);\n    assert.equal(observedInfo.removedNodes.length, 2);\n    // add\n    el.appendChild(d);\n    el.appendChild(d1);\n    observer.flush();\n    assert.equal(observedInfo.addedNodes.length, 2);\n    assert.equal(observedInfo.removedNodes.length, 0);\n    // reset, unobserve and remove\n    observedInfo = null;\n    observer.disconnect();\n    el.removeChild(d);\n    el.removeChild(d1);\n    observer.flush();\n    assert.equal(observedInfo, null);\n    document.body.removeChild(el);\n  });\n\n  test('observe changes to <slot>', function() {\n    var el = document.createElement('test-slot');\n    document.body.appendChild(el);\n\n    var observedInfo;\n    var observer = new FlattenedNodesObserver(el.$.slot, function(info) {\n      observedInfo = info;\n    });\n    observer.flush();\n    // add\n    var d = document.createElement('div');\n    var d1 = document.createElement('div');\n    el.appendChild(d);\n    el.appendChild(d1);\n    observer.flush();\n    assert.equal(observedInfo.target, el.$.slot);\n    assert.equal(observedInfo.addedNodes.length, 2);\n    assert.equal(observedInfo.removedNodes.length, 0);\n    // remove\n    el.removeChild(d);\n    el.removeChild(d1);\n    observer.flush();\n    assert.equal(observedInfo.addedNodes.length, 0);\n    assert.equal(observedInfo.removedNodes.length, 2);\n    // add\n    el.appendChild(d);\n    el.appendChild(d1);\n    observer.flush();\n    assert.equal(observedInfo.addedNodes.length, 2);\n    assert.equal(observedInfo.removedNodes.length, 0);\n    // reset, unobserve and remove\n    observedInfo = null;\n    observer.disconnect();\n    el.removeChild(d);\n    el.removeChild(d1);\n    observer.flush();\n    assert.equal(observedInfo, null);\n    document.body.removeChild(el);\n  });\n\n  test('observe effective children inside distributing element', function() {\n    var el = document.createElement('test-slot1');\n    document.body.appendChild(el);\n\n    var recorded;\n    var observer = new FlattenedNodesObserver(el.$.slot, function(info) {\n      recorded = info;\n    });\n    observer.flush();\n    // add\n    var d = document.createElement('div');\n    var d1 = document.createElement('div');\n    el.appendChild(d);\n    el.appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 2);\n    assert.equal(recorded.removedNodes.length, 0);\n    assert.equal(recorded.addedNodes[0], d);\n    assert.equal(recorded.addedNodes[1], d1);\n    // remove\n    el.removeChild(d);\n    el.removeChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 0);\n    assert.equal(recorded.removedNodes.length, 2);\n    assert.equal(recorded.removedNodes[0], d);\n    assert.equal(recorded.removedNodes[1], d1);\n    // add\n    el.appendChild(d);\n    el.appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 2);\n    assert.equal(recorded.addedNodes[0], d);\n    assert.equal(recorded.addedNodes[1], d1);\n    // reset, unobserve and remove\n    recorded = null;\n    observer.disconnect();\n    el.removeChild(d);\n    el.removeChild(d1);\n    observer.flush();\n    assert.equal(recorded, null);\n    document.body.removeChild(el);\n  });\n\n  test('observe effective children changes when adding to another host', function() {\n    var el = document.createElement('test-slot1');\n    document.body.appendChild(el);\n\n    var recorded;\n    var observer = new FlattenedNodesObserver(el.$.slot, function(info) {\n      recorded = info;\n    });\n    observer.flush();\n    // add\n    var d = document.createElement('div');\n    var d1 = document.createElement('div');\n    el.appendChild(d);\n    el.appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 2);\n    assert.equal(recorded.removedNodes.length, 0);\n    assert.equal(recorded.addedNodes[0], d);\n    assert.equal(recorded.addedNodes[1], d1);\n    // add somewhere else... we should see these as removes\n    document.body.appendChild(d);\n    document.body.appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 0);\n    assert.equal(recorded.removedNodes.length, 2);\n    assert.equal(recorded.removedNodes[0], d);\n    assert.equal(recorded.removedNodes[1], d1);\n    // cleanup\n    document.body.removeChild(d);\n    document.body.removeChild(d1);\n    document.body.removeChild(el);\n    observer.disconnect();\n  });\n\n  test('observe effective children changes in static slot when adding to another host', function() {\n    var el = document.createElement('staticDiv');\n    document.body.appendChild(el);\n\n    var recorded;\n    var observer = new FlattenedNodesObserver(el, function(info) {\n      recorded = info;\n    });\n    observer.flush();\n    // add\n    var d = document.createElement('div');\n    var d1 = document.createElement('div');\n    el.appendChild(d);\n    el.appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 2);\n    assert.equal(recorded.removedNodes.length, 0);\n    assert.equal(recorded.addedNodes[0], d);\n    assert.equal(recorded.addedNodes[1], d1);\n    // add somewhere else... we should see these as removes\n    document.body.appendChild(d);\n    document.body.appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 0);\n    assert.equal(recorded.removedNodes.length, 2);\n    assert.equal(recorded.removedNodes[0], d);\n    assert.equal(recorded.removedNodes[1], d1);\n    // cleanup\n    document.body.removeChild(d);\n    document.body.removeChild(d1);\n    document.body.removeChild(el);\n    observer.disconnect();\n  });\n\n  test('observe effective children inside deep distributing element', function() {\n    var el = document.createElement('test-slot3');\n    document.body.appendChild(el);\n\n    var recorded;\n    var slot = el.$.slot.$.slot.$.slot;\n    var observer = new FlattenedNodesObserver(slot, function(info) {\n      recorded = info;\n    });\n    // add\n    var d = document.createElement('div');\n    var d1 = document.createElement('div');\n    el.appendChild(d);\n    el.appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 2);\n    assert.equal(recorded.removedNodes.length, 0);\n    assert.equal(recorded.addedNodes[0], d);\n    assert.equal(recorded.addedNodes[1], d1);\n    // remove\n    el.removeChild(d);\n    el.removeChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 0);\n    assert.equal(recorded.removedNodes.length, 2);\n    assert.equal(recorded.removedNodes[0], d);\n    assert.equal(recorded.removedNodes[1], d1);\n    // add\n    el.appendChild(d);\n    el.appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 2);\n    assert.equal(recorded.addedNodes[0], d);\n    assert.equal(recorded.addedNodes[1], d1);\n    // reset, unobserve and remove\n    recorded = null;\n    observer.disconnect();\n    el.removeChild(d);\n    el.removeChild(d1);\n    observer.flush();\n    assert.equal(recorded, null);\n    document.body.removeChild(el);\n  });\n\n  test('observe <slot> inside deep distributing element', function() {\n    var el = document.createElement('test-slot3');\n    document.body.appendChild(el);\n\n    var recorded;\n    var slot = el.$.slot.$.slot.$.slot.$.slot;\n    assert.equal(slot.localName, 'slot');\n    var observer = new FlattenedNodesObserver(slot, function(info) {\n      recorded = info;\n    });\n    // add\n    var d = document.createElement('div');\n    var d1 = document.createElement('div');\n    el.appendChild(d);\n    el.appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 2);\n    assert.equal(recorded.removedNodes.length, 0);\n    assert.equal(recorded.addedNodes[0], d);\n    assert.equal(recorded.addedNodes[1], d1);\n    // remove\n    el.removeChild(d);\n    el.removeChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 0);\n    assert.equal(recorded.removedNodes.length, 2);\n    assert.equal(recorded.removedNodes[0], d);\n    assert.equal(recorded.removedNodes[1], d1);\n    // add\n    el.appendChild(d);\n    el.appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 2);\n    assert.equal(recorded.addedNodes[0], d);\n    assert.equal(recorded.addedNodes[1], d1);\n    // reset, unobserve and remove\n    recorded = null;\n    observer.disconnect();\n    el.removeChild(d);\n    el.removeChild(d1);\n    observer.flush();\n    assert.equal(recorded, null);\n    document.body.removeChild(el);\n  });\n\n  test('observe effective children inside deep distributing element (async)', function(done) {\n    var el = document.createElement('test-slot3');\n    document.body.appendChild(el);\n\n    var recorded;\n    var slot = el.$.slot.$.slot.$.slot;\n    var observer = new FlattenedNodesObserver(slot, function(info) {\n      recorded = info;\n    });\n    // add\n    var d = document.createElement('div');\n    var d1 = document.createElement('div');\n    el.appendChild(d);\n    el.appendChild(d1);\n    setTimeout(function() {\n      assert.equal(recorded.addedNodes.length, 2);\n      assert.equal(recorded.removedNodes.length, 0);\n      assert.equal(recorded.addedNodes[0], d);\n      assert.equal(recorded.addedNodes[1], d1);\n      // remove\n      el.removeChild(d);\n      el.removeChild(d1);\n      setTimeout(function() {\n        assert.equal(recorded.addedNodes.length, 0);\n        assert.equal(recorded.removedNodes.length, 2);\n        assert.equal(recorded.removedNodes[0], d);\n        assert.equal(recorded.removedNodes[1], d1);\n        // add\n        el.appendChild(d);\n        el.appendChild(d1);\n        setTimeout(function() {\n          assert.equal(recorded.addedNodes.length, 2);\n          assert.equal(recorded.addedNodes[0], d);\n          assert.equal(recorded.addedNodes[1], d1);\n          // reset, unobserve and remove\n          recorded = null;\n          observer.disconnect();\n          el.removeChild(d);\n          el.removeChild(d1);\n          setTimeout(function() {\n            assert.equal(recorded, null);\n            document.body.removeChild(el);\n            done();\n          });\n        });\n      });\n    });\n  });\n\n\n  test('observe effective children attr changes inside deep distributing element (async)', function(done) {\n    var el = document.createElement('test-slot-attr3');\n    document.body.appendChild(el);\n\n    var recorded;\n    var slot = el.$.slot.$.slot.$.slot;\n    var observer = new FlattenedNodesObserver(slot, function(info) {\n      recorded = info;\n    });\n    observer.flush();\n    recorded = null;\n    // add\n    var d = document.createElement('div');\n    var d1 = document.createElement('div');\n    el.appendChild(d);\n    el.appendChild(d1);\n    observer.flush();\n    assert.equal(recorded, null);\n    setTimeout(function() {\n      assert.equal(recorded, null);\n      d.setAttribute('slot', 'a');\n      setTimeout(function() {\n        assert.equal(recorded.addedNodes.length, 1);\n        assert.equal(recorded.removedNodes.length, 0);\n        assert.equal(recorded.addedNodes[0], d);\n        d.removeAttribute('slot');\n        setTimeout(function() {\n          assert.equal(recorded.addedNodes.length, 0);\n          assert.equal(recorded.removedNodes.length, 1);\n          assert.equal(recorded.removedNodes[0], d);\n          recorded = null;\n          observer.disconnect();\n          d.setAttribute('slot', 'a');\n          setTimeout(function() {\n            assert.equal(recorded, null);\n            document.body.removeChild(el);\n            done();\n          });\n        });\n      });\n    });\n  });\n\n  test('observe effective children attr changes inside deep distributing element without outer select (async)', function(done) {\n    var el = document.createElement('test-slot-attr-inside');\n    document.body.appendChild(el);\n\n    var recorded;\n    var slot = el.$.slot.$.slot.$.slot.$.slot;\n    var observer = new FlattenedNodesObserver(slot, function(info) {\n      recorded = info;\n    });\n    observer.flush();\n    recorded = null;\n    // add\n    var d = document.createElement('div');\n    var d1 = document.createElement('div');\n    el.appendChild(d);\n    el.appendChild(d1);\n    observer.flush();\n    assert.equal(recorded, null);\n    setTimeout(function() {\n      assert.equal(recorded, null);\n      d.setAttribute('slot', 'a');\n      setTimeout(function() {\n        assert.equal(recorded.addedNodes.length, 1);\n        assert.equal(recorded.removedNodes.length, 0);\n        assert.equal(recorded.addedNodes[0], d);\n        d.removeAttribute('slot');\n        setTimeout(function() {\n          assert.equal(recorded.addedNodes.length, 0);\n          assert.equal(recorded.removedNodes.length, 1);\n          assert.equal(recorded.removedNodes[0], d);\n          recorded = null;\n          observer.disconnect();\n          d.setAttribute('slot', 'a');\n          setTimeout(function() {\n            assert.equal(recorded, null);\n            document.body.removeChild(el);\n            done();\n          });\n        });\n      });\n    });\n  });\n\n  test('add/remove multiple observers', function() {\n    var el = document.createElement('test-slot1');\n    document.body.appendChild(el);\n\n    var r1 = 0;\n    var h1 = new FlattenedNodesObserver(el.$.slot, function() {\n      r1++;\n    });\n    var r2 = 0;\n    var h2 = new FlattenedNodesObserver(el.$.slot, function() {\n      r2++;\n    });\n    var r3 = 0;\n    var h3 = new FlattenedNodesObserver(el.$.slot, function() {\n      r3++;\n    });\n    // add\n    var d = document.createElement('div');\n    el.appendChild(d);\n    h1.flush();\n    h2.flush();\n    h3.flush();\n    assert.equal(r1, 1);\n    assert.equal(r2, 1);\n    assert.equal(r3, 1);\n    h1.disconnect();\n    d = document.createElement('div');\n    el.appendChild(d);\n    h1.flush();\n    h2.flush();\n    h3.flush();\n    assert.equal(r1, 1);\n    assert.equal(r2, 2);\n    assert.equal(r3, 2);\n    h2.disconnect();\n    d = document.createElement('div');\n    el.appendChild(d);\n    h1.flush();\n    h2.flush();\n    h3.flush();\n    assert.equal(r1, 1);\n    assert.equal(r2, 2);\n    assert.equal(r3, 3);\n    h3.disconnect();\n    d = document.createElement('div');\n    el.appendChild(d);\n    h1.flush();\n    h2.flush();\n    h3.flush();\n    assert.equal(r1, 1);\n    assert.equal(r2, 2);\n    assert.equal(r3, 3);\n    h1 = new FlattenedNodesObserver(el.$.slot, h1.callback);\n    h2 = new FlattenedNodesObserver(el.$.slot, h2.callback);\n    h3 = new FlattenedNodesObserver(el.$.slot, h3.callback);\n    h1.flush();\n    h2.flush();\n    h3.flush();\n    assert.equal(r1, 2);\n    assert.equal(r2, 3);\n    assert.equal(r3, 4);\n    d = document.createElement('div');\n    el.appendChild(d);\n    h1.flush();\n    h2.flush();\n    h3.flush();\n    assert.equal(r1, 3);\n    assert.equal(r2, 4);\n    assert.equal(r3, 5);\n    h3.disconnect();\n    d = document.createElement('div');\n    el.appendChild(d);\n    h1.flush();\n    h2.flush();\n    h3.flush();\n    assert.equal(r1, 4);\n    assert.equal(r2, 5);\n    assert.equal(r3, 5);\n    h2.disconnect();\n    d = document.createElement('div');\n    el.appendChild(d);\n    h1.flush();\n    h2.flush();\n    h3.flush();\n    assert.equal(r1, 5);\n    assert.equal(r2, 5);\n    assert.equal(r3, 5);\n    h1.disconnect();\n    d = document.createElement('div');\n    el.appendChild(d);\n    h1.flush();\n    h2.flush();\n    h3.flush();\n    assert.equal(r1, 5);\n    assert.equal(r2, 5);\n    assert.equal(r3, 5);\n  });\n\n  test('observe changes of target with dynamically added <slot>', function() {\n    var el = document.createElement('test-static');\n    document.body.appendChild(el);\n    var container = el.shadowRoot.childNodes[1];\n    var recorded = null;\n    var observer = new FlattenedNodesObserver(container, function(info) {\n      recorded = info;\n    });\n    var slot = document.createElement('slot');\n    container.appendChild(slot);\n    observer.flush();\n    recorded = null;\n    var child = document.createElement('div');\n    el.appendChild(child);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 1);\n    assert.equal(recorded.addedNodes[0], child);\n    recorded = null;\n    el.removeChild(child);\n    observer.flush();\n    assert.equal(recorded.removedNodes.length, 1);\n    assert.equal(recorded.removedNodes[0], child);\n    recorded = null;\n    container.removeChild(slot);\n    observer.flush();\n    el.appendChild(child);\n    assert.equal(recorded, null);\n    observer.disconnect();\n    document.body.removeChild(el);\n  });\n\n  test('observe changes of target with dynamically added <slot> (flush/async)', function(done) {\n    var el = document.createElement('test-static');\n    document.body.appendChild(el);\n    var container = el.shadowRoot.childNodes[1];\n    var recorded = null;\n    var observer = new FlattenedNodesObserver(container, function(info) {\n      recorded = info;\n    });\n    var slot = document.createElement('slot');\n    container.appendChild(slot);\n    observer.flush();\n    recorded = null;\n    var child = document.createElement('div');\n    el.appendChild(child);\n    setTimeout(function() {\n      assert.equal(recorded.addedNodes.length, 1);\n      assert.equal(recorded.addedNodes[0], child);\n      done();\n    });\n  });\n\n  test('observe changes of target with dynamically added <slot> (async)', function(done) {\n    var el = document.createElement('test-static');\n    document.body.appendChild(el);\n    var container = el.shadowRoot.childNodes[1];\n    var recorded = null;\n    var observer = new FlattenedNodesObserver(container, function(info) {\n      recorded = info;\n    });\n    var slot = document.createElement('slot');\n    container.appendChild(slot);\n    observer.flush();\n    recorded = null;\n    var child = document.createElement('div');\n    el.appendChild(child);\n    setTimeout(function() {\n      assert.equal(recorded.addedNodes.length, 1);\n      assert.equal(recorded.addedNodes[0], child);\n      recorded = null;\n      el.removeChild(child);\n      setTimeout(function() {\n        assert.equal(recorded.removedNodes.length, 1);\n        assert.equal(recorded.removedNodes[0], child);\n        recorded = null;\n        container.removeChild(slot);\n        setTimeout(function() {\n          el.appendChild(child);\n          assert.equal(recorded, null);\n          observer.disconnect();\n          document.body.removeChild(el);\n          done();\n        });\n      });\n    });\n  });\n\n  test('element distributed to insertion point observing itself', function() {\n    var host = document.createElement('test-slot');\n    var el = document.createElement('test-self-observe');\n    host.appendChild(el);\n    document.body.appendChild(host);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.ok(el._observer);\n    var div = document.createElement('div');\n    el.appendChild(div);\n    el._observer.flush();\n    assert.equal(el.info.addedNodes[0], div);\n    document.body.removeChild(host);\n  });\n\n  test('should not fail on node without children', function() {\n    var recorded;\n    var el = document;\n    var observer = new FlattenedNodesObserver(el, function(info) {\n      recorded = info;\n    });\n    assert.equal(recorded, null);\n    observer.disconnect();\n  });\n\n});\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/gestures-elements.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\nimport { Polymer } from '../../lib/legacy/polymer-fn.js';\nimport { html } from '../../lib/utils/html-tag.js';\nimport { PolymerElement } from '../../polymer-element.js';\nimport { GestureEventListeners } from '../../lib/mixins/gesture-event-listeners.js';\nimport { addListener } from '../../lib/utils/gestures.js';\nPolymer({\n  _template: html`\n  <style>\n    #div {\n      height: 40px;\n      background: red;\n    }\n  </style>\n\n    <div id=\"div\"></div>\n`,\n\n  is: 'x-foo',\n\n  listeners: {\n    tap: 'tapHandler'\n  },\n\n  tapHandler: function(e) {\n    this._testLocalTarget = e.target;\n    this._testRootTarget = e.composedPath()[0];\n  }\n});\nPolymer({\n  _template: html`\n    <x-foo id=\"foo\"></x-foo>\n`,\n\n  is: 'x-app',\n\n  listeners: {\n    tap: 'tapHandler'\n  },\n\n  tapHandler: function(e) {\n    this._testLocalTarget = e.target;\n    this._testRootTarget = e.composedPath()[0];\n  }\n});\nPolymer({\n  _template: html`\n    <div id=\"inner\" on-tap=\"handler\" on-track=\"handler\" on-down=\"handler\" on-up=\"handler\"></div>\n`,\n\n  is: 'x-setup',\n\n  listeners: {\n    tap: 'handler',\n    track: 'handler',\n    down: 'handler',\n    up: 'handler'\n  },\n\n  handler: function() {\n  }\n});\nPolymer({\n  is: 'x-dynamic',\n  handler: function(){},\n  setup: function() {\n    this.listen(this, 'tap', 'handler');\n  },\n  teardown: function() {\n    this.unlisten(this, 'tap', 'handler');\n  }\n});\nvar EventCaptureBehavior = {\n  properties: {\n    stream: {\n      type: Array,\n      value: function() {\n        return [];\n      }\n    }\n  },\n  handle: function(e) {\n    this.stream.push(e);\n  }\n};\nPolymer({\n  listeners: {\n    'down': 'prevent',\n    'up': 'handle',\n    'tap': 'handle',\n    'track': 'handle'\n  },\n  behaviors: [EventCaptureBehavior],\n  is: 'x-prevent',\n  prevent: function(e, detail) {\n    detail.prevent('tap');\n    detail.prevent('track');\n    e.preventDefault();\n    this.handle(e);\n  }\n});\nPolymer({\n  is: 'x-buttons',\n  listeners: {\n    'down': 'handle',\n    'up': 'handle',\n    'tap': 'handle',\n    'track': 'handle'\n  },\n  behaviors: [EventCaptureBehavior]\n});\nPolymer({\n  is: 'x-document-listener',\n  setup: function() {\n    this.listen(document, 'down', 'handle');\n  },\n  teardown: function() {\n    this.unlisten(document, 'down', 'handle');\n  },\n  behaviors: [EventCaptureBehavior]\n});\nPolymer({\n  is: 'x-nested-child-prevent',\n  listeners: {\n    tap: 'handle'\n  },\n  behaviors: [EventCaptureBehavior]\n});\nPolymer({\n  _template: html`\n    <style>\n      :host {\n        position: absolute;\n        display: block;\n        background: orange;\n        height: 100px;\n        width: 100px;\n      }\n      #child {\n        position: relative;\n        display: block;\n        background: blue;\n        height: 50px;\n        width: 50px;\n        margin-top: 25px;\n        margin-left: 25px;\n      }\n    </style>\n    <x-nested-child-prevent id=\"child\"></x-nested-child-prevent>\n`,\n\n  is: 'x-nested-prevent',\n\n  listeners: {\n    track: 'handle'\n  },\n\n  behaviors: [EventCaptureBehavior]\n});\nPolymer({\n  is: 'x-imperative',\n  behaviors: [EventCaptureBehavior]\n});\nclass XNativeLabel extends PolymerElement {\n  static get template() {\n    return html`\n    <label id=\"label\" for=\"check\"></label>\n    <input id=\"check\" type=\"checkbox\">\n`;\n  }\n\n  static get is() {\n    return 'x-native-label';\n  }\n}\ncustomElements.define(XNativeLabel.is, XNativeLabel);\nclass XNativeLabelNested extends PolymerElement {\n  static get template() {\n    return html`\n    <label id=\"label\">\n      <input id=\"check\" type=\"checkbox\">\n    </label>\n`;\n  }\n\n  static get is() {\n    return 'x-native-label-nested';\n  }\n}\ncustomElements.define(XNativeLabelNested.is, XNativeLabelNested);\n\nclass XDisabled extends PolymerElement {\n  static get is() {\n    return 'x-disabled';\n  }\n  static get properties() {\n    return {\n      disabled: {\n        type: Boolean,\n        reflectToAttribute: true\n      }\n    };\n  }\n  constructor() {\n    super();\n    this.disabled = true;\n  }\n}\ncustomElements.define(XDisabled.is, XDisabled);\n\nclass XDisabledTap extends GestureEventListeners(PolymerElement) {\n  constructor() {\n    super();\n    this.taps = [];\n  }\n  static get template() {\n    return html`\n    <button id=\"disabled\" on-tap=\"tap\" disabled></button>\n    <div disabled>\n      <button id=\"nested\" on-tap=\"tap\"></button>\n    </div>\n    <x-disabled id=\"disabledEl\" on-tap=\"tap\"></x-disabled>`;\n  }\n  static get is() {\n    return 'x-disabled-tap';\n  }\n  tap(e) {\n    const target = e.target;\n    this.taps.push(`${target.localName}${target.id ? '#' + target.id : ''}`);\n  }\n}\ncustomElements.define(XDisabledTap.is, XDisabledTap);\n\n\nclass AllDisabled extends GestureEventListeners(PolymerElement) {\n  static get is() {\n    return 'all-disabled';\n  }\n  static get template() {\n    return html`\n    <button></button>\n    <!-- MDN lists as obsolete -->\n    <!-- <command></command> -->\n    <fieldset></fieldset>\n    <input>\n    <!-- MDN lists as obsolete -->\n    <!-- <keygen> -->\n    <select>\n      <optgroup>\n        <option></option>\n      </optgroup>\n    </select>\n    <textarea></textarea>`;\n  }\n  constructor() {\n    super();\n    this.taps = [];\n  }\n  tap(e) {\n    this.taps.push(e.target.localName);\n  }\n  ready() {\n    super.ready();\n    this.shadowRoot.querySelectorAll('*').forEach((el) => {\n      el.setAttribute('disabled', '');\n      addListener(el, 'tap', (e) => this.tap(e));\n    });\n  }\n  tapAll() {\n    this.shadowRoot.querySelectorAll('*').forEach((el) => {\n      el.click();\n    });\n  }\n}\ncustomElements.define(AllDisabled.is, AllDisabled);"
  },
  {
    "path": "test/unit/gestures.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n  <script type=\"module\" src=\"./gestures-elements.js\"></script>\n\n</head>\n<body>\n\n  <script type=\"module\">\nimport './gestures-elements.js';\nimport { afterNextRender } from '../../lib/utils/render-status.js';\nimport { setCancelSyntheticClickEvents } from '../../lib/utils/settings.js';\nimport { resetMouseCanceller, deepTargetFind, recognizers, addListener, removeListener } from '../../lib/utils/gestures.js';\n\nsuite('simulate events', function() {\n\n  var app;\n\n  setup(function(done) {\n    app = document.createElement('x-app');\n    document.body.appendChild(app);\n    afterNextRender(null, done);\n  });\n\n  teardown(function() {\n    document.body.removeChild(app);\n    resetMouseCanceller();\n  });\n\n  test('tap on x-foo and check localTarget and rootTarget', function() {\n    var foo = app.$.foo;\n    foo.dispatchEvent(new CustomEvent('click', {bubbles: true, composed: true}));\n    assert.equal(app._testLocalTarget, app, 'local target');\n    assert.equal(app._testRootTarget, foo, 'root target');\n    let touches = [{\n      clientX: 0,\n      clientY: 0,\n      identifier: 1,\n      // target is set to the element with `addEventListener`, which is app\n      target: app\n    }];\n    let touchstart = new CustomEvent('touchstart', {bubbles: true, composed: true});\n    touchstart.changedTouches = touchstart.touches = touches;\n    foo.dispatchEvent(touchstart);\n    let touchend = new CustomEvent('touchend', {bubbles: true, composed: true});\n    touchend.touches = touchend.changedTouches = touches;\n    foo.dispatchEvent(touchend);\n    assert.equal(app._testLocalTarget, app, 'local target touch');\n    assert.equal(app._testRootTarget, foo, 'root target touch');\n  });\n\n  test('tap on x-foo.div and check target info', function() {\n    var foo = app.$.foo;\n    var div = foo.$.div;\n    div.dispatchEvent(new CustomEvent('click', {bubbles: true, composed: true}));\n    assert.equal(app._testLocalTarget, app, 'app local target');\n    assert.equal(app._testRootTarget, div, 'app root target');\n    assert.equal(foo._testLocalTarget, foo, 'foo local target');\n    assert.equal(foo._testRootTarget, div, 'foo root target');\n    let touches = [{\n      clientX: 0,\n      clientY: 0,\n      identifier: 1,\n      // target is set to the element with `addEventListener`, which is app\n      target: app\n    }];\n    let touchstart = new CustomEvent('touchstart', {bubbles: true, composed: true});\n    touchstart.touches = touchstart.changedTouches = touches;\n    let touchend = new CustomEvent('touchend', {composed: true, bubbles: true});\n    touchend.touches = touchend.changedTouches = touches;\n    div.dispatchEvent(touchstart);\n    div.dispatchEvent(touchend);\n    assert.equal(app._testLocalTarget, app, 'app local target touch');\n    assert.equal(app._testRootTarget, div, 'app root target touch');\n    assert.equal(foo._testLocalTarget, foo, 'foo local target touch');\n    assert.equal(foo._testRootTarget, div, 'foo root target touch');\n  });\n\n  test('HTMLElement.click triggers tap', function() {\n    // put the element off screen to prevent x/y weirdness from .click()\n    app.style.cssText = 'position: absolute; left: -1000px; top: -1000px;';\n    // make a mousedown *very* far away to tickle the distance check\n    var ev = new CustomEvent('mousedown', {composed: true});\n    ev.clientX = 1e8;\n    ev.clientY = 1e8;\n    app.dispatchEvent(ev);\n    app.click();\n    assert.equal(app._testLocalTarget, app, 'app local target');\n    assert.equal(app._testRootTarget, app, 'app root target');\n  });\n});\n\nsuite('cancelling synthetic click events disabled', () => {\n  setup(() => {\n    setCancelSyntheticClickEvents(false);\n  });\n\n  teardown(() => {\n    setCancelSyntheticClickEvents(true);\n  });\n\n  test('HTMLElement.click triggers a click event', function(done) {\n    const buttonA = document.createElement('button');\n    const buttonB = document.createElement('button');\n    document.body.appendChild(buttonA);\n    document.body.appendChild(buttonB);\n    buttonB.addEventListener('click', () => {\n      buttonB.parentElement.removeChild(buttonA);\n      buttonB.parentElement.removeChild(buttonB);\n      done();\n    });\n    // simulate a user click on a button on a touch device\n    buttonA.dispatchEvent(new CustomEvent('touchend', { bubbles: true }));\n    buttonB.click();\n  });\n});\n\nsuite('Event Setup and Teardown', function() {\n  var outer, inner;\n  suiteSetup(function(done) {\n    outer = document.createElement('x-setup');\n    document.body.appendChild(outer);\n    afterNextRender(null, function() {\n      inner = outer.$.inner;\n      done();\n    });\n  });\n\n  suite('setup', function() {\n    test('listeners block', function() {\n      assert.equal(outer.__polymerGesturesTouchAction, 'none');\n      var obj = outer.__polymerGestures;\n      assert.equal(obj.mousedown.downup, 2, 'mousedown downup');\n      assert.equal(obj.mousedown.track, 1, 'mousedown track');\n      assert.equal(obj.mousedown.tap, 1, 'mousedown tap');\n      assert.equal(obj.mousedown._count, 4, 'total mousedown');\n      assert.equal(obj.touchstart.downup, 2, 'touchstart downup');\n      assert.equal(obj.touchstart.tap, 1, 'touchstart tap');\n      assert.equal(obj.touchstart.track, 1, 'touchstart track');\n      assert.equal(obj.touchstart._count, 4, 'total touchstart');\n      assert.equal(obj.touchmove.track, 1, 'touchmove track');\n      assert.equal(obj.touchmove._count, 1, 'total touchmove');\n      assert.equal(obj.touchend.downup, 2, 'touchend downup');\n      assert.equal(obj.touchend.track, 1, 'touchend track');\n      assert.equal(obj.touchend.tap, 1, 'touchend tap');\n      assert.equal(obj.touchend._count, 4, 'total touchend');\n    });\n\n    test('on-*', function() {\n      assert.equal(inner.__polymerGesturesTouchAction, 'none');\n      var obj = inner.__polymerGestures;\n      assert.equal(obj.mousedown.downup, 2, 'mousedown downup');\n      assert.equal(obj.mousedown.track, 1, 'mousedown track');\n      assert.equal(obj.mousedown.tap, 1, 'mousedown tap');\n      assert.equal(obj.mousedown._count, 4, 'total mousedown');\n      assert.equal(obj.touchstart.downup, 2, 'touchstart downup');\n      assert.equal(obj.touchstart.tap, 1, 'touchstart tap');\n      assert.equal(obj.touchstart.track, 1, 'touchstart track');\n      assert.equal(obj.touchstart._count, 4, 'total touchstart');\n      assert.equal(obj.touchmove.track, 1, 'touchmove track');\n      assert.equal(obj.touchmove._count, 1, 'total touchmove');\n      assert.equal(obj.touchend.downup, 2, 'touchend downup');\n      assert.equal(obj.touchend.track, 1, 'touchend track');\n      assert.equal(obj.touchend.tap, 1, 'touchend tap');\n      assert.equal(obj.touchend._count, 4, 'total touchend');\n    });\n\n    test('dynamic', function(done) {\n      var el = document.createElement('x-dynamic');\n      afterNextRender(null, function() {\n        var obj = el.__polymerGestures;\n        assert(!obj);\n        el.setup();\n        obj = el.__polymerGestures;\n        assert(obj, 'gestures object exists');\n        assert.equal(obj.mousedown.tap, 1, 'mousedown tap');\n        assert.equal(obj.click.tap, 1, 'click tap');\n        assert.equal(obj.touchstart.tap, 1, 'touchstart tap');\n        assert.equal(obj.touchend.tap, 1, 'touchend tap');\n        done();\n      });\n    });\n  });\n\n  suite('teardown', function() {\n    test('dynamic', function(){\n      var el = document.createElement('x-dynamic');\n      var obj = el.__polymerGestures;\n      assert(!obj);\n      el.setup();\n      el.teardown();\n      obj = el.__polymerGestures;\n      assert(obj, 'gestures object exists');\n      assert.equal(obj.mousedown.tap, 0, 'mousedown tap');\n      assert.equal(obj.click.tap, 0, 'click tap');\n      assert.equal(obj.touchstart.tap, 0, 'touchstart tap');\n      assert.equal(obj.touchend.tap, 0, 'touchend tap');\n    });\n  });\n});\n\nsuite('target finding', function() {\n  var div, divLocation;\n\n  setup(function() {\n    div = document.createElement('div');\n    div.style.cssText = 'height: 50px; width: 50px; background: red;';\n    div.id = 'target';\n    document.body.appendChild(div);\n    divLocation = div.getBoundingClientRect();\n  });\n\n  test('target finding returns null outside the window', function() {\n    var actual = deepTargetFind(-1, -1);\n    assert.equal(actual, null);\n  });\n\n  test('find the div in document', function() {\n    var x = divLocation.left, y = divLocation.top;\n    var actual = deepTargetFind(x, y);\n    assert.equal(actual, div);\n  });\n\n  test('find the div with a shadowroot', function() {\n    div.attachShadow({mode: 'open'});\n    var x = divLocation.left, y = divLocation.top;\n    var actual = deepTargetFind(x, y);\n    assert.equal(actual, div);\n  });\n\n  test('find the div inside a shadowroot', function() {\n    var divOwner = document.createElement('span');\n    document.body.appendChild(divOwner);\n    divOwner.attachShadow({mode: 'open'}).appendChild(div);\n    var bcr = divOwner.getBoundingClientRect();\n    var x = bcr.left+10, y = bcr.top+10;\n    var actual = deepTargetFind(x, y);\n    assert.equal(actual, div);\n  });\n\n  test('find the div with a shadowroot inside a shadowroot', function() {\n    div.attachShadow({mode: 'open'});\n    var divOwner = document.createElement('span');\n    document.body.appendChild(divOwner);\n    divOwner.attachShadow({mode: 'open'}).appendChild(div);\n    var bcr = divOwner.getBoundingClientRect();\n    var x = bcr.left, y = bcr.top;\n    var actual = deepTargetFind(x, y);\n    assert.equal(actual, div);\n  });\n});\n\nsuite('Prevention', function() {\n  var el;\n  setup(function(done) {\n    el = document.createElement('x-prevent');\n    document.body.appendChild(el);\n    afterNextRender(null, done);\n  });\n  teardown(function() {\n    el.parentNode.removeChild(el);\n    resetMouseCanceller();\n  });\n\n  test('tap', function() {\n    var ev = new CustomEvent('mousedown', {\n      bubbles: true,\n      cancelable: true,\n      composed: true\n    });\n    el.dispatchEvent(ev);\n    assert.equal(el.stream.length, 1, 'one event dispatched');\n    assert.equal(el.stream[0].type, 'down', 'was down event');\n    assert.equal(el.stream[0].defaultPrevented, true, 'was prevented');\n    assert.equal(ev.defaultPrevented, true, 'base event was prevented');\n  });\n\n  test('track', function() {\n    var ev = new CustomEvent('mousedown', {\n      bubbles: true,\n      cancelable: true,\n      composed: true\n    });\n    ev.clientX = ev.clientY = 0;\n    el.dispatchEvent(ev);\n    assert.equal(el.stream.length, 1);\n    for (var i = 0; i < 10; i++) {\n      ev = new CustomEvent(\n        i === 9 ? 'mouseup' : 'mousemove',\n        {bubbles: true, cancelable: true, composed: true}\n      );\n      ev.clientX = ev.clientY = 10 * i;\n      el.dispatchEvent(ev);\n    }\n    assert.equal(el.stream.length, 2, 'expected only down and up');\n    assert.equal(el.stream[0].type, 'down', 'down was found');\n    assert.equal(el.stream[0].defaultPrevented, true, 'down was prevented');\n    assert.equal(el.stream[1].type, 'up', 'up was found');\n  });\n\n  test('nested track and tap with touch', function(done) {\n    el.parentNode.removeChild(el);\n    el = document.createElement('x-nested-prevent');\n    document.body.appendChild(el);\n    afterNextRender(null, function() {\n      var child = el.$.child;\n      var options = {bubbles: true, cancelable: true, composed: true};\n\n      var bgr = el.getBoundingClientRect();\n      var clientX = bgr.left + (bgr.width / 2);\n      var clientY = bgr.top + (bgr.bottom / 2);\n      var ev = new CustomEvent('touchstart', options);\n      ev.touches = ev.changedTouches = [\n        {\n          clientX: clientX,\n          clientY: clientY,\n          identifier: 1,\n          // target is set to the element with `addEventListener`, which is el\n          target: el\n        }\n      ];\n      ev.clientX = clientX;\n      ev.clientY = clientY;\n      child.dispatchEvent(ev);\n\n      for (var i = 0; i < 10; i++) {\n        clientX += 1;\n        ev = new CustomEvent(i === 9 ? 'touchend' : 'touchmove', options);\n        ev.touches = ev.changedTouches = [\n          {\n            clientX: clientX,\n            clientY: clientY,\n            identifier: 1,\n            // target is set to the element with `addEventListener`, which is el\n            target: el\n          }\n        ];\n        ev.clientX = clientX;\n        ev.clientY = clientY;\n        // tell gestures to not turn off mouse events\n        child.dispatchEvent(ev);\n      }\n\n      assert.equal(child.stream.length, 0, 'expected no taps on the child');\n      assert.notEqual(el.stream.length, 0, 'expected some tracks on the parent');\n      done();\n    });\n  });\n});\n\nsuite('Buttons', function() {\n  var el;\n\n  setup(function(done) {\n    el = document.createElement('x-buttons');\n    document.body.appendChild(el);\n    afterNextRender(null, done);\n  });\n\n  teardown(function() {\n    el.parentNode.removeChild(el);\n  });\n\n  suite('Down and Up', function() {\n    test('Left Mouse Button Only', function() {\n      var options = {bubbles: true, composed: true};\n      var evLeftDown = new CustomEvent('mousedown', options);\n      // left button\n      evLeftDown.button = 0;\n      evLeftDown.clientX = 1;\n      var evLeftUp = new CustomEvent('mouseup', options);\n      var evRightDown = new CustomEvent('mousedown', options);\n      // right button\n      evRightDown.button = 2;\n      evRightDown.clientX = 2;\n      var evRightUp = new CustomEvent('mouseup', options);\n\n      el.dispatchEvent(evLeftDown);\n      el.dispatchEvent(evLeftUp);\n      el.dispatchEvent(evRightDown);\n      el.dispatchEvent(evRightUp);\n\n      assert.equal(el.stream.length, 2, 'only saw one up and down pair');\n      assert.equal(el.stream[0].type, 'down');\n      assert.equal(el.stream[1].type, 'up');\n      assert.equal(el.stream[0].detail.x, 1, 'only from the left button');\n    });\n\n    test('Recover from right click', function() {\n      var options = {bubbles: true, composed: true};\n      var evDown = new CustomEvent('mousedown', options);\n      var evMove = new CustomEvent('mousemove', options);\n      evMove.buttons = 0;\n      var evUp = new CustomEvent('mouseup', options);\n\n      el.dispatchEvent(evDown);\n      el.dispatchEvent(evMove);\n      el.dispatchEvent(evUp);\n\n      assert.equal(el.stream.length, 2, 'always get an up');\n    });\n  });\n\n  suite('Tap', function() {\n    test('Left Mouse Button Only', function() {\n      var evMid = new CustomEvent('click', {bubbles: true, composed: true});\n      evMid.button = 1;\n      var evLeft = new CustomEvent('click', {bubbles: true, composed: true});\n      evLeft.button = 0;\n\n      el.dispatchEvent(evMid);\n      el.dispatchEvent(evLeft);\n\n      assert.equal(el.stream.length, 1, 'only one tap');\n    });\n  });\n\n  suite('Track', function() {\n    test('Left Mouse Button Only', function() {\n      var options = {bubbles: true, composed: true};\n      var ev = new CustomEvent('mousedown', options);\n      ev.clientX = ev.clientY = 0;\n      el.dispatchEvent(ev);\n      for (var i = 0; i < 5; i++) {\n        ev = new CustomEvent('mousemove', options);\n        ev.clientX = 10 * i;\n        ev.clientY = 10 * i;\n        // left button until move 4\n        ev.buttons = (i > 3) ? 2 : 1;\n        el.dispatchEvent(ev);\n      }\n      el.dispatchEvent(new CustomEvent('mouseup', options));\n\n      // down, <skipped>, track:start, track:track, track:track, track:end, up\n      assert.equal(el.stream.length, 6);\n      assert.equal(el.stream[0].type, 'down');\n      assert.equal(el.stream[1].detail.state, 'start');\n      assert.equal(el.stream[2].detail.state, 'track');\n      assert.equal(el.stream[3].detail.state, 'track');\n      assert.equal(el.stream[4].type, 'up');\n      assert.equal(el.stream[5].detail.state, 'end');\n    });\n  });\n});\n\nsuite('SD Polyfill', function() {\n  var el;\n  setup(function(done) {\n    el = document.createElement('x-document-listener');\n    document.body.appendChild(el);\n    afterNextRender(null, function() {\n      el.setup();\n      done();\n    });\n  });\n\n  teardown(function() {\n    el.teardown();\n    document.body.removeChild(el);\n  });\n\n  test('document listener works in SD polyfill', function() {\n    var ev = new CustomEvent('mousedown', {bubbles: true, composed: true});\n    el.dispatchEvent(ev);\n    assert.equal(el.stream.length, 1);\n  });\n});\n\nsuite('Reference Cleanup', function() {\n  var el;\n\n  setup(function(done) {\n    el = document.createElement('x-buttons');\n    document.body.appendChild(el);\n    afterNextRender(null, done);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('down and up clear document tracking', function() {\n    var ev = new CustomEvent('mousedown', {bubbles: true, composed: true});\n    el.dispatchEvent(ev);\n\n    // some recognizers do not track the document, like tap\n    var recs = recognizers.filter(function(r) {\n      return r.info.hasOwnProperty('movefn') &&\n        r.info.hasOwnProperty('upfn');\n    });\n\n    assert.isAbove(recs.length, 0, 'some recognizers track the document');\n\n    recs.forEach(function(r) {\n      assert.isFunction(r.info.movefn, r.name + ' movefn');\n      assert.isFunction(r.info.upfn, r.name + ' upfn');\n    });\n\n    ev = new CustomEvent('mouseup', {bubbles: true, composed: true});\n    el.dispatchEvent(ev);\n\n    recs.forEach(function(r) {\n      assert.isNull(r.info.movefn, r.name + ' movefn');\n      assert.isNull(r.info.upfn, r.name + ' upfn');\n    });\n  });\n});\n\nsuite('Imperative API', function() {\n  var el, fn;\n  suiteSetup(function() {\n    el = document.createElement('x-imperative');\n    document.body.appendChild(el);\n    fn = function(e) { el.handle(e); };\n  });\n  suiteTeardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('add listeners with addListener', function() {\n    addListener(el, 'down', fn);\n    addListener(el, 'up', fn);\n    var ev = new CustomEvent('mousedown', {bubbles: true, composed: true});\n    el.dispatchEvent(ev);\n    assert.equal(el.stream.length, 1);\n    assert.equal(el.stream[0].type, 'down');\n    ev = new CustomEvent('mouseup', {bubbles: true, composed: true});\n    el.dispatchEvent(ev);\n    assert.equal(el.stream.length, 2);\n    assert.equal(el.stream[1].type, 'up');\n  });\n\n  test('remove listeners with removeListener', function() {\n    removeListener(el, 'down', fn);\n    removeListener(el, 'up', fn);\n    var ev = new CustomEvent('mousedown', {bubbles: true, composed: true});\n    el.dispatchEvent(ev);\n    ev = new CustomEvent('mouseup', {bubbles: true, composed: true});\n    el.dispatchEvent(ev);\n    assert.equal(el.stream.length, 2);\n  });\n});\n\nsuite('setScrollDirection', function() {\n  test('mapping', function() {\n    var el = document.createElement('x-imperative');\n    var key = '__polymerGesturesTouchAction';\n    el.setScrollDirection('none');\n    assert.equal(el[key], 'none');\n    el.setScrollDirection('all');\n    assert.equal(el[key], 'auto');\n    el.setScrollDirection('x');\n    assert.equal(el[key], 'pan-x');\n    el.setScrollDirection('y');\n    assert.equal(el[key], 'pan-y');\n  });\n});\n\nsuite('Regression Testing', function() {\n  test('#4459', function() {\n    addListener(document, 'tap', null);\n    document.dispatchEvent(new MouseEvent('mousedown', { detail: 1, clientX: -100, bubbles: true, composed: true }));\n    document.dispatchEvent(new MouseEvent('mouseup', { detail: 1, clientX: 100, bubbles: true, composed: true }));\n    document.dispatchEvent(new MouseEvent('click', { detail: 1, clientX: 100, bubbles: true, composed: true }));\n    removeListener(document, 'tap', null);\n  });\n\n  test('#5030', function() {\n    let count = 0;\n    const increment = function() { count++; };\n    addListener(window, 'tap', increment);\n    window.dispatchEvent(new MouseEvent('click', {bubbles: true}));\n    assert.equal(count, 1);\n    removeListener(window, 'tap', increment);\n  });\n\n  suite('native label click', function() {\n\n    test('native label click', function() {\n      let el = document.createElement('x-native-label');\n      document.body.appendChild(el);\n      let target = el.$.label;\n      // simulate the event sequence of a touch on the screen\n      let touches = [{\n        clientX: 0,\n        clientY: 0,\n        identifier: 1,\n        // target is set to the element with `addEventListener`, which is `target`\n        target\n      }];\n      let touchstart = new CustomEvent('touchstart', {bubbles: true, composed: true});\n      touchstart.changedTouches = touchstart.touches = touches;\n      target.dispatchEvent(touchstart);\n      let touchend = new CustomEvent('touchend', {bubbles: true, composed: true});\n      touchend.touches = touchend.changedTouches = touches;\n      target.dispatchEvent(touchend);\n      // simulate a mouse click on the label\n      let click = new MouseEvent('click', {bubbles: true, composed: true});\n      target.dispatchEvent(click);\n      // check that the mouse click on the label will activate the checkbox\n      assert.equal(el.$.check.checked, true, 'checkbox should be checked');\n      document.body.removeChild(el);\n    });\n\n    test('label click with nested element', function() {\n      let el = document.createElement('x-native-label-nested');\n      document.body.appendChild(el);\n      let target = el.$.label;\n      // simulate the event sequence of a touch on the screen\n      let touches = [{\n        clientX: 0,\n        clientY: 0,\n        identifier: 1,\n        // target is set to the element with `addEventListener`, which is `target`\n        target\n      }];\n      let touchstart = new CustomEvent('touchstart', {bubbles: true, composed: true});\n      touchstart.changedTouches = touchstart.touches = touches;\n      target.dispatchEvent(touchstart);\n      let touchend = new CustomEvent('touchend', {bubbles: true, composed: true});\n      touchend.touches = touchend.changedTouches = touches;\n      target.dispatchEvent(touchend);\n      // simulate a mouse click on the label\n      let click = new MouseEvent('click', {bubbles: true, composed: true});\n      target.dispatchEvent(click);\n      // check that the mouse click on the label will activate the checkbox\n      assert.equal(el.$.check.checked, true, 'checkbox should be checked');\n      document.body.removeChild(el);\n    });\n  });\n\n  suite('disabled', function() {\n    let shouldSkip = true;\n\n    suiteSetup(function() {\n      /*\n       * IE 11 does not dispatch events to elements with `disabled` attribute\n       * This is different from all other browsers, so skip these tests in IE 11\n       */\n      const div = document.createElement('div');\n      div.setAttribute('disabled', '');\n      document.body.appendChild(div);\n      div.addEventListener('click', () => {\n        shouldSkip = false;\n      });\n      div.click();\n      document.body.removeChild(div);\n    });\n    setup(function() {\n      resetMouseCanceller();\n    });\n\n    test('click() function works as expected on disabled elements', function() {\n      if (shouldSkip) {\n        this.skip();\n      }\n      let el = document.createElement('x-disabled-tap');\n      document.body.appendChild(el);\n      el.$.disabled.click();\n      el.$.nested.click();\n      el.$.disabledEl.click();\n      assert.deepEqual(el.taps, ['button#nested', 'x-disabled#disabledEl']);\n      document.body.removeChild(el);\n    });\n\n    test('disabled elements don\\'t fire taps', function() {\n      if (shouldSkip) {\n        this.skip();\n      }\n      let el = document.createElement('x-disabled-tap');\n      document.body.appendChild(el);\n      // tap an element with disabled attribute\n      let target = el.$.disabled;\n      // simulate the event sequence of a touch on the screen\n      let touches = [{\n        clientX: 0,\n        clientY: 0,\n        identifier: 1,\n        // target is set to the element with `addEventListener`, which is `target`\n        target\n      }];\n      let touchstart = new CustomEvent('touchstart', {bubbles: true, composed: true});\n      touchstart.changedTouches = touchstart.touches = touches;\n      target.dispatchEvent(touchstart);\n      let touchend = new CustomEvent('touchend', {bubbles: true, composed: true});\n      touchend.touches = touchend.changedTouches = touches;\n      target.dispatchEvent(touchend);\n      assert.deepEqual(el.taps, []);\n\n      // tap an element with a disabled ancestor\n      target = el.$.nested;\n      // simulate the event sequence of a touch on the screen\n      touches = [{\n        clientX: 0,\n        clientY: 0,\n        identifier: 1,\n        // target is set to the element with `addEventListener`, which is `target`\n        target\n      }];\n      touchstart = new CustomEvent('touchstart', {bubbles: true, composed: true});\n      touchstart.changedTouches = touchstart.touches = touches;\n      target.dispatchEvent(touchstart);\n      touchend = new CustomEvent('touchend', {bubbles: true, composed: true});\n      touchend.touches = touchend.changedTouches = touches;\n      target.dispatchEvent(touchend);\n      assert.deepEqual(el.taps, ['button#nested']);\n\n      resetMouseCanceller();\n\n      // tap a custom element with a `disabled` property\n      target = el.$.disabledEl;\n      // simulate the event sequence of a touch on the screen\n      touches = [{\n        clientX: 0,\n        clientY: 0,\n        identifier: 1,\n        // target is set to the element with `addEventListener`, which is `target`\n        target\n      }];\n      touchstart = new CustomEvent('touchstart', {bubbles: true, composed: true});\n      touchstart.changedTouches = touchstart.touches = touches;\n      target.dispatchEvent(touchstart);\n      touchend = new CustomEvent('touchend', {bubbles: true, composed: true});\n      touchend.touches = touchend.changedTouches = touches;\n      target.dispatchEvent(touchend);\n      assert.deepEqual(el.taps, ['button#nested', 'x-disabled#disabledEl']);\n      document.body.removeChild(el);\n    });\n\n    test('test all \"disableable\" elements', function() {\n      const el = document.createElement('all-disabled');\n      document.body.appendChild(el);\n      el.tapAll();\n      assert.deepEqual(el.taps, []);\n      document.body.removeChild(el);\n    });\n  });\n});\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/globals.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script type=\"module\">\nwindow.origOwnProps = Object.getOwnPropertyNames(window).reduce(function(props, prop) {\n  return props[prop] = true && props;\n}, {});\n</script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n<body>\n<!-- Exercise the core features of Polymer -->\n\n<dom-module id=\"shared-styles\">\n  <template strip-whitespace>\n    <style>:host{ --foo: var(--bar); };</style>\n  </template>\n</dom-module>\n<dom-module id=\"global-test\">\n  <template strip-whitespace>\n    <style include=\"shared-styles\">:host{ --foo: var(--bar); };</style>\n    <div class$=\"{{stuff.is.here}}\">{{bindings(are, cool)}}</div>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'global-test',\n  properties: {\n    foo: {\n      notify: true,\n      reflectToAttribute: true,\n      observer: 'observeFoo',\n      value: 'foo'\n    }\n  },\n  observers: ['observeFooDeep(foo.*)'],\n  hostAttributes: {\n    tabIndex: 0\n  },\n  listeners: {\n    tap: 'handleTap'\n  },\n  observeFooDeep() {},\n  observeFoo() {}\n});\n</script>\n</dom-module>\n\n<global-test></global-test>\n\n<script type=\"module\">\nimport '../../polymer-legacy.js';\n\n/* global origOwnProps */\nsuite('globals', function() {\n\n  var expected = {\n    origOwnProps: true,\n\n    // Test harness\n    a11ySuite: true,\n    assert: true,\n    expect: true,\n    run: true,\n    fixture: true,\n    replace: true,\n    stub: true,\n\n    // Polymer\n    JSCompiler_renameProperty: true,\n\n    // weird safari + selenium globals\n    alert: true,\n    confirm: true,\n    prompt: true,\n\n    // weird Firefox event\n    NotifyPaintEvent: true,\n\n    // module-to-amd transform\n    require: true,\n    resolve: true,\n    _wctCallback: true\n  };\n\n  test('check global leakage', function() {\n    // Only run on native ES6 browsers, to avoid transpiler globals\n    if (!window._classCallCheck) {\n      var newProps = Object.getOwnPropertyNames(window).filter(function(prop) {\n        return !origOwnProps[prop] && !expected[prop];\n      });\n      assert.equal(newProps.length, 0, 'new globals added: \\n' + newProps.sort().join('\\n'));\n    }\n  });\n\n});\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/html-tag.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n</head>\n<body>\n  <script type=\"module\">\nimport { html, htmlLiteral } from '../../lib/utils/html-tag.js';\nimport { PolymerElement } from '../../polymer-element.js';\nimport { Polymer } from '../../lib/legacy/polymer-fn.js';\nsuite('html function', function() {\n  test('html makes an HTML template', function() {\n    let t = html``;\n    assert.instanceOf(t, HTMLTemplateElement);\n  });\n  test('template output has elements', function() {\n    let t = html`<div><span></span></div><!-- hi -->`;\n    assert(t.content.querySelector('div'));\n    assert(t.content.querySelector('span'));\n    assert.instanceOf(t.content.lastChild, Comment);\n  });\n  test('escaping works as expected', function() {\n    let t = html`<span>the \\`price\\` is \\${{foo}}\\n</span>`;\n    assert.equal(t.innerHTML, '<span>the `price` is ${{foo}}\\n</span>');\n  });\n  test('interpolation of non-templates throw', function() {\n    assert.throws(() => html`<div>${'a'}</div>`);\n  });\n  test('interpolation of templates include the template contents', function() {\n    let t1 = html`<div></div>`;\n    let t2 = html`<span>${t1}</span>`;\n    assert.equal(t2.innerHTML, '<span><div></div></span>');\n  });\n  test('interpolation of literal values', function() {\n    let s1 = htmlLiteral`hello`;\n    assert.equal(s1.value, `hello`);\n    let s2 = htmlLiteral`hello${htmlLiteral` ${htmlLiteral`world`}!`}!`;\n    assert.equal(s2.value, 'hello world!!');\n  });\n  test('interpolation of literal values within html values', function() {\n    let s1 = htmlLiteral`foo`;\n    let s2 = htmlLiteral`display: block;`;\n    let t = html`<style>:host {${s2}}</style><div ${s1}></div>`;\n    assert.equal(t.innerHTML, `<style>:host {display: block;}</style><div foo=\"\"></div>`);\n  });\n});\nsuite('Polymer + html fn', function() {\n  suiteSetup(function() {\n\n    class HtmlFn extends PolymerElement {\n      static get is() {return 'html-fn';}\n      static get template() {\n        return html`\n        <style>\n          :host {\n            display: block;\n          }\n        </style>\n        <div id=\"child\">\n          [[databoundProperty]]\n        </div>\n        `;\n      }\n      static get properties() {\n        return {\n          databoundProperty: String\n        };\n      }\n      ready() {\n        super.ready();\n        this.databoundProperty = 'first';\n      }\n    }\n\n    customElements.define(HtmlFn.is, HtmlFn);\n\n    class HtmlFnSub extends HtmlFn {\n      static get is() {return 'html-fn-sub';}\n      static get template() {\n        return html`\n        <div id=\"super\">\n          ${super.template}\n        </div>\n        `;\n      }\n      ready() {\n        super.ready();\n        this.databoundProperty = 'second';\n      }\n    }\n\n    customElements.define(HtmlFnSub.is, HtmlFnSub);\n\n    Polymer({\n      is: 'html-legacy',\n      _template: html`\n        <div id=\"child\">[[databoundProperty]]</div>\n      `,\n      properties: {\n        databoundProperty: {\n          type: String,\n          value: 'legacy'\n        }\n      }\n    });\n  });\n\n  test('Polymer elements can use html fn', function () {\n    let el = document.createElement('html-fn');\n    document.body.appendChild(el);\n    assert(el.shadowRoot);\n    assert.equal(el.$.child.textContent.trim(), 'first');\n  });\n\n  test('subclass elements can embed the superclass template', function() {\n    let el = document.createElement('html-fn-sub');\n    document.body.appendChild(el);\n    assert(el.$.super);\n    assert(el.$.child);\n    assert.equal(el.$.child.textContent.trim(), 'second');\n  });\n\n  test('legacy element works with html fn', function() {\n    let el = document.createElement('html-legacy');\n    document.body.appendChild(el);\n    assert(el.shadowRoot);\n    assert.equal(el.$.child.textContent.trim(), 'legacy');\n  });\n});\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/importHref.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../lib/utils/import-href.js\"></script>\n<body>\n\n<x-test></x-test>\n\n<script type=\"module\">\nimport { importHref } from '../../lib/utils/import-href.js';\nimport { PolymerElement } from '../../polymer-element.js';\nimport { Base } from '../../polymer-legacy.js';\n\nsuite('importHref', function() {\n\n  let parsedEl = document.querySelector('x-test');\n\n  test('importing polymer via Polymer.importHref', function(done) {\n    assert.notOk(PolymerElement);\n    importHref('../../polymer.html', function() {\n      assert.ok(PolymerElement);\n      done();\n    });\n  });\n\n  test('element loaded with Polymer.Base.importHref upgrades properly', function(done) {\n    Base.importHref('sub/x-test.html', function() {\n      assert.ok(parsedEl.$.sub, 'parsed element not upgraded with template when import loaded');\n      assert.notOk(parsedEl.$.sub.$, 'sub element of imported element should not yet be upgraded');\n      var el = document.createElement('x-test');\n      document.body.appendChild(el);\n      assert.ok(el.$.sub, 'imperatively created element not upgraded with template when import loaded');\n      done();\n    });\n  });\n\n  test('sub-element loaded with instance importHref upgrades properly', function(done) {\n    parsedEl.importHref('sub/x-sub.html', function() {\n      assert.equal(this, parsedEl);\n      assert.ok(parsedEl.$.sub.$.test, 'sub element not upgraded when import loaded');\n      done();\n    });\n  });\n\n  test('load is triggered on second call', function(done) {\n    Base.importHref('sub/x-test.html', function() {\n      Base.importHref('sub/x-test.html', function() {\n        done();\n      });\n    });\n  });\n\n});\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/inheritance.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n<body>\n\n  <dom-module id=\"uses-underscore-template\">\n    <template><div>error</div></template>\n  </dom-module>\n\n  <dom-module id=\"uses-dom-module\">\n    <template><div>from-dom-module</div></template>\n  </dom-module>\n\n  <dom-module id=\"no-template\">\n    <template><div>error</div></template>\n  </dom-module>\n\n  <dom-module id=\"base-el\">\n    <template>\n      <style>\n        :host {\n          display: block;\n          color: red;\n        }\n        code {\n          color: black;\n        }\n      </style>\n      <!-- dummy nodes with notes be removed by subclass -->\n      <i i=[[i]]></i>\n      <i i=[[i]]></i>\n      <i i=[[i]]></i>\n      <i i=[[i]]></i>\n      <i i=[[i]]></i>\n      <input id=\"input\" value=\"{{foo::input}}\" on-custom=\"handleCustomEvent\">\n      <span>base element: <code>foo = [[foo]]</code></span>\n    </template>\n\n    <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nclass BaseEl extends PolymerElement {\n  static get is() { return 'base-el'; }\n  static get properties() {\n    return { foo: { type: String, value: 5 } };\n  }\n  constructor() {\n    super();\n    this.handleCustomEvent = sinon.spy();\n  }\n}\ncustomElements.define(BaseEl.is, BaseEl);\nwindow.BaseEl = BaseEl;\n</script>\n  </dom-module>\n\n  <dom-module id=\"child-el\">\n    <script type=\"module\">\nclass ChildEl extends window.BaseEl {\n  static get is() { return 'child-el'; }\n  static get properties() {\n    return { bar: { type: String, value: 3 } };\n  }\n}\ncustomElements.define(ChildEl.is, ChildEl);\nwindow.ChildEl = ChildEl;\n</script>\n  </dom-module>\n\n  <dom-module id=\"grand-child-el\">\n    <script type=\"module\">\nclass GrandChildEl extends window.ChildEl {\n  static get is() { return 'grand-child-el'; }\n  static get properties() {\n    return { bar: { type: String, value: 3 } };\n  }\n}\ncustomElements.define(GrandChildEl.is, GrandChildEl);\nwindow.GrandChildEl = GrandChildEl;\n</script>\n  </dom-module>\n\n  <dom-module id=\"child-el-with-template\">\n    <template>should ignore this template</template>\n    <script type=\"module\">\nclass ChildElWithTemplate extends window.GrandChildEl {\n  static get properties() {\n    return { bar: { type: String, value: 3 } };\n  }\n  static get template() {\n    var template = window.GrandChildEl.template.cloneNode(true);\n    var div = document.createElement('div');\n    div.textContent = 'child';\n    template.content.appendChild(div);\n    // Move input to the end\n    template.content.appendChild(template.content.querySelector('#input'));\n    // Remove all the <i>'s, such that the total number of nodes in\n    // this template is less than the super\n    Array.from(template.content.querySelectorAll('i'))\n      .forEach(i=>i.parentNode.removeChild(i));\n    return template;\n  }\n}\ncustomElements.define('child-el-with-template', ChildElWithTemplate);\nwindow.ChildElWithTemplate = ChildElWithTemplate;\n</script>\n  </dom-module>\n\n  <dom-module id=\"parent-element-template-overriding\">\n    <script type=\"module\">\nimport { html } from '../../lib/utils/html-tag.js';\nimport { PolymerElement } from '../../polymer-element.js';\nclass ParentElementWithTemplate extends PolymerElement {\n  static get template() {\n    return html`This template should not exist`;\n  }\n}\nclass ChildWithNoTemplate extends ParentElementWithTemplate {\n  static get template() {\n    return null;\n  }\n}\ncustomElements.define('child-with-no-template', ChildWithNoTemplate);\n</script>\n  </dom-module>\n\n  <test-fixture id=\"basic\">\n    <template>\n      <base-el></base-el>\n      <child-el></child-el>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"basic-with-attributes\">\n    <template>\n      <base-el></base-el>\n      <child-el foo=\"7\" bar=\"7\"></child-el>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"with-template\">\n    <template>\n      <base-el></base-el>\n      <child-el-with-template></child-el-with-template>\n    </template>\n  </test-fixture>\n\n  <script type=\"module\">\nimport { html } from '../../lib/utils/html-tag.js';\nimport { Polymer } from '../../polymer-legacy.js';\n\nsuite('ChildElement extends BaseElement', function() {\n  test('child has base properties', function() {\n    var f = fixture('basic');\n    var child = f[1];\n    assert.equal(child.foo, 5);\n    assert.equal(child.bar, 3);\n  });\n\n  test('child can change base properties', function() {\n    var f  = fixture('basic-with-attributes');\n    var child = f[1];\n    assert.equal(child.foo, 7);\n    assert.equal(child.bar, 7);\n  });\n\n  test('child has base template and style', function() {\n    var f = fixture('basic');\n    var base = f[0];\n    var child = f[1];\n\n    // Child template is the same as the base template.\n    assert.equal(child.shadowRoot.childNodes.length, child.shadowRoot.childNodes.length);\n    for (var i=0; i < child.shadowRoot.childNodes.length; i++) {\n      var childEl = child.shadowRoot.childNodes[i];\n      var baseEl = child.shadowRoot.childNodes[i];\n      assert.equal(childEl.innerHTML, baseEl.innerHTML);\n    }\n\n    // And it's something that we expect.\n    var code = child.shadowRoot.querySelector('code');\n    assert.equal(code.innerHTML, 'foo = 5');\n\n    // And the base style is the same.\n    assert.equal(getComputedStyle(base).color, getComputedStyle(child).color);\n\n    // Id map works as expected\n    assert.equal(child.$.input.localName, 'input');\n    assert.equal(child.$.input.id, 'input');\n\n    // 2-way bindings work as expected\n    child.$.input.value = 'changed';\n    child.$.input.dispatchEvent(new CustomEvent('input'));\n    assert.equal(child.foo, 'changed');\n\n    // Declarative event listeners work as expected\n    assert.equal(child.handleCustomEvent.callCount, 0);\n    child.$.input.dispatchEvent(new CustomEvent('custom'));\n    assert.equal(child.handleCustomEvent.callCount, 1);\n  });\n\n  test('child with properties has updated base template', function() {\n    var f = fixture('basic-with-attributes');\n    var base = f[0];\n    var child = f[1];\n\n    // Child template is not the same as the base template.\n    assert.notEqual(child.shadowRoot.innerHTML, base.shadowRoot.innerHTML);\n\n    // And it's something that we expect.\n    var code = child.shadowRoot.querySelector('code');\n    assert.equal(code.innerHTML, 'foo = 7');\n  });\n});\n\nsuite('ChildElement extends BaseElement and the template', function() {\n  test('child has base properties', function() {\n    var f = fixture('with-template');\n    var child = f[1];\n    assert.equal(child.foo, 5);\n    assert.equal(child.bar, 3);\n  });\n\n  test('child has derived template and style', function() {\n    var f = fixture('with-template');\n    var base = f[0];\n    var child = f[1];\n\n    // Child template is not the same as the base template.\n    assert.notEqual(child.shadowRoot.innerHTML, base.shadowRoot.innerHTML);\n\n    // And it's something that we expect.\n    assert.equal(child.shadowRoot.querySelector('code').innerHTML, 'foo = 5');\n    assert.equal(child.shadowRoot.querySelector('div').innerHTML, 'child');\n\n    // And the base style is the same.\n    assert.equal(getComputedStyle(base).color, getComputedStyle(child).color);\n\n    // Id map works as expected\n    assert.equal(child.$.input.localName, 'input');\n    assert.equal(child.$.input.id, 'input');\n\n    // 2-way bindings work as expected\n    child.$.input.value = 'changed';\n    child.$.input.dispatchEvent(new CustomEvent('input'));\n    assert.equal(child.foo, 'changed');\n\n    // Declarative event listeners work as expected\n    assert.equal(child.handleCustomEvent.callCount, 0);\n    child.$.input.dispatchEvent(new CustomEvent('custom'));\n    assert.equal(child.handleCustomEvent.callCount, 1);\n  });\n});\n\nsuite('child overriding a template', function() {\n  let el;\n\n  setup(function() {\n    el = document.createElement('child-with-no-template');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('returning null nullifies the parent template', function() {\n    assert.equal(el.shadowRoot, null);\n  });\n});\n\nsuite('Legacy _template property: null/undefined', function() {\n\n  let el;\n  teardown(function() {\n    if (el) {\n      document.body.removeChild(el);\n    }\n  });\n\n  test('_template: returning template works', function() {\n    Polymer({\n      is: 'uses-underscore-template',\n      _template:  html`<div>from-underscore-template</div>`\n    });\n    const el = document.createElement('uses-underscore-template');\n    document.body.appendChild(el);\n    assert.equal(el.shadowRoot.firstChild.textContent, 'from-underscore-template');\n  });\n\n  test('_template: undefined falls back to dom-module', function() {\n    Polymer({\n      is: 'uses-dom-module',\n      _template: undefined\n    });\n    const el = document.createElement('uses-dom-module');\n    document.body.appendChild(el);\n    assert.equal(el.shadowRoot.firstChild.textContent, 'from-dom-module');\n  });\n\n  test('_template: null overrides dom-module', function() {\n    Polymer({\n      is: 'no-template',\n      _template: null\n    });\n    const el = document.createElement('no-template');\n    document.body.appendChild(el);\n    assert.notOk(el.shadowRoot);\n  });\n\n  test('_template: returning template works in sub-class', function() {\n    customElements.define('sub-uses-underscore-template', class extends customElements.get('uses-underscore-template') {\n      get _template() { return this._$tmpl || html`<div>sub-from-underscore-template</div>`; }\n      set _template(v) { this._$tmpl = v; }\n    });\n    const el = document.createElement('sub-uses-underscore-template');\n    document.body.appendChild(el);\n    assert.equal(el.shadowRoot.firstChild.textContent, 'sub-from-underscore-template');\n  });\n\n  test('_template: undefined falls back to dom-module in sub-class', function() {\n    customElements.define('sub-uses-dom-module', class extends customElements.get('uses-dom-module') {\n      get _template() { return this._$tmpl || undefined; }\n      set _template(v) { this._$tmpl = v; }\n    });\n    const el = document.createElement('sub-uses-dom-module');\n    document.body.appendChild(el);\n    assert.equal(el.shadowRoot.firstChild.textContent, 'from-dom-module');\n  });\n\n  test('_template: null overrides dom-module in sub-class', function() {\n    customElements.define('sub-no-template', class extends customElements.get('no-template') {\n      get _template() { return this._$tmpl || null; }\n      set _template(v) { this._$tmpl = v; }\n    });\n    const el = document.createElement('sub-no-template');\n    document.body.appendChild(el);\n    assert.notOk(el.shadowRoot);\n  });\n\n});\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/legacy-data.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <!-- Applies LegacyDataMixin to all legacy Polymer({..}) elements -->\n  <script type=\"module\" src=\"../../lib/legacy/legacy-data-mixin.js\"></script>\n</head>\n<body>\n\n  <dom-module id=\"x-data\">\n    <template>\n      <div id=\"child\"\n        computed-single=\"[[computeSingle(inlineSingleDep)]]\"\n        computed-multi=\"[[computeMulti(inlineMultiDep1, inlineMultiDep2)]]\">\n        <dom-if if>\n          <template><div id=\"ifChild\" computed-multi=\"[[computeMulti(inlineMultiIfDep1, inlineMultiIfDep2)]]\"></div></template>\n        </dom-if>\n      </div>\n    </template>\n    <script type=\"module\">\n      import {Polymer} from '../../polymer-legacy.js';\n      Polymer({\n        is: 'x-data',\n        _legacyUndefinedCheck: true,\n        properties: {\n          singleProp: String,\n          multiProp1: String,\n          multiProp2: String,\n          computedSingleDep: String,\n          computedMultiDep1: String,\n          computedMultiDep2: String,\n          inlineSingleDep: String,\n          inlineMultiDep1: String,\n          inlineMultiDep2: String,\n          inlineMultiIfDep1: String,\n          inlineMultiIfDep2: String,\n          computedSingle: {\n            computed: 'computeSingle(computedSingleDep)'\n          },\n          computedMulti: {\n            computed: 'computeMulti(computedMultiDep1, computedMultiDep2)'\n          },\n          wildcardProp: String,\n          wildcardObj: Object\n        },\n        observers: [\n          'staticObserver(\"staticObserver\")',\n          'singlePropObserver(singleProp)',\n          'multiPropObserver(multiProp1, multiProp2)',\n          'throws(throwProp)',\n          'wildcardObserver(wildcardProp, wildcardObj.*)'\n        ],\n        created() {\n          this.singlePropObserver = sinon.spy();\n          this.multiPropObserver = sinon.spy();\n          this.staticObserver = sinon.spy();\n          this.computeSingle = sinon.spy((inlineSingleDep) => `[${inlineSingleDep}]`);\n          this.computeMulti = sinon.spy((inlineMultiDep1, inlineMultiDep2) => `[${inlineMultiDep1},${inlineMultiDep2}]`);\n          this.wildcardObserver = sinon.spy();\n        },\n        throws() {\n          throw new Error('real error');\n        }\n      });\n    </script>\n  </dom-module>\n\n  <test-fixture id=\"declarative-none\">\n    <template>\n      <x-data></x-data>\n    </template>\n  </test-fixture>\n  \n  <test-fixture id=\"declarative-single\">\n    <template>\n      <x-data single-prop=\"a\"></x-data>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"declarative-multi-one\">\n    <template>\n      <x-data multi-prop1=\"b\"></x-data>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"declarative-multi-all\">\n    <template>\n      <x-data multi-prop1=\"b\" multi-prop2=\"c\"></x-data>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"declarative-single-computed\">\n    <template>\n      <x-data computed-single-dep=\"a\"></x-data>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"declarative-multi-one-computed\">\n    <template>\n      <x-data computed-multi-dep1=\"b\"></x-data>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"declarative-multi-all-computed\">\n    <template>\n      <x-data computed-multi-dep1=\"b\" computed-multi-dep2=\"c\"></x-data>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"declarative-single-computed-inline\">\n    <template>\n      <x-data inline-single-dep=\"a\"></x-data>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"declarative-multi-one-computed-inline\">\n    <template>\n      <x-data inline-multi-dep1=\"b\"></x-data>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"declarative-multi-all-computed-inline\">\n    <template>\n      <x-data inline-multi-dep1=\"b\" inline-multi-dep2=\"c\"></x-data>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"declarative-multi-if-one-computed-inline\">\n    <template>\n      <x-data inline-multi-if-dep1=\"b\"></x-data>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"declarative-multi-if-all-computed-inline\">\n    <template>\n      <x-data inline-multi-if-dep1=\"b\" inline-multi-if-dep2=\"c\"></x-data>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"declarative-wildcard-one\">\n    <template>\n      <x-data wildcard-prop='prop'></x-data>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"declarative-wildcard-all\">\n    <template>\n      <x-data wildcard-prop=\"prop\" wildcard-obj='{\"prop\": \"wildcardObj\"}'></x-data>\n    </template>\n  </test-fixture>\n\n  <script type=\"module\">\n    import {flush} from '../../lib/utils/flush.js';\n\n    let el;\n\n    function assertEffects(callCounts) {\n      assert.equal(el.staticObserver.callCount, 1, 'staticObserver call count wrong');\n      assert.equal(el.singlePropObserver.callCount, \n        callCounts.singlePropObserver || 0, 'singlePropObserver call count wrong');\n      assert.equal(el.multiPropObserver.callCount,\n        callCounts.multiPropObserver || 0, 'multiPropObserver call count wrong');\n      assert.equal(el.computeSingle.callCount,\n        callCounts.computeSingle || 0, 'computeSingle call count wrong');\n      assert.equal(el.computeMulti.callCount,\n        callCounts.computeMulti || 0, 'computeMulti call count wrong');\n      assert.equal(console.warn.callCount, callCounts.warn || 0,\n        'console.warn call count wrong');\n    }\n\n    suite('imperative', () => {\n\n      setup(() => sinon.spy(console, 'warn'));\n      \n      function setupElement(check, props) {\n        el = document.createElement('x-data');\n        el._legacyUndefinedCheck = check;\n        Object.assign(el, props);\n        document.body.appendChild(el);\n        flush();\n      }\n\n      teardown(() => {\n        console.warn.restore();\n        el.parentNode.removeChild(el);\n      });\n\n      const singleProp = 'singleProp';\n      const multiProp1 = 'multiProp1';\n      const multiProp2 = 'multiProp2';\n      const computedSingleDep = 'computedSingleDep';\n      const computedMultiDep1 = 'computedMultiDep1';\n      const computedMultiDep2 = 'computedMultiDep2';\n      const inlineSingleDep = 'inlineSingleDep';\n      const inlineMultiDep1 = 'inlineMultiDep1';\n      const inlineMultiDep2 = 'inlineMultiDep2';\n      const inlineMultiIfDep1 = 'inlineMultiIfDep1';\n      const inlineMultiIfDep2 = 'inlineMultiIfDep2';\n      const wildcardProp = 'wildcardProp';\n      const wildcardObj = {prop: 'wildcardObj'};\n\n      suite('check disabled', () => {\n        test('no arguments defined', () => {\n          setupElement(false, {});\n          assertEffects({});\n        });\n        test('singlePropObserver argument defined', () => {\n          setupElement(false, {singleProp});\n          assertEffects({singlePropObserver: 1});\n        });\n        test('one multiPropObserver arguments defined', () => {\n          setupElement(false, {multiProp1});\n          assertEffects({multiPropObserver: 1});\n        });\n        test('all multiPropObserver defined', () => {\n          setupElement(false, {multiProp1, multiProp2});\n          assertEffects({multiPropObserver: 1});\n        });\n        test('singlePropObserver argument undefined', () => {\n          setupElement(false, {singleProp});\n          assertEffects({singlePropObserver: 1});\n          el.singleProp = undefined;\n          assertEffects({singlePropObserver: 2});\n        });\n        test('one multiPropObserver arguments undefined', () => {\n          setupElement(false, {multiProp1, multiProp2});\n          assertEffects({multiPropObserver: 1});\n          el.multiProp1 = undefined;\n          assertEffects({multiPropObserver: 2});\n        });\n        test('all multiPropObserver undefined', () => {\n          setupElement(false, {multiProp1, multiProp2});\n          assertEffects({multiPropObserver: 1});\n          el.multiProp1 = undefined;\n          assertEffects({multiPropObserver: 2});\n          el.multiProp2 = undefined;\n          assertEffects({multiPropObserver: 3});\n        });\n        test('computeSingle argument defined', () => {\n          setupElement(false, {computedSingleDep});\n          assertEffects({computeSingle: 1});\n          assert.equal(el.computedSingle, '[computedSingleDep]');\n        });\n        test('one computeMulti argument defined', () => {\n          setupElement(false, {computedMultiDep1});\n          assertEffects({computeMulti: 1});\n          assert.equal(el.computedMulti, '[computedMultiDep1,undefined]');\n        });\n        test('all computeMulti argument defined', () => {\n          setupElement(false, {computedMultiDep1, computedMultiDep2});\n          assertEffects({computeMulti: 1});\n          assert.equal(el.computedMulti, '[computedMultiDep1,computedMultiDep2]');\n        });\n        test('inline computeSingle argument defined', () => {\n          setupElement(false, {inlineSingleDep});\n          assertEffects({computeSingle: 1});\n          assert.equal(el.$.child.computedSingle, '[inlineSingleDep]');\n        });\n        test('one inline computeMulti argument defined', () => {\n          setupElement(false, {inlineMultiDep1});\n          assertEffects({computeMulti: 1});\n          assert.equal(el.$.child.computedMulti, '[inlineMultiDep1,undefined]');\n        });\n        test('all inline computeMulti argument defined', () => {\n          setupElement(false, {inlineMultiDep1, inlineMultiDep2});\n          assertEffects({computeMulti: 1});\n          assert.equal(el.$.child.computedMulti, '[inlineMultiDep1,inlineMultiDep2]');\n        });\n        test('one inline computeMulti argument defined in dom-if', () => {\n          setupElement(false, {inlineMultiIfDep1});\n          assertEffects({computeMulti: 1});\n          assert.equal(el.$$('#ifChild').computedMulti, '[inlineMultiIfDep1,undefined]');\n        });\n        test('all inline computeMulti argument defined in dom-if', () => {\n          setupElement(false, {inlineMultiIfDep1, inlineMultiIfDep2});\n          assertEffects({computeMulti: 1});\n          assert.equal(el.$$('#ifChild').computedMulti, '[inlineMultiIfDep1,inlineMultiIfDep2]');\n        });\n        test('one wildcard argument defined', () => {\n          setupElement(false, {wildcardProp});\n          assertEffects({wildcardObserver: 1});\n        });\n        test('all wildcard arguments defined', () => {\n          setupElement(false, {wildcardProp, wildcardObj});\n          assertEffects({wildcardObserver: 1});\n        });\n      });\n\n      suite('warn', () => {\n        test('no arguments defined', () => {\n          setupElement(true, {});\n          assertEffects({});\n        });\n        test('singlePropObserver argument defined', () => {\n          setupElement(true, {singleProp});\n          assertEffects({singlePropObserver: 1});\n        });\n        test('one multiPropObserver arguments defined', () => {\n          setupElement(true, {multiProp1});\n          assertEffects({multiPropObserver: 0, warn: 1});\n        });\n        test('all multiPropObserver defined', () => {\n          setupElement(true, {multiProp1, multiProp2});\n          assertEffects({multiPropObserver: 1});\n        });\n        test('singlePropObserver argument undefined', () => {\n          setupElement(true, {singleProp});\n          assertEffects({singlePropObserver: 1});\n          el.singleProp = undefined;\n          assertEffects({singlePropObserver: 2});\n        });\n        test('one multiPropObserver arguments undefined', () => {\n          setupElement(true, {multiProp1, multiProp2});\n          assertEffects({multiPropObserver: 1});\n          el.multiProp1 = undefined;\n          assertEffects({multiPropObserver: 1, warn: 1});\n        });\n        test('all multiPropObserver undefined', () => {\n          setupElement(true, {multiProp1, multiProp2});\n          assertEffects({multiPropObserver: 1});\n          el.multiProp1 = undefined;\n          assertEffects({multiPropObserver: 1, warn: 1});\n          el.multiProp2 = undefined;\n          assertEffects({multiPropObserver: 1, warn: 2});\n        });\n        test('computeSingle argument defined', () => {\n          setupElement(true, {computedSingleDep});\n          assertEffects({computeSingle: 1});\n          assert.equal(el.computedSingle, '[computedSingleDep]');\n        });\n        test('one computeMulti argument defined', () => {\n          setupElement(true, {computedMultiDep1});\n          assertEffects({warn: 1});\n          assert.equal(el.computedMulti, undefined);\n        });\n        test('all computeMulti argument defined', () => {\n          setupElement(true, {computedMultiDep1, computedMultiDep2});\n          assertEffects({computeMulti: 1});\n          assert.equal(el.computedMulti, '[computedMultiDep1,computedMultiDep2]');\n        });\n        test('inline computeSingle argument defined', () => {\n          setupElement(true, {inlineSingleDep});\n          assertEffects({computeSingle: 1});\n          assert.equal(el.$.child.computedSingle, '[inlineSingleDep]');\n        });\n        test('one inline computeMulti argument defined', () => {\n          setupElement(true, {inlineMultiDep1});\n          assertEffects({warn: 1});\n          assert.equal(el.$.child.computedMulti, undefined);\n        });\n        test('all inline computeMulti argument defined', () => {\n          setupElement(true, {inlineMultiDep1, inlineMultiDep2});\n          assertEffects({computeMulti: 1});\n          assert.equal(el.$.child.computedMulti, '[inlineMultiDep1,inlineMultiDep2]');\n        });\n        test('one inline computeMulti argument defined in dom-if', () => {\n          setupElement(true, {inlineMultiIfDep1});\n          assertEffects({warn: 1});\n          assert.equal(el.$$('#ifChild').computedMulti, undefined);\n        });\n        test('all inline computeMulti argument defined in dom-if', () => {\n          setupElement(true, {inlineMultiIfDep1, inlineMultiIfDep2});\n          assertEffects({computeMulti: 1});\n          assert.equal(el.$$('#ifChild').computedMulti, '[inlineMultiIfDep1,inlineMultiIfDep2]');\n        });\n        test('one wildcard argument defined', () => {\n          setupElement(true, {wildcardProp});\n          assertEffects({warn: 1});\n        });\n        test('all wildcard arguments defined', () => {\n          setupElement(true, {wildcardProp, wildcardObj});\n          assertEffects({wildcardObserver: 1});\n        });\n      });\n    });\n\n    suite('declarative', () => {\n\n      setup(() => sinon.spy(console, 'warn'));\n\n      teardown(() => console.warn.restore());\n\n      suite('warn', () => {\n        test('no arguments defined', () => {\n          el = fixture('declarative-none');\n          assertEffects({});\n        });\n        test('singlePropObserver argument defined', () => {\n          el = fixture('declarative-single');\n          assertEffects({singlePropObserver: 1});\n        });\n        test('one multiPropObserver arguments defined', () => {\n          el = fixture('declarative-multi-one');\n          assertEffects({multiPropObserver: 0, warn: 1});\n        });\n        test('all multiPropObserver defined', () => {\n          el = fixture('declarative-multi-all');\n          assertEffects({multiPropObserver: 1});\n        });\n        test('computeSingle argument defined', () => {\n          el = fixture('declarative-single-computed');\n          assertEffects({computeSingle: 1});\n          assert.equal(el.computedSingle, '[a]');\n        });\n        test('one computeMulti arguments defined', () => {\n          el = fixture('declarative-multi-one-computed');\n          assertEffects({computeMulti: 0, warn: 1});\n          assert.equal(el.computedMulti, undefined);\n        });\n        test('all computeMulti defined', () => {\n          el = fixture('declarative-multi-all-computed');\n          assert.equal(el.computedMulti, '[b,c]');\n        });\n        test('inline computeSingle argument defined', () => {\n          el = fixture('declarative-single-computed-inline');\n          assertEffects({computeSingle: 1});\n          assert.equal(el.$.child.computedSingle, '[a]');\n        });\n        test('inline one computeMulti arguments defined', () => {\n          el = fixture('declarative-multi-one-computed-inline');\n          assertEffects({computeMulti: 0, warn: 1});\n          assert.equal(el.$.child.computedMulti, undefined);\n        });\n        test('inline all computeMulti defined', () => {\n          el = fixture('declarative-multi-all-computed-inline');\n          assertEffects({computeMulti: 1});\n          assert.equal(el.$.child.computedMulti, '[b,c]');\n        });\n        test('one inline computeMulti argument defined in dom-if', () => {\n          el = fixture('declarative-multi-if-one-computed-inline');\n          flush();\n          assertEffects({computeMulti: 0, warn: 1});\n          assert.equal(el.$$('#ifChild').computedMulti, undefined);\n        });\n        test('all inline computeMulti argument defined in dom-if', () => {\n          el = fixture('declarative-multi-if-all-computed-inline');\n          flush();\n          assertEffects({computeMulti: 1});\n          assert.equal(el.$$('#ifChild').computedMulti, '[b,c]');\n        });\n        test('one wildcard argument defined', () => {\n          el = fixture('declarative-wildcard-one');\n          flush();\n          assertEffects({warn: 1});\n        });\n        test('all wildcard arguments defined', () => {\n          el = fixture('declarative-wildcard-all');\n          flush();\n          assertEffects({wildcardObserver: 1});\n        });\n      });\n    });\n\n    suite('other', () => {\n      test('real errors still throw', () => {\n        const el = document.createElement('x-data');\n        document.body.appendChild(el);\n        assert.throws(() => {\n          el.throwProp = true;\n        }, /real error/);\n        document.body.removeChild(el);\n      });\n    });\n    \n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/legacy-noattributes.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\">\n    import {setLegacyNoObservedAttributes, setLegacyOptimizations} from '../../lib/utils/settings.js';\n    setLegacyNoObservedAttributes(true);\n    setLegacyOptimizations(true);\n  </script>\n</head>\n<body>\n\n  <dom-module id=\"x-child\">\n    <template>\n      <div id=\"content\">[[foo]]</div>\n    </template>\n    <script type=\"module\">\n      import {Polymer} from '../../polymer-legacy.js';\n      Polymer({\n        is: 'x-child',\n        properties: {\n          foo: {type: String, value: 'default'},\n          bar: {type: String, value: 'default'},\n          zot: {type: Boolean, value: false, reflectToAttribute: true},\n          camelCase: String\n        },\n        ready() {\n          this.isEnabled = true;\n        }\n      });\n    </script>\n  </dom-module>\n\n  <dom-module id=\"x-attrs\">\n    <template>\n      <x-child id=\"child1\" foo=\"x-attrs.foo\" bar$=\"[[bar]]\" zot$=\"[[zot]]\" camel-case=\"camelCase\"></x-child>\n      <x-child id=\"child2\" foo=\"x-attrs.foo\" bar$=\"[[bar]]\" zot$=\"[[zot]]\" camel-case=\"[[camelCase]]\" disable-upgrade></x-child>\n      <x-child id=\"child3\" foo=\"x-attrs.foo\" bar$=\"[[bar]]\" zot$=\"[[zot]]\" camel-case=\"[[camelCase]]\" disable-upgrade$=\"[[disabled]]\"></x-child>\n      <div id=\"ifContainer\">\n        <dom-if if=\"[[shouldIf]]\">\n          <template><x-child foo=\"x-attrs.foo\" bar$=\"[[bar]]\" zot$=\"[[zot]]\" camel-case=\"[[camelCase]]\"></x-child></template>\n        </dom-if>\n      </div>\n    </template>\n    <script type=\"module\">\n      import {Polymer} from '../../polymer-legacy.js';\n      Polymer({\n        is: 'x-attrs',\n        properties: {\n          foo: String,\n          bar: {type: String, value: 'bar'},\n          zot: Boolean,\n          shouldIf: Boolean,\n          camelCase: String,\n          disabled: {type: Boolean, value: 'true'},\n        },\n        created() {\n          this.wasCreated = true;\n        },\n        attributeChanged(name, old, value) {\n          this.wasCreatedInAttributeChanged = this.wasCreated;\n          this.attrInfo = {name, old, value};\n        }\n      });\n\n      Polymer({\n        is: 'x-native-attrs-force',\n        _legacyForceObservedAttributes: true,\n        properties: {\n          tabindex: {reflectToAttribute: true, type: Number}\n        },\n        attributeChanged() {\n          this.attributeChangedCalled = true;\n        }\n      });\n    </script>\n  </dom-module>\n\n  <test-fixture id=\"declarative\">\n    <template>\n      <x-attrs foo=\"foo\" bar=\"bar\" camel-case=\"camelCase\"></x-attrs>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"one-attr\">\n    <template>\n      <x-attrs foo=\"foo\"></x-attrs>\n    </template>\n  </test-fixture>\n\n  <script type=\"module\">\n    import {flush} from '../../lib/utils/flush.js';\n    import {wrap} from '../../lib/utils/wrap.js';\n    import {registrations} from '../../lib/utils/telemetry.js';\n\n    suite('legacyNoObservedAttributes', () => {\n\n      let el;\n      setup(() => {\n        el = fixture('declarative');\n      });\n\n      test('telemetry collected as expected', () => {\n        const defs = registrations.filter((def) => def.is === el.localName);\n        assert.ok(defs[0]);\n      });\n\n      test('native properties observeable when `_legacyForceObservedAttributes` set', function() {\n        // Unsupported when polyfill is in use since it uses `setAttribute`.\n        if (customElements.polyfillWrapFlushCallback) {\n          this.skip();\n        }\n        el = document.createElement('x-native-attrs-force');\n        document.body.appendChild(el);\n        el.tabIndex = 5;\n        assert.ok(el.attributeChangedCalled);\n        assert.equal(el.tabindex, 5);\n        document.body.removeChild(el);\n      });\n\n      test('static attributes', () => {\n        assert.equal(el.foo, 'foo');\n        assert.equal(el.$.child1.getAttribute('foo'), 'x-attrs.foo');\n        assert.equal(el.$.child1.foo, \"x-attrs.foo\");\n        assert.equal(el.$.child1.$.content.textContent, 'x-attrs.foo');\n        assert.equal(el.camelCase, 'camelCase');\n      });\n\n      test('imperative creation', () => {\n        el = document.createElement('x-attrs');\n        // Create attributes in an unpatched way.\n        const a = document.createAttribute('foo');\n        a.value = 'foo';\n        el.setAttributeNode(a);\n        const b = document.createAttribute('bar');\n        b.value = 'bar';\n        el.setAttributeNode(b);\n        const c = document.createAttribute('camel-case');\n        c.value = 'camelCase';\n        el.setAttributeNode(c);\n        document.body.appendChild(el);\n        assert.equal(el.foo, 'foo');\n        assert.equal(el.$.child1.getAttribute('foo'), 'x-attrs.foo');\n        assert.equal(el.$.child1.foo, \"x-attrs.foo\");\n        assert.equal(el.$.child1.$.content.textContent, 'x-attrs.foo');\n        assert.equal(el.camelCase, 'camelCase');\n        document.body.removeChild(el);\n      });\n\n      test('created called before attributeChanged', () => {\n        assert.isTrue(el.wasCreatedInAttributeChanged);\n      });\n\n      test('attributeChanged gets expected arguments', () => {\n        el = fixture('one-attr');\n        assert.deepEqual(el.attrInfo, {name: 'foo', old: null, value: 'foo'});\n        el.setAttribute('zot', '');\n        assert.deepEqual(el.attrInfo, {name: 'zot', old: null, value: ''});\n        el.setAttribute('zot', 'foo');\n        assert.deepEqual(el.attrInfo, {name: 'zot', old: '', value: 'foo'});\n        el.removeAttribute('zot', 'foo');\n        assert.deepEqual(el.attrInfo, {name: 'zot', old: 'foo', value: null});\n        el.setAttribute('zot', 'bar');\n        assert.deepEqual(el.attrInfo, {name: 'zot', old: null, value: 'bar'});\n        el.setAttribute('foo', 'foo2');\n        assert.deepEqual(el.attrInfo, {name: 'foo', old: 'foo', value: 'foo2'});\n      });\n\n      test('static attribute bindings', () => {\n        assert.equal(el.$.child1.getAttribute('bar'), 'bar');\n        assert.equal(el.$.child1.bar, 'bar');\n        assert.equal(el.$.child1.getAttribute('zot'), null);\n        assert.equal(el.$.child1.zot, false);\n        assert.equal(el.$.child1.camelCase, 'camelCase');\n      });\n\n      test('dynamic attribute bindings', () => {\n        el.bar = 'bar-modified';\n        assert.equal(el.$.child1.getAttribute('bar'), 'bar-modified');\n        assert.equal(el.$.child1.bar, 'bar-modified');\n        el.zot = true;\n        assert.equal(el.$.child1.getAttribute('zot'), '');\n        assert.equal(el.$.child1.zot, true);\n      });\n\n      test('attributes inside dom-if', () => {\n        el.shouldIf = true;\n        flush();\n        const child = wrap(el.$.ifContainer).querySelector('x-child');\n        assert.equal(child.getAttribute('foo'), 'x-attrs.foo');\n        assert.equal(child.foo, \"x-attrs.foo\");\n        assert.equal(child.$.content.textContent, 'x-attrs.foo');\n        assert.equal(child.camelCase, 'camelCase');\n        //\n        assert.equal(child.getAttribute('bar'), 'bar');\n        assert.equal(child.bar, 'bar');\n        assert.equal(child.getAttribute('zot'), null);\n        assert.equal(child.zot, false);\n        //\n        el.bar = 'bar-modified';\n        assert.equal(child.getAttribute('bar'), 'bar-modified');\n        assert.equal(child.bar, 'bar-modified');\n        el.zot = true;\n        assert.equal(child.getAttribute('zot'), '');\n        assert.equal(child.zot, true);\n      });\n\n      test('disable-upgrade static', () => {\n        assert.notOk(el.$.child2.isEnabled);\n        el.$.child2.removeAttribute('disable-upgrade');\n        assert.isTrue(el.$.child2.isEnabled);\n        assert.equal(el.$.child2.camelCase, 'camelCase');\n      });\n\n      test('disable-upgrade binding', () => {\n        assert.notOk(el.$.child3.isEnabled);\n        el.disabled = false;\n        assert.isTrue(el.$.child3.isEnabled);\n        assert.equal(el.$.child3.camelCase, 'camelCase');\n      });\n\n\n    });\n\n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/legacy-undefined.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\">\n    import {setLegacyUndefined} from '../../lib/utils/settings.js';\n    setLegacyUndefined(true);\n  </script>\n</head>\n<body>\n\n  <dom-module id=\"x-data\">\n    <template>\n      <div id=\"child\"\n        computed-single=\"[[computeSingle(inlineSingleDep)]]\"\n        computed-multi=\"[[computeMulti(inlineMultiDep1, inlineMultiDep2)]]\">\n        <dom-if if>\n          <template><div id=\"ifChild\" computed-multi=\"[[computeMulti(inlineMultiIfDep1, inlineMultiIfDep2)]]\"></div></template>\n        </dom-if>\n      </div>\n    </template>\n    <script type=\"module\">\n      import {Polymer} from '../../polymer-legacy.js';\n      Polymer({\n        is: 'x-data',\n        _legacyUndefinedCheck: true,\n        properties: {\n          singleProp: String,\n          multiProp1: String,\n          multiProp2: String,\n          computedSingleDep: String,\n          computedMultiDep1: String,\n          computedMultiDep2: String,\n          inlineSingleDep: String,\n          inlineMultiDep1: String,\n          inlineMultiDep2: String,\n          inlineMultiIfDep1: String,\n          inlineMultiIfDep2: String,\n          computedSingle: {\n            computed: 'computeSingle(computedSingleDep)'\n          },\n          computedMulti: {\n            computed: 'computeMulti(computedMultiDep1, computedMultiDep2)'\n          }\n        },\n        observers: [\n          'staticObserver(\"staticObserver\")',\n          'singlePropObserver(singleProp)',\n          'multiPropObserver(multiProp1, multiProp2)',\n          'throws(throwProp)'\n        ],\n        created() {\n          this.singlePropObserver = sinon.spy();\n          this.multiPropObserver = sinon.spy();\n          this.staticObserver = sinon.spy();\n          this.computeSingle = sinon.spy((inlineSingleDep) => `[${inlineSingleDep}]`);\n          this.computeMulti = sinon.spy((inlineMultiDep1, inlineMultiDep2) => `[${inlineMultiDep1},${inlineMultiDep2}]`);\n        },\n        throws() {\n          throw new Error('real error');\n        }\n      });\n    </script>\n  </dom-module>\n\n  <test-fixture id=\"declarative-none\">\n    <template>\n      <x-data></x-data>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"declarative-single\">\n    <template>\n      <x-data single-prop=\"a\"></x-data>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"declarative-multi-one\">\n    <template>\n      <x-data multi-prop1=\"b\"></x-data>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"declarative-multi-all\">\n    <template>\n      <x-data multi-prop1=\"b\" multi-prop2=\"c\"></x-data>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"declarative-single-computed\">\n    <template>\n      <x-data computed-single-dep=\"a\"></x-data>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"declarative-multi-one-computed\">\n    <template>\n      <x-data computed-multi-dep1=\"b\"></x-data>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"declarative-multi-all-computed\">\n    <template>\n      <x-data computed-multi-dep1=\"b\" computed-multi-dep2=\"c\"></x-data>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"declarative-single-computed-inline\">\n    <template>\n      <x-data inline-single-dep=\"a\"></x-data>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"declarative-multi-one-computed-inline\">\n    <template>\n      <x-data inline-multi-dep1=\"b\"></x-data>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"declarative-multi-all-computed-inline\">\n    <template>\n      <x-data inline-multi-dep1=\"b\" inline-multi-dep2=\"c\"></x-data>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"declarative-multi-if-one-computed-inline\">\n    <template>\n      <x-data inline-multi-if-dep1=\"b\"></x-data>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"declarative-multi-if-all-computed-inline\">\n    <template>\n      <x-data inline-multi-if-dep1=\"b\" inline-multi-if-dep2=\"c\"></x-data>\n    </template>\n  </test-fixture>\n\n  <script type=\"module\">\n    import {flush} from '../../lib/utils/flush.js';\n\n    let el;\n\n    function assertEffects(callCounts) {\n      assert.equal(el.staticObserver.callCount, 1, 'staticObserver call count wrong');\n      assert.equal(el.singlePropObserver.callCount,\n        callCounts.singlePropObserver || 0, 'singlePropObserver call count wrong');\n      assert.equal(el.multiPropObserver.callCount,\n        callCounts.multiPropObserver || 0, 'multiPropObserver call count wrong');\n      assert.equal(el.computeSingle.callCount,\n        callCounts.computeSingle || 0, 'computeSingle call count wrong');\n      assert.equal(el.computeMulti.callCount,\n        callCounts.computeMulti || 0, 'computeMulti call count wrong');\n    }\n\n    suite('imperative', () => {\n\n\n      function setupElement(props) {\n        el = document.createElement('x-data');\n        Object.assign(el, props);\n        document.body.appendChild(el);\n        flush();\n      }\n\n      teardown(() => {\n        el.parentNode.removeChild(el);\n      });\n\n      const singleProp = 'singleProp';\n      const multiProp1 = 'multiProp1';\n      const multiProp2 = 'multiProp2';\n      const computedSingleDep = 'computedSingleDep';\n      const computedMultiDep1 = 'computedMultiDep1';\n      const computedMultiDep2 = 'computedMultiDep2';\n      const inlineSingleDep = 'inlineSingleDep';\n      const inlineMultiDep1 = 'inlineMultiDep1';\n      const inlineMultiDep2 = 'inlineMultiDep2';\n      const inlineMultiIfDep1 = 'inlineMultiIfDep1';\n      const inlineMultiIfDep2 = 'inlineMultiIfDep2';\n\n      suite('check disabled', () => {\n        test('no arguments defined', () => {\n          setupElement({});\n          assertEffects({});\n        });\n        test('singlePropObserver argument defined', () => {\n          setupElement({singleProp});\n          assertEffects({singlePropObserver: 1});\n        });\n        test('one multiPropObserver arguments defined', () => {\n          setupElement({multiProp1});\n          assertEffects({multiPropObserver: 0});\n        });\n        test('all multiPropObserver defined', () => {\n          setupElement({multiProp1, multiProp2});\n          assertEffects({multiPropObserver: 1});\n        });\n        test('singlePropObserver argument undefined', () => {\n          setupElement({singleProp});\n          assertEffects({singlePropObserver: 1});\n          el.singleProp = undefined;\n          assertEffects({singlePropObserver: 2});\n        });\n        test('one multiPropObserver arguments undefined', () => {\n          setupElement({multiProp1, multiProp2});\n          assertEffects({multiPropObserver: 1});\n          el.multiProp1 = undefined;\n          assertEffects({multiPropObserver: 1});\n        });\n        test('all multiPropObserver undefined', () => {\n          setupElement({multiProp1, multiProp2});\n          assertEffects({multiPropObserver: 1});\n          el.multiProp1 = undefined;\n          assertEffects({multiPropObserver: 1});\n          el.multiProp2 = undefined;\n          assertEffects({multiPropObserver: 1});\n        });\n        test('computeSingle argument defined', () => {\n          setupElement({computedSingleDep});\n          assertEffects({computeSingle: 1});\n          assert.equal(el.computedSingle, '[computedSingleDep]');\n        });\n        test('one computeMulti argument defined', () => {\n          setupElement({computedMultiDep1});\n          assertEffects({computeMulti: 0});\n          assert.equal(el.computedMulti, undefined);\n        });\n        test('all computeMulti argument defined', () => {\n          setupElement({computedMultiDep1, computedMultiDep2});\n          assertEffects({computeMulti: 1});\n          assert.equal(el.computedMulti, '[computedMultiDep1,computedMultiDep2]');\n        });\n        test('inline computeSingle argument defined', () => {\n          setupElement({inlineSingleDep});\n          assertEffects({computeSingle: 1});\n          assert.equal(el.$.child.computedSingle, '[inlineSingleDep]');\n        });\n        test('one inline computeMulti argument defined', () => {\n          setupElement({inlineMultiDep1});\n          assertEffects({computeMulti: 0});\n          assert.equal(el.$.child.computedMulti, undefined);\n        });\n        test('all inline computeMulti argument defined', () => {\n          setupElement({inlineMultiDep1, inlineMultiDep2});\n          assertEffects({computeMulti: 1});\n          assert.equal(el.$.child.computedMulti, '[inlineMultiDep1,inlineMultiDep2]');\n        });\n        test('one inline computeMulti argument defined in dom-if', () => {\n          setupElement({inlineMultiIfDep1});\n          assertEffects({computeMulti: 0});\n          assert.equal(el.$$('#ifChild').computedMulti, undefined);\n        });\n        test('all inline computeMulti argument defined in dom-if', () => {\n          setupElement({inlineMultiIfDep1, inlineMultiIfDep2});\n          assertEffects({computeMulti: 1});\n          assert.equal(el.$$('#ifChild').computedMulti, '[inlineMultiIfDep1,inlineMultiIfDep2]');\n        });\n      });\n\n    });\n\n    suite('declarative', () => {\n\n      setup(() => sinon.spy(console, 'warn'));\n\n      teardown(() => console.warn.restore());\n\n      test('no arguments defined', () => {\n        el = fixture('declarative-none');\n        assertEffects({});\n      });\n      test('singlePropObserver argument defined', () => {\n        el = fixture('declarative-single');\n        assertEffects({singlePropObserver: 1});\n      });\n      test('one multiPropObserver arguments defined', () => {\n        el = fixture('declarative-multi-one');\n        assertEffects({multiPropObserver: 0});\n      });\n      test('all multiPropObserver defined', () => {\n        el = fixture('declarative-multi-all');\n        assertEffects({multiPropObserver: 1});\n      });\n      test('computeSingle argument defined', () => {\n        el = fixture('declarative-single-computed');\n        assertEffects({computeSingle: 1});\n        assert.equal(el.computedSingle, '[a]');\n      });\n      test('one computeMulti arguments defined', () => {\n        el = fixture('declarative-multi-one-computed');\n        assertEffects({computeMulti: 0});\n        assert.equal(el.computedMulti, undefined);\n      });\n      test('all computeMulti defined', () => {\n        el = fixture('declarative-multi-all-computed');\n        assert.equal(el.computedMulti, '[b,c]');\n      });\n      test('inline computeSingle argument defined', () => {\n        el = fixture('declarative-single-computed-inline');\n        assertEffects({computeSingle: 1});\n        assert.equal(el.$.child.computedSingle, '[a]');\n      });\n      test('inline one computeMulti arguments defined', () => {\n        el = fixture('declarative-multi-one-computed-inline');\n        assertEffects({computeMulti: 0});\n        assert.equal(el.$.child.computedMulti, undefined);\n      });\n      test('inline all computeMulti defined', () => {\n        el = fixture('declarative-multi-all-computed-inline');\n        assertEffects({computeMulti: 1});\n        assert.equal(el.$.child.computedMulti, '[b,c]');\n      });\n      test('one inline computeMulti argument defined in dom-if', () => {\n        el = fixture('declarative-multi-if-one-computed-inline');\n        flush();\n        assertEffects({computeMulti: 0});\n        assert.equal(el.$$('#ifChild').computedMulti, undefined);\n      });\n      test('all inline computeMulti argument defined in dom-if', () => {\n        el = fixture('declarative-multi-if-all-computed-inline');\n        flush();\n        assertEffects({computeMulti: 1});\n        assert.equal(el.$$('#ifChild').computedMulti, '[b,c]');\n      });\n\n    });\n\n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/logging.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n</head>\n<body>\n  <dom-module id=\"x-logging\">\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-logging',\n  properties: {\n    stream: {\n      value: () => [],\n      type: Array\n    }\n  },\n  _logger(level, args) {\n    this.stream.push({level, args});\n  }\n});\n</script>\n  </dom-module>\n  <script type=\"module\">\nimport { LegacyElementMixin } from '../../lib/legacy/legacy-element-mixin.js';\nclass XMixin extends LegacyElementMixin(HTMLElement) {\n  static get is() { return 'x-mixin'; }\n  static get properties() {\n    return {\n      stream: {\n        value: () => [],\n        type: Array\n      }\n    };\n  }\n  _logger(level, args) {\n    this.stream.push({level, args});\n  }\n}\ncustomElements.define(XMixin.is, XMixin);\n</script>\n  <script type=\"module\">\nimport { Base } from '../../polymer-legacy.js';\nsuite('Logging', () => {\n  let fnEl, classEl;\n  suiteSetup(() => {\n    fnEl = document.createElement('x-logging');\n    document.body.appendChild(fnEl);\n    classEl = document.createElement('x-mixin');\n    document.body.appendChild(classEl);\n  });\n  test('API', () => {\n    ['_log', '_warn', '_error', '_logf', '_logger'].forEach((n) => {\n      assert.isFunction(fnEl[n], `${n} not defined on Polymer() element`);\n      assert.isFunction(classEl[n], `${n} not defined on Polymer.Element element`);\n    });\n  });\n  test('_log, _warn_, and _error go through _logger', () => {\n    fnEl._log('fn');\n    classEl._log('class');\n    fnEl._warn('fn');\n    classEl._warn('class');\n    fnEl._error('fn');\n    classEl._error('class');\n    assert.deepEqual(fnEl.stream, [{level: 'log', args: ['fn']}, {level: 'warn', args: ['fn']}, {level: 'error', args: ['fn']}]);\n    assert.deepEqual(classEl.stream, [{level: 'log', args: ['class']}, {level: 'warn', args: ['class']}, {level: 'error', args: ['class']}]);\n  });\n  test('_logf', () => {\n    let args = ['hi', 'there'];\n    let output = fnEl._logf(...args);\n    assert.oneOf(fnEl.is, output, `${fnEl.is} should be in ${output}`);\n    assert.includeMembers(output, args, `${args} should be in ${output}`);\n  });\n});\nsuite('_logger', () => {\n  test('_log with single parameter', () => {\n    const msg = 'log test';\n    const orgConsole = console;\n    const spy = sinon.spy();\n    window.console = {\n      log: spy\n    };\n    Base._log(msg);\n    window.console = orgConsole;\n    assert.equal(spy.callCount, 1, 'console.log called more than one time');\n    assert.equal(spy.args[0].length, 1, 'console.log called with more than one argument');\n    assert.equal(spy.args[0][0], msg, 'message not pass properly to log');\n  });\n});\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/mixin-behaviors.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n<body>\n\n  <script type=\"module\">\n    window.LifeCycleBehavior1 = {\n\n      properties: {\n        foo: {\n          type: String\n        }\n      },\n\n      created() {\n            this.__createdList = this.__createdList || [];\n            this.__createdList.push('1');\n      },\n\n      attached() {\n            this.__attachedList = this.__attachedList || [];\n            this.__attachedList.push('1');\n      },\n\n      attributeChanged() {\n            this.__attributeChangedList = this.__attributeChangedList || [];\n            this.__attributeChangedList.push('1');\n      }\n    };\n\n    window.LifeCycleBehavior2 = {\n      created() {\n        this.__createdList = this.__createdList || [];\n        this.__createdList.push('2');\n      },\n\n      attached() {\n        this.__attachedList = this.__attachedList || [];\n        this.__attachedList.push('2');\n      }\n    };\n\n    window.LifeCycleBehavior3 = {\n      created() {\n        this.__createdList = this.__createdList || [];\n        this.__createdList.push('3');\n      }\n    };\n\n    window.LifeCycleBehavior4 = {\n      created() {\n        this.__createdList = this.__createdList || [];\n        this.__createdList.push('4');\n      }\n    };\n\n    window.BehaviorA = {\n      properties: {\n\n        label: {\n          type: String,\n          observer: '_labelChanged'\n        },\n\n        hasOptionsA: {\n          readOnly: true,\n          notify: true\n        },\n\n        overridableProperty: {\n          value: false\n        },\n\n        overridablePropertyB: {\n          value: false\n        },\n\n        hasBehaviorA: {\n          value: true\n        },\n\n        computeADependency: {\n          value: true\n        },\n\n        computeA: {\n          computed: '_computeProp(computeADependency)'\n        }\n      },\n\n      _simpleProperty: 'A',\n\n      hostAttributes: {\n        behavior: 'A',\n        element: 'A',\n        user: 'A'\n      },\n\n      listeners: {\n        change: '_changeHandler'\n      },\n\n      ready: function() {\n        this.__readyA = true;\n      },\n\n      _labelChanged: function(label) {\n        this.__label = label;\n      },\n\n      _changeHandler: function(e) {\n        this.__change = e.detail.value;\n      },\n\n      _computeProp: function(a) {\n        return a;\n      }\n    };\n\n    window.BehaviorB = {\n      properties: {\n\n        disabled: {\n          type: Boolean,\n          value: false,\n          observer: '_disabledChanged'\n        },\n\n        hasOptionsB: {\n          readOnly: true,\n          notify: true\n        },\n\n        hasBehaviorB: {\n          value: true\n        },\n\n        overridablePropertyB: {\n          value: true\n        },\n\n        computeADependencyDependency: {\n          value: 'hi'\n        },\n\n        computeADependency: {\n          computed: '_computeProp(computeADependencyDependency)'\n        }\n\n      },\n\n      hostAttributes: {\n        behavior: 'B',\n        element: 'B',\n        user: 'B'\n      },\n\n      _simpleProperty: 'B',\n\n      _disabledChanged: function(disabled) {\n        this.__disabled = disabled;\n      },\n\n      ready: function() {\n        this.__readyB = true;\n      },\n\n    };\n\n    window.BehaviorC = {\n\n      properties: {\n\n        hasBehaviorC: {\n          value: true\n        }\n\n      },\n\n      _simpleProperty: 'C'\n    };\n\n    window.BehaviorD = {\n\n      properties: {\n\n        hasBehaviorD: {\n          value: true\n        }\n\n      },\n      _simpleProperty: 'D'\n\n    };\n  </script>\n\n  <dom-module id=\"single-behavior\">\n    <script type=\"module\">\n      import { mixinBehaviors } from '../../lib/legacy/class.js';\n      import { PolymerElement } from '../../polymer-element.js';\n      customElements.define('single-behavior',\n        mixinBehaviors(window.BehaviorA, PolymerElement));\n    </script>\n  </dom-module>\n\n  <dom-module id=\"lifecycle-behavior\">\n    <script type=\"module\">\n      import { mixinBehaviors } from '../../lib/legacy/class.js';\n      import { PolymerElement } from '../../polymer-element.js';\n      customElements.define('lifecycle-behavior',\n        mixinBehaviors([window.LifeCycleBehavior1,\n          window.LifeCycleBehavior2], PolymerElement));\n    </script>\n  </dom-module>\n\n  <dom-module id=\"multi-behaviors\">\n    <script type=\"module\">\n      import { mixinBehaviors } from '../../lib/legacy/class.js';\n      import { PolymerElement } from '../../polymer-element.js';\n      customElements.define('multi-behaviors',\n        class extends mixinBehaviors(\n          [window.BehaviorA, window.BehaviorB], PolymerElement) {\n\n          static get properties() {\n            return {\n              foo: {\n                type: String,\n                reflectToAttribute: true,\n                readOnly: true,\n                observer: '_fooChanged'\n              },\n\n              overridableProperty: {\n                value: true\n              }\n            };\n          }\n\n          constructor() {\n            super();\n          }\n\n          _fooChanged(foo) {\n            this.__foo = foo;\n          }\n\n          _ensureAttributes() {\n            this._ensureAttribute('element', 'element');\n            super._ensureAttributes();\n          }\n      });\n    </script>\n  </dom-module>\n\n  <script type=\"module\">\n    import { mixinBehaviors } from '../../lib/legacy/class.js';\n    import { Polymer } from '../../polymer-legacy.js';\n    import { PolymerElement } from '../../polymer-element.js';\n\n    customElements.define('nested-behaviors',\n      class extends mixinBehaviors([window.BehaviorD, window.LifeCycleBehavior1], mixinBehaviors(\n        [\n          [window.BehaviorB, [window.BehaviorC, window.BehaviorB], window.BehaviorA, window.LifeCycleBehavior2],\n            ], PolymerElement)) {\n        });\n\n    var base = Polymer({\n      is: 'sup-element',\n      behaviors: [\n        window.LifeCycleBehavior1,\n        window.LifeCycleBehavior2\n      ],\n      created: function() {\n        this.__createdList.push('sup');\n      }\n    });\n\n    class extended extends mixinBehaviors([window.LifeCycleBehavior3,\n        window.LifeCycleBehavior4], base) {\n\n      created() {\n        super.created();\n        this.__createdList.push('sub');\n      }\n    }\n\n    customElements.define('extended-behaviors', extended);\n  </script>\n\n  <dom-module id=\"behavior-registered\">\n    <template>\n      <div id=\"content\"></div>\n    </template>\n    <script type=\"module\">\n      import { mixinBehaviors } from '../../lib/legacy/class.js';\n      import { PolymerElement } from '../../polymer-element.js';\n\n      window.registerBehavior1 ={\n              registeredCount: 0,\n        registered: function() {\n          this._createPropertyObserver('prop', 'propChanged1');\n          this._createMethodObserver('propChanged2(prop)');\n          this.registeredCount++;\n          this.registeredProps = [this.prop1, this.prop2, this.prop3];\n          this.registeredBehaviors = this.behaviors;\n        },\n        prop1: true,\n        ready: function() {\n          this._ensureAttribute('attr', true);\n        },\n        propChanged1: function() {\n          this.propChanged1Called = true;\n        },\n        propChanged2: function() {\n          this.propChanged2Called = true;\n        }\n      };\n\n      window.registerBehavior2 ={\n        prop2: true,\n        registered: function() {\n          this.registeredCount++;\n        }\n      };\n\n      window.registerBehavior3 ={\n        prop3: true,\n        registered: function() {\n          this.registeredCount++;\n        }\n      };\n\n      class BehaviorRegistered extends mixinBehaviors([\n          window.registerBehavior1,\n          window.registerBehavior2,\n          window.registerBehavior3\n        ], PolymerElement) {\n\n        static get is() { return 'behavior-registered';}\n\n        _initializeProperties() {\n          super._initializeProperties();\n          this.registeredCount++;\n        }\n      }\n\n      customElements.define(BehaviorRegistered.is, BehaviorRegistered);\n\n      class BehaviorRegisteredExt extends BehaviorRegistered {\n        static get is() { return 'behavior-registered-ext';}\n      }\n\n      customElements.define(BehaviorRegisteredExt.is, BehaviorRegisteredExt);\n    </script>\n  </dom-module>\n\n  <script type=\"module\">\n    import { mixinBehaviors } from '../../lib/legacy/class.js';\n    import { PolymerElement } from '../../polymer-element.js';\n\n    var klass = mixinBehaviors([\n      {\n        __fooChangedCalled: 0,\n        beforeRegister: function() {\n          this.constructor.generatedFrom.observers = [\n            '_fooChanged(foo)'\n          ];\n        },\n        _fooChanged: function() {\n          this.__fooChangedCalled++;\n        }\n      }\n    ], PolymerElement);\n\n    customElements.define('before-register-observers', klass);\n  </script>\n\n  <script type=\"module\">\n    import { mixinBehaviors } from '../../lib/legacy/class.js';\n    import { PolymerElement } from '../../polymer-element.js';\n\n    const Base = mixinBehaviors([{\n      registered() {\n        this.usedExtendedProto = this.canUseExtendedProto;\n      }\n    }], PolymerElement);\n\n    customElements.define('registered-proto', mixinBehaviors([\n      {canUseExtendedProto: true}\n    ], Base));\n\n  </script>\n\n  <script type=\"module\">\n    import { mixinBehaviors } from '../../lib/legacy/class.js';\n    import { PolymerElement } from '../../polymer-element.js';\n\n\n    class Base extends mixinBehaviors([{\n        properties: {b1: String} }], PolymerElement) {\n\n      static get properties() {\n        return { e1: String};\n      }\n    }\n\n    class El extends mixinBehaviors([{\n        properties: {b2: String}}], Base) {\n\n      static get properties() {\n        return { e2: String};\n      }\n\n    }\n\n    customElements.define('extended-observed-attributes', El);\n\n  </script>\n\n  <test-fixture id=\"single\">\n    <template>\n      <single-behavior></single-behavior>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"lifecycle\">\n    <template>\n      <lifecycle-behavior foo=\"foo\"></lifecycle-behavior>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"multi\">\n    <template>\n      <multi-behaviors user=\"user\"></multi-behaviors>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"nested\">\n    <template>\n      <nested-behaviors foo=\"foo\"></nested-behaviors>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"extended-behaviors\">\n    <template>\n      <extended-behaviors></extended-behaviors>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"registered\">\n    <template>\n      <behavior-registered></behavior-registered>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"before-register-observers\">\n    <template>\n      <before-register-observers></before-register-observers>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"registered-ext\">\n    <template>\n      <behavior-registered-ext></behavior-registered-ext>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"registered-proto\">\n    <template>\n      <registered-proto></registered-proto>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"extended-observed-attributes\">\n    <template>\n      <extended-observed-attributes b1=\"b1\" e1=\"e1\" b2=\"b2\" e2=\"e2\"></extended-observed-attributes>\n    </template>\n  </test-fixture>\n\n\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nimport { mixinBehaviors } from '../../lib/legacy/class.js';\nimport { PolymerElement } from '../../polymer-element.js';\n\nsuite('single behavior element', function() {\n  var el;\n\n  setup(function() {\n    el = fixture('single');\n  });\n\n  test('ready from behavior', function() {\n    assert.equal(el.__readyA, true);\n  });\n\n  test('properties from behavior', function() {\n    el.label = 'foo';\n    assert.equal(el.__label, 'foo');\n  });\n\n  test('instance behaviors', function() {\n    assert.equal(el.behaviors.length, 1);\n  });\n\n  test('listener from behavior', function() {\n    el.fire('change', {value: 'bar'});\n    assert.equal(el.__change, 'bar');\n  });\n\n  test('property info from behavior', function() {\n    assert.equal(el._hasNotifyEffect('hasOptionsA'), true);\n    assert.equal(el._hasReadOnlyEffect('hasOptionsA'), true);\n    assert.equal(typeof el._setHasOptionsA, 'function');\n  });\n\n  test('compute property from behavior', function() {\n    assert.equal(el.computeA, true);\n  });\n\n});\n\nsuite('behavior.registered/beforeRegister', function() {\n  test('can install dynamic properties', function() {\n    var el = fixture('registered');\n    assert.ok(el.$.content);\n    el.prop = 42;\n    assert.isTrue(el.propChanged1Called);\n    assert.isTrue(el.propChanged2Called);\n    assert.isTrue(el.hasAttribute('attr'));\n  });\n\n  test('called once for each behavior with access to element prototype', function() {\n    var el = fixture('registered');\n    assert.equal(el.registeredCount, 4);\n    assert.equal(el.registeredBehaviors.length, 3);\n    assert.equal(el.registeredBehaviors, el.behaviors);\n    assert.deepEqual(el.registeredProps, [true, true, true]);\n  });\n\n  test('extending element with behaviors with registered properly registers', function() {\n    var el = fixture('registered-ext');\n    assert.equal(el.registeredCount, 4);\n    assert.equal(el.registeredBehaviors.length, 3);\n    assert.equal(el.registeredBehaviors, el.behaviors);\n    assert.deepEqual(el.registeredProps, [true, true, true]);\n  });\n\n  test('add observers via behavior in beforeRegister', function() {\n    var el = fixture('before-register-observers');\n    el.foo = 1;\n    assert.equal(el.__fooChangedCalled, 1);\n  });\n\n  test('registered called on class prototype when extended', function() {\n    var el = fixture('registered-proto');\n    assert.isTrue(el.usedExtendedProto);\n  });\n\n});\n\nsuite('behavior lifecycle', function() {\n\n    var el;\n\n    setup(function() {\n      el = fixture('lifecycle');\n    });\n\n    test('lifecycle', function() {\n      assert.deepEqual(el.__createdList, ['1', '2'], 'created list wrong');\n      assert.deepEqual(el.__attachedList, ['1', '2'], 'attached list wrong');\n      assert.deepEqual(el.__attributeChangedList, ['1'],  'attributeChanged list wrong');\n    });\n\n  });\n\nsuite('multi-behaviors element', function() {\n  var el;\n\n  setup(function() {\n    el = fixture('multi');\n  });\n\n  test('ready from behaviors', function() {\n    assert.equal(el.__readyA, true);\n    assert.equal(el.__readyB, true);\n  });\n\n  test('instance behaviors', function() {\n    assert.equal(el.behaviors.length, 2);\n  });\n\n  test('properties from behaviors', function() {\n    el.label = 'foo';\n    assert.equal(el.__label, 'foo');\n    el.disabled = true;\n    assert.equal(el.__disabled, true);\n  });\n\n  test('properties from itself', function() {\n    assert.isDefined(el._setFoo, 'readOnly setter not available');\n    el._setFoo('bar');\n    assert.equal(el.__foo, 'bar', 'observer not getting called');\n    assert.equal(el.getAttribute('foo'), 'bar', 'not getting reflected');\n  });\n\n  test('listener from behaviors', function() {\n    el.fire('change', {value: 'bar'});\n    assert.equal(el.__change, 'bar');\n  });\n\n  test('property info from behavior A', function() {\n    assert.equal(el._hasNotifyEffect('hasOptionsA'), true);\n    assert.equal(el._hasReadOnlyEffect('hasOptionsA'), true);\n    assert.equal(typeof el._setHasOptionsA, 'function');\n  });\n\n  test('property info from behavior B', function() {\n    assert.equal(el._hasReadOnlyEffect('hasOptionsB'), true);\n    assert.equal(el._hasNotifyEffect('hasOptionsB'), true);\n    assert.equal(typeof el._setHasOptionsB, 'function');\n  });\n\n  test('computed property dependency can become a computed property', function() {\n    assert.equal(el.computeA, 'hi');\n  });\n\n  test('multi-behavior overrides ordering', function() {\n    assert(el.overridableProperty, 'Behavior property was not overridden by prototype');\n    assert(el.overridablePropertyB, 'Behavior config-property was not overridden by sub-behavior');\n  });\n\n  test('hostAttributes ordering', function() {\n    assert.equal(el.attributes.behavior.value, 'B', 'Behavior hostAttribute not overridden by younger behavior');\n    assert.equal(el.attributes.element.value, 'element', 'Behavior hostAttribute overridden by behavior');\n    assert.equal(el.attributes.user.value, 'user', 'Behavior hostAttribute overrode user attribute');\n  });\n\n  test('behavior is null generates warning', function() {\n    sinon.spy(console, 'warn');\n    Polymer({\n      is: 'behavior-null',\n      behaviors: [\n        null\n      ]\n    });\n    document.createElement('behavior-null');\n    assert.equal(console.warn.callCount, 1, 'Null behaviour should generate warning');\n    console.warn.restore();\n  });\n\n  test('behavior array is unique', function() {\n    customElements.define('behavior-unique', mixinBehaviors(\n      [window.BehaviorA, window.BehaviorA], PolymerElement));\n    assert.equal(document.createElement('behavior-unique').behaviors.length, 1);\n  });\n\n  test('duplicate behaviors keep first behavior', function() {\n    customElements.define('behavior-unique-last-behavior', mixinBehaviors(\n      [window.BehaviorA, window.BehaviorB, window.BehaviorC, window.BehaviorA, window.BehaviorB], PolymerElement));\n    var behaviors = document.createElement('behavior-unique-last-behavior').behaviors;\n    assert.deepEqual(behaviors, [window.BehaviorC, window.BehaviorA, window.BehaviorB]);\n  });\n\n});\n\nsuite('nested-behaviors element', function() {\n  var el;\n\n  setup(function() {\n    el = fixture('nested');\n  });\n\n  test('nested-behavior dedups', function() {\n    assert.equal(el.behaviors.length, 6);\n  });\n\n  test('nested-behavior lifecycle', function() {\n    assert.deepEqual(el.__createdList, ['2', '1'], 'created list wrong');\n    assert.deepEqual(el.__attachedList, ['2', '1'], 'attached list wrong');\n    assert.deepEqual(el.__attributeChangedList, ['1'],  'attributeChanged list wrong');\n  });\n\n  test('nested-behavior overrides ordering', function() {\n    assert.ok(el.hasBehaviorA, \"missing BehaviorA\");\n    assert.ok(el.hasBehaviorB, \"missing BehaviorB\");\n    assert.ok(el.hasBehaviorC, \"missing BehaviorC\");\n    assert.ok(el.hasBehaviorD, \"missing BehaviorD\");\n    assert.equal(el._simpleProperty, 'D', 'Behavior simple property was not overridden by sub-behavior');\n  });\n\n});\n\nsuite('extended-behaviors', function() {\n\n  var el;\n\n  setup(function() {\n    el = fixture('extended-behaviors');\n  });\n\n  test('lifecycle', function() {\n    assert.deepEqual(el.__createdList, ['1', '2', 'sup', '3', '4', 'sub'], 'created list wrong');\n  });\n\n  test('observedAttributes when extended', function() {\n    const el = fixture('extended-observed-attributes');\n    assert.equal(el.b1, 'b1');\n    assert.equal(el.e1, 'e1');\n    assert.equal(el.b2, 'b2');\n    assert.equal(el.e2, 'e2');\n  });\n\n});\n\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/mixin-utils.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n</head>\n<body>\n  <script type=\"module\">\nimport { dedupingMixin } from '../../lib/utils/mixin.js';\nsuite('Mixin Utilities', () => {\n  suite('Mixin Caching', () => {\n    let mixinFn;\n    let cachingMixinFn;\n    suiteSetup(() => {\n      mixinFn = (base) => class mixin extends base {\n        mixed(){ return true; }\n      };\n      cachingMixinFn = dedupingMixin(mixinFn);\n    });\n    test('cachingMixin applies mixins', () => {\n      let app = cachingMixinFn(class {});\n      let inst = new app();\n      assert.isFunction(inst.mixed);\n      assert.equal(inst.mixed(), true);\n    });\n    test('Mixins are cached when the base class is identical', () => {\n      class base {}\n      let applicationOne = cachingMixinFn(base);\n      let applicationTwo = cachingMixinFn(base);\n      assert.equal(applicationOne, applicationTwo);\n    });\n    test('Original Mixin function keeps the cache', () => {\n      assert.ok(mixinFn.__mixinApplications);\n      assert.instanceOf(mixinFn.__mixinApplications, WeakMap);\n      assert.notOk(cachingMixinFn.__mixinApplications);\n    });\n  });\n  suite('Mixin Deduplicating', () => {\n    let mixinFn, dedupingMixinFn;\n    suiteSetup(() => {\n      mixinFn = (base) => class mixin extends base {\n        mixed(){ return true; }\n      };\n      dedupingMixinFn = dedupingMixin(mixinFn);\n    });\n    test('dedupingMixin applies mixins', () => {\n      let app = dedupingMixinFn(class {});\n      let inst = new app();\n      assert.isFunction(inst.mixed);\n      assert.equal(inst.mixed(), true);\n    });\n    test('dedupingMixin also caches', () => {\n      class base {}\n      let appOne = dedupingMixinFn(base);\n      let appTwo = dedupingMixinFn(base);\n      assert.equal(appOne, appTwo);\n    });\n    test('Mixins apply only if unique on the base class', () => {\n      class base {}\n      let appOne = dedupingMixinFn(base);\n      class intermediate extends appOne {}\n      let appTwo = dedupingMixinFn(intermediate);\n      assert.equal(intermediate, appTwo);\n      let inst = new appTwo();\n      assert.equal(inst.mixed(), true);\n    });\n    test('Multiple deduplicating mixins apply uniquely', () => {\n      let mixinFn1 = dedupingMixin((base) => class one extends base {\n        one(){ return true; }\n      });\n      let mixinFn2 = dedupingMixin((base) => class two extends base {\n        two(){ return true; }\n      });\n      class base {}\n      let app1 = mixinFn1(base);\n      let app2 = mixinFn2(app1);\n      let app3 = mixinFn1(app2);\n      assert.equal(app3, app2);\n      let inst = new app3();\n      assert.equal(inst.one(), true);\n      assert.equal(inst.two(), true);\n    });\n    test('Classes with mixins do not share mixin sets', () => {\n      let mixinFn1 = dedupingMixin((base) => class one extends base {\n        one(){ return true; }\n      });\n      let mixinFn2 = dedupingMixin((base) => class two extends base {\n        two(){ return true; }\n      });\n      let mixinFn3 = dedupingMixin((base) => class three extends base {\n        three(){ return true; }\n      });\n      class base {}\n      let app1 = mixinFn1(base);\n      let app2 = mixinFn2(app1);\n      let app3 = mixinFn3(app2);\n      let appNot2 = mixinFn3(app1);\n      assert.notEqual(appNot2.__mixinSet, app3.__mixinSet);\n      let inst = new appNot2();\n      assert.isFunction(inst.one);\n      assert.isFunction(inst.three);\n      assert.isNotFunction(inst.two);\n    });\n  });\n});\n</script>\n</body>\n</html>"
  },
  {
    "path": "test/unit/multi-style.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n</head>\n<body>\n  <dom-module id=\"shared-styles\">\n    <template>\n      <style>\n        #zot {\n          border: 1px solid black;\n        }\n      </style>\n    </template>\n  </dom-module>\n\n  <dom-module id=\"my-element\">\n\n    <template>\n      <style>\n        #foo {\n          border: 2px solid green;\n        }\n      </style>\n      <style>\n        #bar {\n          border: 3px solid orange;\n        }\n        </style>\n      <div id=\"foo\">foo</div>\n      <div id=\"bar\">bar</div>\n    </template>\n  </dom-module>\n\n  <dom-module id=\"my-element2\">\n\n    <template>\n      <style include=\"shared-styles\">\n        #zug {\n          border: 4px solid red;\n        }\n      </style>\n      <div id=\"zug\">zug</div>\n      <div id=\"zot\">zot</div>\n    </template>\n\n    <script type=\"module\">\n</script>\n\n  </dom-module>\n\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nimport { PolymerElement } from '../../polymer-element.js';\nimport { DomModule } from '../../lib/elements/dom-module.js';\nsuite('elements including multiple styles', function() {\n\n  suiteSetup(function() {\n    const skip = window.ShadyDOM || !Polymer;\n    if (skip) {\n      this.skip();\n    } else {\n      class MyElement extends PolymerElement {\n        static get is() { return 'my-element'; }\n      }\n      customElements.define(MyElement.is, MyElement);\n\n      class MyElement2 extends MyElement {\n        static get is() { return 'my-element2'; }\n        static get template() {\n          Object.getPrototypeOf(this.prototype).constructor.template;\n          const t = DomModule.import(MyElement2.is, 'template');\n          const superT = MyElement.template;\n          t.content.insertBefore(superT.content.cloneNode(true), t.content.firstElementChild.nextElementSibling);\n          return t;\n        }\n      }\n      customElements.define(MyElement2.is, MyElement2);\n    }\n  });\n\n  function assertComputed(element, value, property, pseudo) {\n    var computed = getComputedStyle(element, pseudo);\n    property = property || 'border-top-width';\n    if (Array.isArray(value)) {\n      assert.oneOf(computed[property], value, 'computed style incorrect for ' + property);\n    } else {\n      assert.equal(computed[property], value, 'computed style incorrect for ' + property);\n    }\n  }\n\n  test('multiple styles preserved separately in element root and apply', function() {\n    const e = document.createElement('my-element');\n    document.body.appendChild(e);\n    const styles = e.shadowRoot.querySelectorAll('style');\n    assert.equal(styles.length, 2);\n    assertComputed(e.$.foo, '2px');\n    assertComputed(e.$.bar, '3px');\n  });\n\n  test('super class and included styles preserved separately in element root and apply', function() {\n    const e = document.createElement('my-element2');\n    document.body.appendChild(e);\n    const styles = e.shadowRoot.querySelectorAll('style');\n    assert.equal(styles.length, 4);\n    assertComputed(e.$.foo, '2px');\n    assertComputed(e.$.bar, '3px');\n    assertComputed(e.$.zug, '4px');\n    assertComputed(e.$.zot, '1px');\n  });\n\n});\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/path-effects-elements.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport { PropertiesMixin } from '../../lib/mixins/properties-mixin.js';\n\nimport { Polymer } from '../../lib/legacy/polymer-fn.js';\nimport { html } from '../../lib/utils/html-tag.js';\nclass XPropertiesElement extends PropertiesMixin(HTMLElement) {\n  static get properties() {\n    return {\n      obj: Object\n    };\n  }\n  constructor() {\n    super();\n    this.resetObservers();\n  }\n  // Allow re-set objects to show in _propertiesChanged\n  _shouldPropertyChange(property, value, old) {\n    return (typeof value == 'object') ||\n      super._shouldPropertyChange(property, value, old);\n  }\n  resetObservers() {\n    this._propertiesChanged = sinon.spy();\n  }\n}\ncustomElements.define('x-pe', XPropertiesElement);\nPolymer({\n  is: 'x-basic',\n  properties: {\n    notifyingValue: {\n      type: Number,\n      notify: true\n    },\n    computed: {\n      computed: 'compute(notifyingValue)'\n    }\n  },\n  compute: function(val) {\n    return '[' + val + ']';\n  }\n});\nPolymer({\n  _template: html`\n    <x-basic id=\"basic1\" notifying-value=\"{{obj.value}}\" attrvalue\\$=\"{{obj.value}}\" othervalue=\"{{obj.value2}}\"></x-basic>\n    <x-basic id=\"basic2\" notifying-value=\"{{obj.value}}\" attrvalue\\$=\"{{obj.value}}\"></x-basic>\n`,\n\n  is: 'x-compose',\n\n  properties: {\n    obj: {\n      type: Object,\n      notify: true\n    },\n    computed: {\n      computed: 'compute(obj.value)'\n    }\n  },\n\n  observers: [\n    'objSubpathChanged(obj.*)',\n    'objValueChanged(obj.value)',\n  ],\n\n  created: function() {\n    this.resetObservers();\n  },\n\n  resetObservers: function() {\n    this.objSubpathChanged = sinon.spy();\n    this.objValueChanged = sinon.spy();\n  },\n\n  compute: function(val) {\n    return '[' + val + ']';\n  }\n});\nPolymer({\n  _template: html`\n    <x-compose id=\"compose\" obj=\"{{obj}}\"></x-compose>\n`,\n\n  is: 'x-forward',\n\n  properties: {\n    obj: {\n      type: Object,\n      notify: true\n    },\n    computed: {\n      computed: 'compute(obj.value)'\n    }\n  },\n\n  observers: [\n    'objSubpathChanged(obj.*)',\n    'objValueChanged(obj.value)'\n  ],\n\n  created: function() {\n    this.resetObservers();\n  },\n\n  resetObservers: function() {\n    this.objSubpathChanged = sinon.spy();\n    this.objValueChanged = sinon.spy();\n    if (this.$) {\n      this.$.compose.resetObservers();\n    }\n  },\n\n  compute: function(val) {\n    return '[' + val + ']';\n  }\n});\nPolymer({\n  _template: html`\n    <x-basic id=\"basic\" notifying-value=\"{{nested.obj.value}}\" attrvalue\\$=\"{{nested.obj.value}}\"></x-basic>\n    <x-compose id=\"compose\" obj=\"{{nested.obj}}\"></x-compose>\n    <x-forward id=\"forward\" obj=\"{{nested.obj}}\"></x-forward>\n    <div id=\"boundChild\" computed-from-paths=\"{{computeFromPaths(a, nested.b, nested.obj.c)}}\" array-length=\"{{data.length}}\"></div>\n    <x-pe id=\"pe\" obj=\"[[nested.obj]]\"></x-pe>\n`,\n\n  is: 'x-stuff',\n\n  properties: {\n    nested: {\n      observer: 'nestedChanged'\n    },\n    computedFromPaths: {\n      computed: 'computeFromPaths(a, nested.b, nested.obj.c)'\n    },\n    computedFromLinkedPaths: {\n      computed: 'computeFromLinkedPaths(a, linked1.prop, linked2.prop)'\n    },\n    computed: {\n      computed: 'compute(nested.obj.value)'\n    }\n  },\n\n  observers: [\n    'nestedSubpathChanged(nested.*)',\n    'nestedObjChanged(nested.obj)',\n    'nestedObjSubpathChanged(nested.obj.*)',\n    'nestedObjValueChanged(nested.obj.value)',\n    'multipleChanged(a, b, nested.obj.*)',\n    'multiplePathsChanged(a, nested.b, nested.obj.c)',\n    'arrayChanged(array.splices)',\n    'arrayChangedDeep(array.*)',\n    'arrayNoCollChanged(arrayNoColl.splices)',\n    'arrayOrPropChanged(prop, array.splices)',\n    // a has other (computed) effects; x & y don't, which allows testing\n    // different code paths in linkPaths tests\n    'aChanged(a.*)',\n    'xChanged(x.*)',\n    'yChanged(y.*)',\n    'abChanged(a.b.*)',\n    'abcChanged(a.b.c.*)',\n    'abcxChanged(a.b.c.*, x)'\n  ],\n\n  created: function() {\n    this.resetObservers();\n  },\n\n  resetObservers: function() {\n    this.nestedChanged = sinon.spy();\n    this.nestedSubpathChanged = sinon.spy();\n    this.nestedObjChanged = sinon.spy();\n    this.nestedObjSubpathChanged = sinon.spy();\n    this.nestedObjValueChanged = sinon.spy();\n    this.multipleChanged = sinon.spy();\n    this.multiplePathsChanged = sinon.spy();\n    this.arrayChanged = sinon.spy(function(splices) {\n      this.arraySplices = splices;\n    });\n    this.arrayChangedDeep = sinon.spy();\n    this.arrayNoCollChanged = sinon.spy();\n    this.arrayOrPropChanged = sinon.spy();\n    this.aChanged = sinon.spy();\n    this.xChanged = sinon.spy();\n    this.yChanged = sinon.spy();\n    if (this.$) {\n      this.$.compose.resetObservers();\n      this.$.forward.resetObservers();\n      this.$.pe.resetObservers();\n    }\n    this.abChanged = sinon.spy();\n    this.abcChanged = sinon.spy();\n    this.abcxChanged = sinon.spy();\n  },\n\n  computeFromPaths: function(a, b, c) {\n    return a + b + c;\n  },\n\n  computeFromLinkedPaths: sinon.spy(function(a, b, c) {\n    return a + b + c;\n  }),\n\n  compute: function(val) {\n    return '[' + val + ']';\n  }\n});\nPolymer({\n  is: 'x-reentry-client',\n  properties: {\n    prop: {\n      notify: true\n    }\n  },\n  observers: ['objChanged(obj.*)'],\n  created: function() {\n    this.objChanged = sinon.spy(this.objChanged);\n  },\n  objChanged: function(info) {\n    if (info.path !== 'obj') {\n      this.prop++;\n    }\n  }\n});\nPolymer({\n  _template: html`\n    <x-reentry-client obj=\"{{obj}}\" prop=\"{{prop}}\"></x-reentry-client>\n`,\n\n  is: 'x-reentry-host',\n\n  properties: {\n    obj: {\n      value: function() {\n        return {prop: 0};\n      }\n    },\n    prop: {\n      value: 0\n    }\n  },\n\n  observers: ['objChanged(obj.*)'],\n\n  created: function() {\n    this.objChanged = sinon.spy();\n  }\n});\n\nPolymer({\n\n  is: 'x-reentry-true',\n\n  properties: {\n    prop: {\n      type: Boolean,\n      computed: 'computeProp(trigger, value)'\n    },\n    value: {\n      type: Boolean\n    },\n    trigger: {\n      type: Boolean,\n      observer: 'triggerChanged',\n      value: true\n    }\n  },\n  \n  observers: ['propChanged(prop.*)'],\n\n  created() {\n    this.propChanged = sinon.spy();\n  },\n  \n  computeProp(trigger, value) {\n    return Boolean(value);\n  },\n  \n  triggerChanged() {\n    this.value = true;\n  }\n  \n});\n\nPolymer({\n\n  is: 'x-reentry-undefined',\n\n  properties: {\n    prop: {\n      type: Boolean,\n      computed: 'computeProp(trigger, value)'\n    },\n    value: {\n      type: Boolean\n    },\n    trigger: {\n      type: Boolean,\n      observer: 'triggerChanged',\n      value: true\n    }\n  },\n  \n  observers: ['propChanged(prop.*)'],\n\n  created() {\n    this.propChanged = sinon.spy();\n  },\n  \n  computeProp(trigger, value) {\n    return value ? undefined : true;\n  },\n  \n  triggerChanged() {\n    this.value = true;\n  }\n  \n});\n\nPolymer({\n\n  is: 'x-reentry-undefined-path',\n\n  properties: {\n    prop: {\n      type: Object\n    },\n    value: {\n      type: Boolean\n    },\n    trigger: {\n      type: Boolean,\n      value: true\n    }\n  },\n  \n  observers: [\n    'computeProp(trigger, value)',\n    'triggerChanged(trigger)',\n    'propChanged(prop.sub.*)'\n  ],\n\n  created() {\n    this.propChanged = sinon.spy();\n  },\n  \n  computeProp(trigger, value) {\n    if (value) {\n      this.set('prop.sub', undefined);\n    } else {\n      this.prop = {sub: true};\n    }\n  },\n  \n  triggerChanged() {\n    this.value = true;\n  }\n  \n});\n\nPolymer({\n\n  is: 'x-reentry-splices',\n\n  properties: {\n    array: {\n      type: Array,\n      value() { return []; }\n    }\n  },\n  \n  observers: [\n    'changeArray(array.splices.*)',\n    'arrayChanged(array.splices.*)'\n  ],\n\n  created() {\n    this.arrayChanged = sinon.spy();\n  },\n\n  changeArray() {\n    if (this.array.length === 0) {\n      this.push('array', 'one');\n    } else if (this.array.length === 1) {\n      this.push('array', 'two');\n    }\n  }\n  \n});\n\nPolymer({\n  is: 'x-path-client',\n  observers: ['objChanged(obj.*)'],\n  objChanged: function() {}\n});\nPolymer({\n  _template: html`\n    <x-path-client id=\"client\" obj=\"{{obj}}\"></x-path-client>\n`,\n\n  is: 'x-path-host',\n\n  properties: {\n    obj: {\n      value: function() {\n        return {prop: 0};\n      }\n    },\n    prop: {\n      value: 0\n    }\n  },\n\n  observers: ['objChanged(obj.*)'],\n\n  created: function() {\n    this.objChanged = sinon.spy();\n  }\n});"
  },
  {
    "path": "test/unit/path-effects.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n  <script type=\"module\" src=\"./path-effects-elements.js\"></script>\n<body>\n\n<script type=\"module\">\nimport './path-effects-elements.js';\nimport { Polymer } from '../../lib/legacy/polymer-fn.js';\nimport { setOrderedComputed } from '../../lib/utils/settings.js';\n\nsetOrderedComputed(Boolean(window.location.search.match('orderedComputed')));\n\n// Safari 9 has a horrible bug related to array enumeration after defining\n// a non-enumerable property on it (we do for `.splices`); for now we work\n// around chai's deepEqual implementation that enumerates array keys using\n// `for in` in the specific case the bug causes an assert failure\nfunction arraysEqual(a, b) {\n  for (var i=0; i<a.length; i++) {\n    if (a[i] !== b[i]) {\n      throw new Error('expected ' + a + ' to equal ' + b);\n    }\n  }\n  if (a.length != b.length) {\n    throw new Error('expected ' + a + ' to equal ' + b);\n  }\n}\n\nsuite('basic path bindings', function() {\n\n  var el;\n\n  setup(function() {\n    el = document.createElement('x-stuff');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  function verifyObserverOutput(nestingLevel, nested, done) {\n    assert.equal(el.computed, '[' + nested.obj.value + ']');\n    assert.equal(el.nestedChanged.callCount, nestingLevel == 0 ? 1 : 0);\n    if (nestingLevel == 0) {\n      assert.equal(el.nestedChanged.firstCall.args[0], nested);\n    }\n    assert.equal(el.nestedSubpathChanged.callCount, 1);\n    assert.equal(el.nestedObjChanged.callCount, nestingLevel <= 1 ? 1 : 0);\n    if (nestingLevel <= 1) {\n      assert.equal(el.nestedObjChanged.firstCall.args[0], nested.obj);\n    }\n    assert.equal(el.nestedObjSubpathChanged.callCount, 1);\n    assert.equal(el.nestedObjSubpathChanged.firstCall.args[0].base, nested.obj);\n    assert.equal(el.nestedObjValueChanged.callCount, 1);\n    assert.equal(el.nestedObjValueChanged.firstCall.args[0], nested.obj.value);\n    assert.equal(el.nestedSubpathChanged.callCount, 1);\n    assert.equal(el.nestedSubpathChanged.firstCall.args[0].base, nested);\n    assert.equal(el.$.compose.computed, '[' + nested.obj.value + ']');\n    assert.equal(el.$.compose.objSubpathChanged.callCount, 1);\n    assert.equal(el.$.compose.objSubpathChanged.firstCall.args[0].base, nested.obj);\n    assert.equal(el.$.compose.objValueChanged.callCount, 1);\n    assert.equal(el.$.compose.objValueChanged.firstCall.args[0], nested.obj.value);\n    assert.equal(el.$.forward.computed, '[' + nested.obj.value + ']');\n    assert.equal(el.$.forward.objSubpathChanged.callCount, 1);\n    assert.equal(el.$.forward.objSubpathChanged.firstCall.args[0].base, nested.obj);\n    assert.equal(el.$.forward.objValueChanged.callCount, 1);\n    assert.equal(el.$.forward.objValueChanged.firstCall.args[0], nested.obj.value);\n    assert.equal(el.$.basic.computed, '[' + nested.obj.value + ']');\n    assert.equal(el.$.basic.notifyingValue, 42);\n    assert.equal(el.$.basic.notifyingValue, 42);\n    assert.equal(el.$.compose.$.basic1.computed, '[' + nested.obj.value + ']');\n    assert.equal(el.$.compose.$.basic1.notifyingValue, 42);\n    assert.equal(el.$.compose.$.basic2.computed, '[' + nested.obj.value + ']');\n    assert.equal(el.$.compose.$.basic2.notifyingValue, 42);\n    assert.equal(el.$.forward.$.compose.$.basic1.computed, '[' + nested.obj.value + ']');\n    assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 42);\n    assert.equal(el.$.forward.$.compose.$.basic2.computed, '[' + nested.obj.value + ']');\n    assert.equal(el.$.forward.$.compose.$.basic2.notifyingValue, 42);\n    assert.equal(el.$.basic.getAttribute('attrvalue'), '42');\n    assert.equal(el.$.compose.$.basic1.getAttribute('attrvalue'), '42');\n    assert.equal(el.$.compose.$.basic2.getAttribute('attrvalue'), '42');\n    assert.equal(el.$.forward.$.compose.$.basic1.getAttribute('attrvalue'), '42');\n    assert.equal(el.$.forward.$.compose.$.basic2.getAttribute('attrvalue'), '42');\n    assert.equal(el.$.pe.obj, nested.obj);\n    switch (nestingLevel) {\n      case 0:\n        assert.equal(el.nestedSubpathChanged.firstCall.args[0].path, 'nested');\n        assert.equal(el.nestedSubpathChanged.firstCall.args[0].value, nested);\n        assert.equal(el.nestedObjSubpathChanged.firstCall.args[0].path, 'nested.obj');\n        assert.equal(el.nestedObjSubpathChanged.firstCall.args[0].value, nested.obj);\n        assert.equal(el.$.compose.objSubpathChanged.firstCall.args[0].path, 'obj');\n        assert.equal(el.$.compose.objSubpathChanged.firstCall.args[0].value, nested.obj);\n        assert.equal(el.$.forward.objSubpathChanged.firstCall.args[0].path, 'obj');\n        assert.equal(el.$.forward.objSubpathChanged.firstCall.args[0].value, nested.obj);\n        assert.equal(el.$.forward.$.compose.objSubpathChanged.firstCall.args[0].path, 'obj');\n        assert.equal(el.$.forward.$.compose.objSubpathChanged.firstCall.args[0].value, nested.obj);\n        // x-pe uses async PropertiesChanged\n        setTimeout(() => {\n          assert.equal(el.$.pe._propertiesChanged.callCount, 1);\n          assert.equal(el.$.pe._propertiesChanged.firstCall.args[1].obj, nested.obj);\n          done();\n        });\n        break;\n      case 1:\n        assert.equal(el.nestedSubpathChanged.firstCall.args[0].path, 'nested.obj');\n        assert.equal(el.nestedSubpathChanged.firstCall.args[0].value, nested.obj);\n        assert.equal(el.nestedObjSubpathChanged.firstCall.args[0].path, 'nested.obj');\n        assert.equal(el.nestedObjSubpathChanged.firstCall.args[0].value, nested.obj);\n        assert.equal(el.$.compose.objSubpathChanged.firstCall.args[0].path, 'obj');\n        assert.equal(el.$.compose.objSubpathChanged.firstCall.args[0].value, nested.obj);\n        assert.equal(el.$.forward.objSubpathChanged.firstCall.args[0].path, 'obj');\n        assert.equal(el.$.forward.objSubpathChanged.firstCall.args[0].value, nested.obj);\n        assert.equal(el.$.forward.$.compose.objSubpathChanged.firstCall.args[0].path, 'obj');\n        assert.equal(el.$.forward.$.compose.objSubpathChanged.firstCall.args[0].value, nested.obj);\n        // x-pe uses async PropertiesChanged\n        setTimeout(() => {\n          assert.equal(el.$.pe._propertiesChanged.callCount, 1);\n          assert.equal(el.$.pe._propertiesChanged.firstCall.args[1].obj, nested.obj);\n          done();\n        });\n        break;\n      case 2:\n        assert.equal(el.nestedSubpathChanged.firstCall.args[0].path, 'nested.obj.value');\n        assert.equal(el.nestedSubpathChanged.firstCall.args[0].value, 42);\n        assert.equal(el.nestedObjSubpathChanged.firstCall.args[0].path, 'nested.obj.value');\n        assert.equal(el.nestedObjSubpathChanged.firstCall.args[0].value, 42);\n        assert.equal(el.$.compose.objSubpathChanged.firstCall.args[0].path, 'obj.value');\n        assert.equal(el.$.compose.objSubpathChanged.firstCall.args[0].value, 42);\n        assert.equal(el.$.forward.objSubpathChanged.firstCall.args[0].path, 'obj.value');\n        assert.equal(el.$.forward.objSubpathChanged.firstCall.args[0].value, 42);\n        assert.equal(el.$.forward.$.compose.objSubpathChanged.firstCall.args[0].path, 'obj.value');\n        assert.equal(el.$.forward.$.compose.objSubpathChanged.firstCall.args[0].value, 42);\n        // x-pe uses async PropertiesChanged\n        setTimeout(() => {\n          // Note the PropertiesMixin element only sees a deep set to 'nested.obj.value'\n          // because it overrides _shouldPropertyChange to allow object re-sets through\n          assert.equal(el.$.pe._propertiesChanged.callCount, 1);\n          assert.equal(el.$.pe._propertiesChanged.firstCall.args[1].obj, nested.obj);\n          done();\n        });\n        break;\n    }\n  }\n\n  test('downward data flow', function(done) {\n    // Do the thing\n    el.nested = {\n      obj: {\n        value: 42\n      }\n    };\n    // Verify\n    verifyObserverOutput(0, el.nested, done);\n  });\n\n  test('notification from basic element property change', function(done) {\n    // Setup\n    el.nested = {\n      obj: {\n        value: 41\n      }\n    };\n    el.resetObservers();\n    // Do the thing\n    el.$.basic.notifyingValue = 42;\n    // Verify\n    verifyObserverOutput(2, el.nested, done);\n  });\n\n  test('notification from composed element property change', function(done) {\n    // Setup\n    el.nested = {\n      obj: {\n        value: 41\n      }\n    };\n    el.resetObservers();\n    // Do the thing\n    el.$.compose.$.basic1.notifyingValue = 42;\n    // Verify\n    verifyObserverOutput(2, el.nested, done);\n  });\n\n  test('notification from forward\\'s composed element property change', function(done) {\n    // Setup\n    el.nested = {\n      obj: {\n        value: 41\n      }\n    };\n    el.resetObservers();\n    // Do the thing\n    el.$.forward.$.compose.$.basic1.notifyingValue = 42;\n    // Verify\n    verifyObserverOutput(2, el.nested, done);\n  });\n\n  test('notification from set in top element', function(done) {\n    // Setup\n    el.nested = {\n      obj: {\n        value: 41\n      }\n    };\n    el.resetObservers();\n    // Do the thing\n    el.set('nested.obj.value', 42);\n    // Verify\n    verifyObserverOutput(2, el.nested, done);\n  });\n\n  test('notification from set in composed element', function(done) {\n    // Setup\n    el.nested = {\n      obj: {\n        value: 41\n      }\n    };\n    el.resetObservers();\n    // Do the thing\n    el.$.compose.set('obj.value', 42);\n    // Verify\n    verifyObserverOutput(2, el.nested, done);\n  });\n\n  test('notification from set in forward element', function(done) {\n    // Setup\n    el.nested = {\n      obj: {\n        value: 41\n      }\n    };\n    el.resetObservers();\n    // Do the thing\n    el.$.forward.set('obj.value', 42);\n    // Verify\n    verifyObserverOutput(2, el.nested, done);\n  });\n\n  test('notification from set in forward\\'s composed element', function(done) {\n    // Setup\n    el.nested = {\n      obj: {\n        value: 41\n      }\n    };\n    el.resetObservers();\n    // Do the thing\n    el.$.forward.$.compose.set('obj.value', 42);\n    // Verify\n    verifyObserverOutput(2, el.nested, done);\n  });\n\n  test('notification from object change in compose element', function(done) {\n    // Setup\n    el.nested = {\n      obj: {\n        value: 41\n      }\n    };\n    el.resetObservers();\n    // Do the thing\n    el.$.compose.obj = {\n      value: 42\n    };\n    // Verify\n    verifyObserverOutput(1, el.nested, done);\n  });\n\n  test('notification from object change in forward element', function(done) {\n    // Setup\n    el.nested = {\n      obj: {\n        value: 41\n      }\n    };\n    el.resetObservers();\n    // Do the thing\n    el.$.forward.obj = {\n      value: 42\n    };\n    // Verify\n    verifyObserverOutput(1, el.nested, done);\n  });\n\n  test('notification from object change in forward\\'s compose element', function(done) {\n    // Setup\n    el.nested = {\n      obj: {\n        value: 41\n      }\n    };\n    el.resetObservers();\n    // Do the thing\n    // Do the thing\n    el.$.forward.$.compose.obj = {\n      value: 42\n    };\n    // Verify\n    verifyObserverOutput(1, el.nested, done);\n  });\n\n  test('cached paths get invalidated by object sets', function() {\n    el.nested = {obj: { value: 'initial' }};\n    assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 'initial');\n    el.$.forward.$.compose.$.basic1.notifyingValue = 'correct';\n    assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 'correct');\n    el.nested = {obj: { value: 'wrong' }};\n    assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 'wrong');\n    el.set('nested.obj.value', 'correct');\n    assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 'correct');\n  });\n\n  test('similarly named properties', function() {\n    var nested = {\n      obj: {\n        value: 41,\n        value2: 99\n      }\n    };\n    el.nested = nested;\n    assert.equal(el.$.compose.$.basic1.notifyingValue, 41);\n    assert.equal(el.$.compose.$.basic1.othervalue, 99);\n    el.set('nested.obj.value', 42);\n    assert.equal(el.$.compose.$.basic1.notifyingValue, 42);\n    assert.equal(el.$.compose.$.basic1.othervalue, 99);\n    el.set('nested.obj.value2', 98);\n    assert.equal(el.$.compose.$.basic1.notifyingValue, 42);\n    assert.equal(el.$.compose.$.basic1.othervalue, 98);\n  });\n\n  suite('ancestors and descendants', function() {\n\n    test('change base', function() {\n      let c = {}, b = {c}, a = {b};\n      el.a = a;\n      assert.equal(el.aChanged.callCount, 1);\n      assert.deepEqual(el.aChanged.firstCall.args[0], {path: 'a', base: a, value: a});\n      assert.equal(el.abChanged.callCount, 1);\n      assert.deepEqual(el.abChanged.firstCall.args[0], {path: 'a.b', base: b, value: b});\n      assert.equal(el.abcChanged.callCount, 1);\n      assert.deepEqual(el.abcChanged.firstCall.args[0], {path: 'a.b.c', base: c, value: c});\n      assert.equal(el.abcxChanged.callCount, 1);\n      assert.deepEqual(el.abcxChanged.firstCall.args[0], {path: 'a.b.c', base: c, value: c});\n    });\n\n    test('change subpath level 1', function() {\n      let c = {}, b = {c}, a = {b};\n      el.a = a;\n      el.resetObservers();\n      c = {};\n      b = {c};\n      el.set('a.b', b);\n      assert.equal(el.aChanged.callCount, 1);\n      assert.deepEqual(el.aChanged.firstCall.args[0], {path: 'a.b', base: a, value: b});\n      assert.equal(el.abChanged.callCount, 1);\n      assert.deepEqual(el.abChanged.firstCall.args[0], {path: 'a.b', base: b, value: b});\n      assert.equal(el.abcChanged.callCount, 1);\n      assert.deepEqual(el.abcChanged.firstCall.args[0], {path: 'a.b.c', base: c, value: c});\n      assert.equal(el.abcxChanged.callCount, 1);\n      assert.deepEqual(el.abcxChanged.firstCall.args[0], {path: 'a.b.c', base: c, value: c});\n    });\n\n    test('change subpath level 2', function() {\n      let c = {}, b = {c}, a = {b};\n      el.a = a;\n      el.resetObservers();\n      c = {};\n      el.set('a.b.c', c);\n      assert.equal(el.aChanged.callCount, 1);\n      assert.deepEqual(el.aChanged.firstCall.args[0], {path: 'a.b.c', base: a, value: c});\n      assert.equal(el.abChanged.callCount, 1);\n      assert.deepEqual(el.abChanged.firstCall.args[0], {path: 'a.b.c', base: b, value: c});\n      assert.equal(el.abcChanged.callCount, 1);\n      assert.deepEqual(el.abcChanged.firstCall.args[0], {path: 'a.b.c', base: c, value: c});\n      assert.equal(el.abcxChanged.callCount, 1);\n      assert.deepEqual(el.abcxChanged.firstCall.args[0], {path: 'a.b.c', base: c, value: c});\n    });\n\n    test('change subpath of base only', function() {\n      let c = {}, b = {c}, a = {b};\n      el.a = a;\n      el.resetObservers();\n      let d = {};\n      el.set('a.d', d);\n      assert.equal(el.aChanged.callCount, 1);\n      assert.deepEqual(el.aChanged.firstCall.args[0], {path: 'a.d', base: a, value: d});\n      assert.equal(el.abChanged.callCount, 0);\n      assert.equal(el.abcChanged.callCount, 0);\n      assert.equal(el.abcxChanged.callCount, 0);\n    });\n\n    test('change subpath of level 1 only', function() {\n      let c = {}, b = {c}, a = {b};\n      el.a = a;\n      el.resetObservers();\n      let e = {};\n      el.set('a.b.e', e);\n      assert.equal(el.aChanged.callCount, 1);\n      assert.deepEqual(el.aChanged.firstCall.args[0], {path: 'a.b.e', base: a, value: e});\n      assert.equal(el.abChanged.callCount, 1);\n      assert.deepEqual(el.abChanged.firstCall.args[0], {path: 'a.b.e', base: b, value: e});\n      assert.equal(el.abcChanged.callCount, 0);\n      assert.equal(el.abcxChanged.callCount, 0);\n    });\n    \n    test('change subpath of level 2', function() {\n      let c = {}, b = {c}, a = {b};\n      el.a = a;\n      el.resetObservers();\n      let f = {};\n      el.set('a.b.c.f', f);\n      assert.equal(el.aChanged.callCount, 1);\n      assert.deepEqual(el.aChanged.firstCall.args[0], {path: 'a.b.c.f', base: a, value: f});\n      assert.equal(el.abChanged.callCount, 1);\n      assert.deepEqual(el.abChanged.firstCall.args[0], {path: 'a.b.c.f', base: b, value: f});\n      assert.equal(el.abcChanged.callCount, 1);\n      assert.deepEqual(el.abcChanged.firstCall.args[0], {path: 'a.b.c.f', base: c, value: f});\n      assert.equal(el.abcxChanged.callCount, 1);\n      assert.deepEqual(el.abcxChanged.firstCall.args[0], {path: 'a.b.c.f', base: c, value: f});\n    });\n    \n    test('change non-wildcard argument', function() {\n      let c = {}, b = {c}, a = {b};\n      el.a = a;\n      el.resetObservers();\n      let x = el.x = {};\n      assert.equal(el.aChanged.callCount, 0);\n      assert.equal(el.abChanged.callCount, 0);\n      assert.equal(el.abcChanged.callCount, 0);\n      assert.equal(el.abcxChanged.callCount, 1);\n      assert.deepEqual(el.abcxChanged.firstCall.args[0], {path: 'a.b.c', base: c, value: c});\n      assert.equal(el.abcxChanged.firstCall.args[1], x);\n    });\n    \n  });\n\n});\n\nsuite('path effects', function() {\n\n  var el;\n\n  setup(function() {\n    el = document.createElement('x-stuff');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('observer with multiple args, object last', function() {\n    // Setup\n    var nested = {\n      obj: {\n        value: 42\n      }\n    };\n    // Do the thing\n    el.setProperties({\n      a: 'a',\n      b: 'b',\n      nested: nested\n    });\n    // Verify\n    assert.equal(el.multipleChanged.callCount, 1);\n    assert.equal(el.multipleChanged.firstCall.args[0], 'a');\n    assert.equal(el.multipleChanged.firstCall.args[1], 'b');\n    assert.equal(el.multipleChanged.firstCall.args[2].path, 'nested.obj');\n    assert.equal(el.multipleChanged.firstCall.args[2].value, nested.obj);\n    assert.equal(el.multipleChanged.firstCall.args[2].base, nested.obj);\n  });\n\n  test('observer with multiple args, object not last', function() {\n    // Setup\n    var nested = {\n      obj: {\n        value: 42\n      }\n    };\n    // Do the thing\n    el.setProperties({\n      a: 'a',\n      nested: nested,\n      b: 'b'\n    });\n    // Verify\n    assert.equal(el.multipleChanged.callCount, 1);\n    assert.equal(el.multipleChanged.firstCall.args[0], 'a');\n    assert.equal(el.multipleChanged.firstCall.args[1], 'b');\n    assert.equal(el.multipleChanged.firstCall.args[2].path, 'nested.obj');\n    assert.equal(el.multipleChanged.firstCall.args[2].value, nested.obj);\n    assert.equal(el.multipleChanged.firstCall.args[2].base, nested.obj);\n  });\n\n  test('observer with multiple args, object first, then last', function() {\n    // Setup\n    var nested = {\n      obj: {\n        value: 42\n      }\n    };\n    el.nested = nested;\n    el.resetObservers();\n    // Do the thing\n    el.setProperties({\n      a: 'a',\n      b: 'b'\n    });\n    // Verify\n    assert.equal(el.multipleChanged.callCount, 1);\n    assert.equal(el.multipleChanged.firstCall.args[0], 'a');\n    assert.equal(el.multipleChanged.firstCall.args[1], 'b');\n    assert.equal(el.multipleChanged.firstCall.args[2].path, 'nested.obj');\n    assert.equal(el.multipleChanged.firstCall.args[2].value, nested.obj);\n    assert.equal(el.multipleChanged.firstCall.args[2].base, nested.obj);\n\n    // Do another thing\n    el.set('nested.obj.value', 43);\n    // Verify\n    assert.equal(el.multipleChanged.callCount, 2);\n    assert.equal(el.multipleChanged.secondCall.args[0], 'a');\n    assert.equal(el.multipleChanged.secondCall.args[1], 'b');\n    assert.equal(el.multipleChanged.secondCall.args[2].path, 'nested.obj.value');\n    assert.equal(el.multipleChanged.secondCall.args[2].value, 43);\n    assert.equal(el.multipleChanged.secondCall.args[2].base, nested.obj);\n  });\n\n  test('observer & computed with multiple path args', function() {\n    // Setup\n    var nested = {\n      b: 33,\n      obj: {\n        c: 66\n      }\n    };\n    var a = 1;\n    // Do the thing\n    el.setProperties({\n      a: a,\n      nested: nested\n    });\n    // Verify\n    assert.equal(el.multiplePathsChanged.callCount, 1);\n    assert.equal(el.multiplePathsChanged.firstCall.args[0], 1);\n    assert.equal(el.multiplePathsChanged.firstCall.args[1], 33);\n    assert.equal(el.multiplePathsChanged.firstCall.args[2], 66);\n    assert.equal(el.computedFromPaths, 100);\n    assert.equal(el.$.boundChild.computedFromPaths, 100);\n\n    el.set('a', a + 10);\n    assert.equal(el.$.boundChild.computedFromPaths, 110);\n\n    el.set('nested.b', nested.b + 10);\n    assert.equal(el.$.boundChild.computedFromPaths, 120);\n\n    el.set('nested.obj.c', nested.obj.c + 10);\n    assert.equal(el.$.boundChild.computedFromPaths, 130);\n  });\n\n  test('array.splices notified', function() {\n    el.arrayNoColl = [];\n    assert.equal(el.arrayNoCollChanged.callCount, 1);\n    el.push('arrayNoColl', 1, 2, 3);\n    assert.equal(el.arrayNoCollChanged.callCount, 2);\n    el.push('arrayNoColl', 4, 5, 6);\n    assert.equal(el.arrayNoCollChanged.callCount, 3);\n  });\n\n  test('ensure splices sent into userland dont get nulled', function(){\n    el.array = [];\n    el.push('array', 1, 2, 3);\n    assert.notEqual(el.arraySplices.indexSplices, null);\n  });\n\n  test('array.splices notified, multiple args, prop first', function() {\n    var array = [];\n    el.setProperties({\n      array: array,\n      prop: 'first'\n    });\n    assert.equal(el.arrayOrPropChanged.callCount, 1);\n    el.push('array', 1, 2, 3);\n    assert.equal(el.arrayOrPropChanged.callCount, 2);\n    el.push('array', 4, 5, 6);\n    assert.equal(el.arrayOrPropChanged.callCount, 3);\n  });\n\n  test('array.splices notified, multiple args, prop last', function() {\n    el.array = [];\n    el.push('array', 1, 2, 3);\n    el.prop = 'last';\n    // Twice for array (.splices & .length), once for prop\n    assert.equal(el.arrayOrPropChanged.callCount, 3);\n  });\n\n  test('array.length notified', function() {\n    el.data = [];\n    assert.equal(el.$.boundChild.arrayLength, el.data.length);\n    el.push('data', 1, 2, 3);\n    assert.equal(el.$.boundChild.arrayLength, el.data.length);\n    el.pop('data');\n    el.pop('data');\n    assert.equal(el.$.boundChild.arrayLength, el.data.length);\n    el.unshift('data', 4, 5);\n    el.unshift('data', 6, 7, 8);\n    assert.equal(el.$.boundChild.arrayLength, el.data.length);\n    el.splice('data', 9, 10, 11, 12, 13);\n    assert.equal(el.$.boundChild.arrayLength, el.data.length);\n    el.shift('data');\n    el.shift('data');\n    el.shift('data');\n    assert.equal(el.$.boundChild.arrayLength, el.data.length);\n  });\n\n  test('splice correctly deletes full array if only 1 argument is passed in', function() {\n    el.data = [1,2,3];\n    assert.equal(el.data.length, 3);\n    el.splice('data', 0);\n    assert.equal(el.data.length, 0);\n  });\n\n});\n\nsuite('path API', function() {\n\n  var el;\n\n  setup(function() {\n    el = document.createElement('x-stuff');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('get', function() {\n    el.simple = 11;\n    el.nested = {\n      again: {\n        again: {\n          wayOverThere: 99\n        },\n        there: 55\n      },\n      here: 42\n    };\n    assert.equal(el.get('simple'), 11);\n    assert.equal(el.get('nested'), el.nested);\n    assert.equal(el.get('nested.here'), 42);\n    assert.equal(el.get(['nested', 'again']), el.nested.again);\n    assert.equal(el.get('nested.again.there'), 55);\n    assert.equal(el.get('nested.again.again'), el.nested.again.again);\n    assert.equal(el.get(['nested', 'again.again', 'wayOverThere']), 99);\n  });\n\n  test('set', function() {\n    el.set('simple', 11);\n    el.set('nested', {});\n    el.set('nested.here', 42);\n    el.set(['nested', 'again'], {});\n    el.set('nested.again.there', 55);\n    el.set('nested.again.again', {});\n    el.set(['nested', 'again.again', 'wayOverThere'], 99);\n    el.set(['again.thereToo'], 111, el.nested.again);\n    assert.equal(el.simple, 11);\n    assert.equal(el.get('simple'), 11);\n    assert.equal(el.get('nested'), el.nested);\n    assert.equal(el.nested.here, 42);\n    assert.equal(el.get('nested.here'), 42);\n    assert.equal(el.get('nested.again'), el.nested.again);\n    assert.equal(el.nested.again.there, 55);\n    assert.equal(el.get('nested.again.there'), 55);\n    assert.equal(el.get('nested.again.again'), el.nested.again.again);\n    assert.equal(el.nested.again.again.wayOverThere, 99);\n    assert.equal(el.get('nested.again.again.wayOverThere'), 99);\n    assert.equal(el.nested.again.again.thereToo, 111);\n    assert.equal(el.get('nested.again.again.thereToo'), 111);\n  });\n\n  test('notifyPath basic', function() {\n    el.a = {b: {c: 0}};\n    el.resetObservers();\n    el.a.b.c = 55;\n    el.notifyPath('a.b.c');\n    assert.isTrue(el.aChanged.calledOnce);\n    assert.equal(el.aChanged.firstCall.args[0].path, 'a.b.c');\n    assert.equal(el.aChanged.firstCall.args[0].value, 55);\n    assert.equal(el.get('a.b.c'), 55);\n  });\n\n  test('notifyPath with array path argument', function() {\n    el.a = {b: {c: 0}};\n    el.resetObservers();\n    el.a.b.c = 56;\n    el.notifyPath(['a', 'b.c']);\n    assert.isTrue(el.aChanged.calledOnce);\n    assert.equal(el.aChanged.firstCall.args[0].path, 'a.b.c');\n    assert.equal(el.aChanged.firstCall.args[0].value, 56);\n    assert.equal(el.get('a.b.c'), 56);\n  });\n\n  test('notifyPath with value argument', function() {\n    el.a = {b: {c: 0}};\n    el.resetObservers();\n    el.a.b.c = 57;\n    el.notifyPath('a.b.c', 57);\n    assert.isTrue(el.aChanged.calledOnce);\n    assert.equal(el.aChanged.firstCall.args[0].path, 'a.b.c');\n    assert.equal(el.aChanged.firstCall.args[0].value, 57);\n    assert.equal(el.get('a.b.c'), 57);\n  });\n\n  test('notifyPath with value argument and array path argument', function() {\n    el.a = {b: {c: 0}};\n    el.resetObservers();\n    el.a.b.c = 57;\n    el.notifyPath(['a', 'b.c'], 57);\n    assert.isTrue(el.aChanged.calledOnce);\n    assert.equal(el.aChanged.firstCall.args[0].path, 'a.b.c');\n    assert.equal(el.aChanged.firstCall.args[0].value, 57);\n    assert.equal(el.get('a.b.c'), 57);\n  });\n\n  test('notifyPath a non-extistant does nothing', function() {\n    el.notifyPath('does.not.exist', true);\n  });\n\n  test('get array', function() {\n    el.arrayChanged = function() {};\n    el.array = [1, 2, 3];\n    el.array.array = [5, 6, 7];\n    el.array.prop = 'prop';\n    assert.equal(el.get('array'), el.array);\n    assert.equal(el.get('array.0'), 1);\n    assert.equal(el.get('array.1'), 2);\n    assert.equal(el.get('array.2'), 3);\n    assert.equal(el.get('array.array'), el.array.array);\n    assert.equal(el.get('array.array.0'), 5);\n    assert.equal(el.get('array.array.1'), 6);\n    assert.equal(el.get('array.array.2'), 7);\n    assert.equal(el.get('array.prop'), 'prop');\n    el.unshift('array', 0);\n    el.splice('array', 2, 0, 1.5);\n    el.unshift('array.array', 4);\n    el.splice('array.array', 2, 0, 5.5);\n    assert.equal(el.get('array.0'), 0);\n    assert.equal(el.get('array.1'), 1);\n    assert.equal(el.get('array.2'), 1.5);\n    assert.equal(el.get('array.3'), 2);\n    assert.equal(el.get('array.4'), 3);\n    assert.equal(el.get('array.array.0'), 4);\n    assert.equal(el.get('array.array.1'), 5);\n    assert.equal(el.get('array.array.2'), 5.5);\n    assert.equal(el.get('array.array.3'), 6);\n    assert.equal(el.get('array.array.4'), 7);\n  });\n\n  test('set array', function() {\n    el.arrayChanged = function() {};\n    el.set('array', [1, 2, 3]);\n    el.set('array.array', [5, 6, 7]);\n    el.set('array.prop', 'prop');\n    assert.equal(el.get('array'), el.array);\n    assert.equal(el.get('array.0'), 1);\n    assert.equal(el.get('array.1'), 2);\n    assert.equal(el.get('array.2'), 3);\n    assert.equal(el.get('array.array'), el.array.array);\n    assert.equal(el.get('array.array.0'), 5);\n    assert.equal(el.get('array.array.1'), 6);\n    assert.equal(el.get('array.array.2'), 7);\n    assert.equal(el.get('array.prop'), 'prop');\n    el.set(['array', 0], 81);\n    el.set(['array', 1], 82);\n    el.set(['array', 2], 83);\n    el.set(['array.array', 0], 91);\n    el.set(['array.array', 1], 92);\n    el.set(['array.array', 2], 93);\n    el.set('array.prop', 'foo');\n    assert.equal(el.get('array.0'), 81);\n    assert.equal(el.get('array.1'), 82);\n    assert.equal(el.get('array.2'), 83);\n    assert.equal(el.get('array.array.0'), 91);\n    assert.equal(el.get('array.array.1'), 92);\n    assert.equal(el.get('array.array.2'), 93);\n    assert.equal(el.get('array.prop'), 'foo');\n    // el.set(['array', '#0'], 31);\n    // el.set(['array', '#1'], 32);\n    // el.set(['array', '#2'], 33);\n    // el.set(['array.array', '#0'], 41);\n    // el.set(['array.array', '#1'], 42);\n    // el.set(['array.array', '#2'], 43);\n  });\n\n  var nop = function() {};\n\n  test('push array', function() {\n    el.arrayChanged = nop;\n    el.array = ['orig1', 'orig2', 'orig3'];\n    // var key = el.array.length;\n    el.arrayChanged = function(change) {\n      assert.strictEqual(change.indexSplices.length, 1);\n      assert.strictEqual(change.indexSplices[0].index, 3);\n      assert.strictEqual(change.indexSplices[0].addedCount, 2);\n      assert.strictEqual(change.indexSplices[0].removed.length, 0);\n    };\n    var ret = el.push('array', 'new1', 'new2');\n    assert.strictEqual(ret, 5);\n    assert.strictEqual(el.array.length, 5);\n    assert.strictEqual(el.array[0], 'orig1');\n    assert.strictEqual(el.array[1], 'orig2');\n    assert.strictEqual(el.array[2], 'orig3');\n    assert.strictEqual(el.array[3], 'new1');\n    assert.strictEqual(el.array[4], 'new2');\n  });\n\n  test('pop array', function() {\n    el.arrayChanged = nop;\n    el.array = ['orig1', 'orig2', 'orig3'];\n    // var key = el.array.length-1;\n    el.arrayChanged = function(change) {\n      assert.strictEqual(change.indexSplices.length, 1);\n      assert.strictEqual(change.indexSplices[0].index, 2);\n      assert.strictEqual(change.indexSplices[0].addedCount, 0);\n      assert.strictEqual(change.indexSplices[0].removed.length, 1);\n      assert.strictEqual(change.indexSplices[0].removed[0], 'orig3');\n    };\n    var ret = el.pop('array');\n    assert.strictEqual(ret, 'orig3');\n    assert.strictEqual(el.array.length, 2);\n    assert.strictEqual(el.array[0], 'orig1');\n    assert.strictEqual(el.array[1], 'orig2');\n  });\n\n  test('unshift array', function() {\n    el.arrayChanged = nop;\n    el.array = ['orig1', 'orig2', 'orig3'];\n    // var key = el.array.length;\n    el.arrayChanged = function(change) {\n      assert.strictEqual(change.indexSplices.length, 1);\n      assert.strictEqual(change.indexSplices[0].index, 0);\n      assert.strictEqual(change.indexSplices[0].addedCount, 2);\n      assert.strictEqual(change.indexSplices[0].removed.length, 0);\n    };\n    var ret = el.unshift('array', 'new1', 'new2');\n    assert.strictEqual(ret, 5);\n    assert.strictEqual(el.array.length, 5);\n    assert.strictEqual(el.array[0], 'new1');\n    assert.strictEqual(el.array[1], 'new2');\n    assert.strictEqual(el.array[2], 'orig1');\n    assert.strictEqual(el.array[3], 'orig2');\n    assert.strictEqual(el.array[4], 'orig3');\n  });\n\n  test('shift array', function() {\n    el.arrayChanged = nop;\n    el.array = ['orig1', 'orig2', 'orig3'];\n    el.arrayChanged = function(change) {\n      assert.strictEqual(change.indexSplices.length, 1);\n      assert.strictEqual(change.indexSplices[0].index, 0);\n      assert.strictEqual(change.indexSplices[0].addedCount, 0);\n      assert.strictEqual(change.indexSplices[0].removed.length, 1);\n      assert.strictEqual(change.indexSplices[0].removed[0], 'orig1');\n    };\n    var ret = el.shift('array');\n    assert.strictEqual(ret, 'orig1');\n    assert.strictEqual(el.array.length, 2);\n    assert.strictEqual(el.array[0], 'orig2');\n    assert.strictEqual(el.array[1], 'orig3');\n  });\n\n  test('splice array', function() {\n    el.arrayChanged = nop;\n    el.array = ['orig1', 'orig2', 'orig3'];\n    // var key = el.array.length;\n    el.arrayChanged = function(change) {\n      assert.strictEqual(change.indexSplices.length, 1);\n      assert.strictEqual(change.indexSplices[0].index, 1);\n      assert.strictEqual(change.indexSplices[0].addedCount, 2);\n      assert.strictEqual(change.indexSplices[0].removed.length, 1);\n      assert.strictEqual(change.indexSplices[0].removed[0], 'orig2');\n    };\n    var ret = el.splice('array', 1, 1, 'new1', 'new2');\n    assert.deepEqual(ret, ['orig2']);\n    assert.strictEqual(el.array.length, 4);\n    assert.strictEqual(el.array[0], 'orig1');\n    assert.strictEqual(el.array[1], 'new1');\n    assert.strictEqual(el.array[2], 'new2');\n    assert.strictEqual(el.array[3], 'orig3');\n  });\n\n  test('corner: no-op push array', function() {\n    el.arrayChanged = nop;\n    el.array = ['orig1', 'orig2', 'orig3'];\n    el.arrayChanged = function() {\n      throw new Error(\"should not notify\");\n    };\n    var ret = el.push('array');\n    assert.deepEqual(ret, 3);\n    assert.strictEqual(el.array.length, 3);\n    assert.strictEqual(el.array[0], 'orig1');\n    assert.strictEqual(el.array[1], 'orig2');\n    assert.strictEqual(el.array[2], 'orig3');\n  });\n\n  test('corner: no-op pop array', function() {\n    el.arrayChanged = nop;\n    el.array = [];\n    el.arrayChanged = function() {\n      throw new Error(\"should not notify\");\n    };\n    var ret = el.pop('array');\n    assert.strictEqual(ret, undefined);\n    assert.strictEqual(el.array.length, 0);\n  });\n\n  test('corner: no-op unshift array', function() {\n    el.arrayChanged = nop;\n    el.array = ['orig1', 'orig2', 'orig3'];\n    el.arrayChanged = function() {\n      throw new Error(\"should not notify\");\n    };\n    var ret = el.unshift('array');\n    assert.deepEqual(ret, 3);\n    assert.strictEqual(el.array.length, 3);\n    assert.strictEqual(el.array[0], 'orig1');\n    assert.strictEqual(el.array[1], 'orig2');\n    assert.strictEqual(el.array[2], 'orig3');\n  });\n\n  test('corner: no-op shift array', function() {\n    el.arrayChanged = nop;\n    el.array = [];\n    el.arrayChanged = function() {\n      throw new Error(\"should not notify\");\n    };\n    var ret = el.shift('array');\n    assert.strictEqual(ret, undefined);\n    assert.strictEqual(ret, undefined);\n    assert.strictEqual(el.array.length, 0);\n  });\n\n  test('corner: no-op splice array', function() {\n    el.arrayChanged = nop;\n    el.array = ['orig1', 'orig2', 'orig3'];\n    el.arrayChanged = function() {\n      throw new Error(\"should not notify\");\n    };\n    var ret = el.splice('array');\n    assert.deepEqual(ret, []);\n    assert.strictEqual(el.array.length, 3);\n    assert.strictEqual(el.array[0], 'orig1');\n    assert.strictEqual(el.array[1], 'orig2');\n    assert.strictEqual(el.array[2], 'orig3');\n  });\n\n  test('corner: splice array: string args', function() {\n    el.arrayChanged = nop;\n    el.array = ['orig1', 'orig2', 'orig3'];\n    // var key = el.array.length;\n    el.arrayChanged = function(change) {\n      assert.strictEqual(change.indexSplices.length, 1);\n      assert.strictEqual(change.indexSplices[0].index, 1);\n      assert.strictEqual(change.indexSplices[0].addedCount, 2);\n      assert.strictEqual(change.indexSplices[0].removed.length, 1);\n      assert.strictEqual(change.indexSplices[0].removed[0], 'orig2');\n    };\n    var ret = el.splice('array', '1', '1', 'new1', 'new2');\n    assert.deepEqual(ret, ['orig2']);\n    assert.strictEqual(el.array.length, 4);\n    assert.strictEqual(el.array[0], 'orig1');\n    assert.strictEqual(el.array[1], 'new1');\n    assert.strictEqual(el.array[2], 'new2');\n    assert.strictEqual(el.array[3], 'orig3');\n  });\n\n  test('corner: splice array: negative start', function() {\n    el.arrayChanged = nop;\n    el.array = ['orig1', 'orig2', 'orig3'];\n    // var key = el.array.length;\n    el.arrayChanged = function(change) {\n      assert.strictEqual(change.indexSplices.length, 1);\n      assert.strictEqual(change.indexSplices[0].index, 1);\n      assert.strictEqual(change.indexSplices[0].addedCount, 2);\n      assert.strictEqual(change.indexSplices[0].removed.length, 1);\n      assert.strictEqual(change.indexSplices[0].removed[0], 'orig2');\n    };\n    var ret = el.splice('array', '-2', '1', 'new1', 'new2');\n    assert.deepEqual(ret, ['orig2']);\n    assert.strictEqual(el.array.length, 4);\n    assert.strictEqual(el.array[0], 'orig1');\n    assert.strictEqual(el.array[1], 'new1');\n    assert.strictEqual(el.array[2], 'new2');\n    assert.strictEqual(el.array[3], 'orig3');\n  });\n\n  test('link two objects', function() {\n    el.x = el.y = {};\n    el.linkPaths('y', 'x');\n    el.xChanged = sinon.spy();\n    el.yChanged = sinon.spy();\n    el.set('x.foo', 1);\n    assert.equal(el.xChanged.callCount, 1);\n    assert.equal(el.yChanged.callCount, 1);\n    el.unlinkPaths('y');\n    el.set('x.foo', 2);\n    assert.equal(el.xChanged.callCount, 2);\n    assert.equal(el.yChanged.callCount, 1);\n  });\n\n  test('link three objects', function() {\n    el.x = el.y = el.a = {};\n    el.linkPaths('y', 'x');\n    el.linkPaths('a', 'x');\n    el.xChanged = sinon.spy();\n    el.yChanged = sinon.spy();\n    el.aChanged = sinon.spy();\n    el.set('x.foo', 1);\n    assert.equal(el.xChanged.callCount, 1);\n    assert.equal(el.yChanged.callCount, 1);\n    assert.equal(el.aChanged.callCount, 1);\n    el.set('a.foo', 2);\n    assert.equal(el.xChanged.callCount, 2);\n    assert.equal(el.yChanged.callCount, 2);\n    assert.equal(el.aChanged.callCount, 2);\n    el.unlinkPaths('y');\n    el.set('a.foo', 3);\n    assert.equal(el.xChanged.callCount, 3);\n    assert.equal(el.yChanged.callCount, 2);\n    assert.equal(el.aChanged.callCount, 3);\n  });\n\n  test('multiple linked dependencies to computed property', function() {\n    let linkedObj = {prop: 'Linked'};\n    el.computeFromLinkedPaths.reset();\n    el.setProperties({\n      linked1: linkedObj,\n      linked2: linkedObj,\n      a: 'A'\n    });\n    assert.equal(el.computeFromLinkedPaths.callCount, 1);\n    assert.equal(el.computedFromLinkedPaths, 'ALinkedLinked');\n\n    el.linkPaths('linked1', 'linked2');\n    el.set('linked1.prop', 'Linked+');\n    assert.equal(el.computeFromLinkedPaths.callCount, 2);\n    assert.equal(el.computedFromLinkedPaths, 'ALinked+Linked+');\n    el.linked3 = el.linked2;\n    el.linkPaths('linked2', 'linked3');\n    el.set('linked3.prop', 'Linked++');\n    assert.equal(el.computeFromLinkedPaths.callCount, 3);\n    assert.equal(el.computedFromLinkedPaths, 'ALinked++Linked++');\n    el.set('linked2.prop', 'Linked+++');\n    assert.equal(el.computeFromLinkedPaths.callCount, 4);\n    assert.equal(el.computedFromLinkedPaths, 'ALinked+++Linked+++');\n    el.set('linked1.prop', 'Linked++++');\n    assert.equal(el.computeFromLinkedPaths.callCount, 5);\n    assert.equal(el.computedFromLinkedPaths, 'ALinked++++Linked++++');\n\n    el.linked4 = el.linked1;\n    el.linkPaths('linked4', 'linked1');\n    el.set('linked4.prop', 'Linked+++++');\n    assert.equal(el.computeFromLinkedPaths.callCount, 6);\n    assert.equal(el.computedFromLinkedPaths, 'ALinked+++++Linked+++++');\n    el.set('linked3.prop', 'Linked++++++');\n    assert.equal(el.computeFromLinkedPaths.callCount, 7);\n    assert.equal(el.computedFromLinkedPaths, 'ALinked++++++Linked++++++');\n    el.set('linked2.prop', 'Linked+++++++');\n    assert.equal(el.computeFromLinkedPaths.callCount, 8);\n    assert.equal(el.computedFromLinkedPaths, 'ALinked+++++++Linked+++++++');\n    el.set('linked1.prop', 'Linked++++++++');\n    assert.equal(el.computeFromLinkedPaths.callCount, 9);\n    assert.equal(el.computedFromLinkedPaths, 'ALinked++++++++Linked++++++++');\n\n    el.linked5 = el.linked3;\n    el.linkPaths('linked5', 'linked3');\n    el.set('linked4.prop', 'Linked+++++++++');\n    assert.equal(el.computeFromLinkedPaths.callCount, 10);\n    assert.equal(el.computedFromLinkedPaths, 'ALinked+++++++++Linked+++++++++');\n    el.set('linked3.prop', 'Linked++++++++++');\n    assert.equal(el.computeFromLinkedPaths.callCount, 11);\n    assert.equal(el.computedFromLinkedPaths, 'ALinked++++++++++Linked++++++++++');\n    el.set('linked2.prop', 'Linked+++++++++++');\n    assert.equal(el.computeFromLinkedPaths.callCount, 12);\n    assert.equal(el.computedFromLinkedPaths, 'ALinked+++++++++++Linked+++++++++++');\n    el.set('linked1.prop', 'Linked++++++++++++');\n    assert.equal(el.computeFromLinkedPaths.callCount, 13);\n    assert.equal(el.computedFromLinkedPaths, 'ALinked++++++++++++Linked++++++++++++');\n\n    el.unlinkPaths('linked4');\n    el.set('linked4.prop', 'Linked+++++++++++++');\n    assert.equal(el.computeFromLinkedPaths.callCount, 13);\n    assert.equal(el.computedFromLinkedPaths, 'ALinked++++++++++++Linked++++++++++++');\n  });\n\n  test('link two arrays', function() {\n    el.x = el.y = [];\n    el.linkPaths('y', 'x');\n    el.xChanged = sinon.spy();\n    el.yChanged = sinon.spy();\n    el.push('x', {});\n    // 2 changes for arrays (splices & length)\n    assert.equal(el.xChanged.callCount, 2);\n    assert.equal(el.yChanged.callCount, 2);\n    el.unlinkPaths('y');\n    el.push('x', {});\n    assert.equal(el.xChanged.callCount, 4);\n    assert.equal(el.yChanged.callCount, 2);\n  });\n\n  test('link three arrays', function() {\n    el.x = el.y = el.a = [];\n    el.linkPaths('y', 'x');\n    el.linkPaths('a', 'x');\n    el.xChanged = sinon.spy();\n    el.yChanged = sinon.spy();\n    el.aChanged = sinon.spy();\n    el.push('x', {});\n    // 2 changes for arrays (splices & length)\n    assert.equal(el.xChanged.callCount, 2);\n    assert.equal(el.yChanged.callCount, 2);\n    assert.equal(el.aChanged.callCount, 2);\n    el.unlinkPaths('y');\n    el.push('x', {});\n    assert.equal(el.xChanged.callCount, 4);\n    assert.equal(el.yChanged.callCount, 2);\n    assert.equal(el.aChanged.callCount, 4);\n  });\n\n  test('get from path in deep observer', function() {\n    el.arrayChanged = nop;\n    var array = [1, 2, 3];\n    // Initialize array\n    el.arrayChangedDeep = function(info) {\n      assert.strictEqual(el.get(info.path), array);\n    };\n    el.array = array;\n    // Change index 0\n    el.arrayChangedDeep = function(info) {\n      assert.strictEqual(el.get(info.path), 99);\n    };\n    el.set('array.0', 99);\n    // Unshift value\n    el.arrayChangedDeep = function(info) {\n      if (info.path == 'array.splices') {\n        assert.strictEqual(el.get(info.path), array.splices);\n      } else {\n        assert.strictEqual(el.get(info.path), 4);\n      }\n    };\n    el.unshift('array', 0);\n    // Change index 0\n    el.arrayChangedDeep = function(info) {\n      assert.strictEqual(el.get(info.path), -1);\n    };\n    el.set('array.0', -1);\n    // Verify array contents\n    arraysEqual(el.array, [-1, 99, 2, 3]);\n  });\n\n});\n\nsuite('corner cases', function() {\n\n  test('malformed observer has nice message on failure', function() {\n    var thrown = false;\n    var verifyError = function(e) {\n      assert.equal(e.message, \"Malformed observer expression 'foo(missingParenthesis'\");\n      thrown = true;\n    };\n    try {\n      Polymer({\n        is: 'x-broken',\n        observers: ['foo(missingParenthesis']\n      }).finalize();\n    } catch (e) {\n      verifyError(e);\n    }\n\n    assert.equal(thrown, true, \"No exception thrown when parsing malformed observer\");\n  });\n\n  test('reentry during path processing', function() {\n    let host = document.createElement('x-reentry-host');\n    document.body.appendChild(host);\n    assert.equal(host.objChanged.callCount, 1);\n    assert.equal(host.obj.prop, 0);\n    host.set('obj.prop', host.obj.prop+1);\n    assert.equal(host.objChanged.callCount, 2);\n    assert.equal(host.objChanged.secondCall.args[0].path, 'obj.prop');\n    assert.equal(host.objChanged.secondCall.args[0].value, 1);\n  });\n\n  test('reentry after wildcard observer queued', function() {\n    let el = document.createElement('x-reentry-true');\n    document.body.appendChild(el);\n    assert.equal(el.propChanged.callCount, 2);\n    assert.equal(el.propChanged.firstCall.args[0].base, true);\n    assert.equal(el.propChanged.firstCall.args[0].value, true);\n    assert.equal(el.propChanged.secondCall.args[0].base, true);\n    assert.equal(el.propChanged.secondCall.args[0].value, true);\n    document.body.removeChild(el);\n  });\n\n  // TODO(kschaaf): address code in `getArgValue` that looks in changedProps\n  // when `undefined` for splices, which breaks this test (latent issue)\n  // https://github.com/Polymer/polymer/issues/5479\n  test.skip('reentry after prop goes back to undefined', function() {\n    let el = document.createElement('x-reentry-undefined');\n    document.body.appendChild(el);\n    assert.equal(el.propChanged.callCount, 2);\n    assert.equal(el.propChanged.firstCall.args[0].base, undefined);\n    assert.equal(el.propChanged.firstCall.args[0].value, undefined);\n    assert.equal(el.propChanged.secondCall.args[0].base, undefined);\n    assert.equal(el.propChanged.secondCall.args[0].value, undefined);\n    document.body.removeChild(el);\n  });\n\n  // TODO(kschaaf): address code in `getArgValue` that looks in changedProps\n  // when `undefined` for splices, which breaks this test (latent issue)\n  // https://github.com/Polymer/polymer/issues/5479\n  test.skip('reentry after path goes back to undefined', function() {\n    let el = document.createElement('x-reentry-undefined-path');\n    document.body.appendChild(el);\n    assert.equal(el.propChanged.callCount, 2);\n    assert.equal(el.propChanged.firstCall.args[0].base, undefined);\n    assert.equal(el.propChanged.firstCall.args[0].value, undefined);\n    assert.equal(el.propChanged.secondCall.args[0].base, undefined);\n    assert.equal(el.propChanged.secondCall.args[0].value, undefined);\n    document.body.removeChild(el);\n  });\n\n  test('reentry from array splices', function() {\n    let el = document.createElement('x-reentry-splices');\n    document.body.appendChild(el);\n    assert.equal(el.arrayChanged.callCount, 3);\n    assert.deepEqual(el.arrayChanged.getCalls()[0].args[0].value, {\n      indexSplices: [{ \n        index: 1, addedCount: 1, removed: [], object: el.array, type: 'splice'\n      }]\n    });\n    assert.deepEqual(el.arrayChanged.getCalls()[1].args[0].value, {\n      indexSplices: [{ \n        index: 0, addedCount: 1, removed: [], object: el.array, type: 'splice'\n      }]\n    });\n    assert.deepEqual(el.arrayChanged.getCalls()[2].args[0].value, undefined);\n    document.body.removeChild(el);\n  });\n\n  test('element without notify effects still notifies paths (1.x guarantee)', function() {\n    let host = document.createElement('x-path-host');\n    let listener = sinon.spy();\n    host.addEventListener('obj-changed', listener);\n    document.body.appendChild(host);\n    assert.equal(host.objChanged.callCount, 1);\n    assert.equal(host.obj.prop, 0);\n    assert.equal(listener.callCount, 0);\n    host.$.client.set('obj.prop', host.obj.prop+1);\n    assert.equal(host.objChanged.callCount, 2);\n    assert.equal(host.objChanged.secondCall.args[0].path, 'obj.prop');\n    assert.equal(host.objChanged.secondCall.args[0].value, 1);\n    assert.equal(listener.callCount, 1);\n    assert.equal(listener.firstCall.args[0].detail.path, 'obj.prop');\n    assert.equal(listener.firstCall.args[0].detail.value, 1);\n  });\n\n});\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/path.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n</head>\n<body>\n\n<script type=\"module\">\nimport { isAncestor, isDeep, isDescendant, root, matches, translate } from '../../lib/utils/path.js';\nsuite('path utilities', function() {\n\n  test('root()', function() {\n    assert.equal(root('foo'), 'foo');\n    assert.equal(root('foo.bar'), 'foo');\n  });\n\n  test('isDeep()', function() {\n    assert.equal(isDeep('foo'), false);\n    assert.equal(isDeep('foo.bar'), true);\n  });\n\n  test('isAncestor()', function() {\n    assert.equal(isAncestor('foo.bar', 'foo'),          true);\n\n    assert.equal(isAncestor('foo.bar', 'foo.bar'),      false);\n    assert.equal(isAncestor('foo.bar', 'foo.baz'),      false);\n    assert.equal(isAncestor('foo.bar', 'fooz'),         false);\n    assert.equal(isAncestor('foo.bar', 'bar'),          false);\n    assert.equal(isAncestor('foo.bar', 'foo.bars'),     false);\n    assert.equal(isAncestor('foo.bar', 'foo.bar.quux'), false);\n\n\n    assert.equal(isAncestor('foo.bar.baz', 'foo'),      true);\n    assert.equal(isAncestor('foo.bar.baz', 'foo.bar'),  true);\n\n    assert.equal(isAncestor('foo.bar.baz', 'foo.baz'),  false);\n    assert.equal(isAncestor('foo.bar.baz', 'foo.bars'), false);\n  });\n\n  test('isDescendant()', function() {\n    assert.equal(isDescendant('foo.bar', 'foo.bar.baz'),  true);\n    assert.equal(isDescendant('foo.bar', 'foo.bar'),      false);\n    assert.equal(isDescendant('foo.bar', 'foo.bars'),     false);\n    assert.equal(isDescendant('foo.bar', 'foo'),          false);\n    assert.equal(isDescendant('foo.bar', 'bar'),          false);\n\n    assert.equal(isDescendant('foo', 'foo.bar'), true);\n    assert.equal(isDescendant('foo', 'foo'),     false);\n  });\n\n  test('translate()', function() {\n    assert.equal(translate('foo', 'baz', 'foo.bar'),\n                 'baz.bar');\n    assert.equal(translate('foo', 'quux', 'foo.bar.baz'),\n                 'quux.bar.baz');\n    assert.equal(translate('foo.bar', 'quux', 'foo.bar.baz'),\n                 'quux.baz');\n  });\n\n  test('matches()', function() {\n    assert.equal(matches('foo.bar','foo'),          true);\n    assert.equal(matches('foo.bar','foo.bar'),      true);\n    assert.equal(matches('foo.bar','foo.bar.baz'),  true);\n    assert.equal(matches('foo.bar','fooz'),         false);\n    assert.equal(matches('foo.bar','foo.baz'),      false);\n    assert.equal(matches('foo.bar','foo.bars'),     false);\n  });\n});\n</script>\n"
  },
  {
    "path": "test/unit/polymer-dom-nopatch.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script>\n    ShadyDOM = {force: true, noPatch: true};\n  </script>\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n</head>\n<body>\n\n  <dom-module id=\"x-slot\">\n    <template>\n      <div id=\"container\"><slot id=\"slot\"></slot></div>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-slot'\n});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-container-slot\">\n    <template>\n      <x-slot id=\"container\"><div id=\"first\">first</div><slot id=\"slot\"></slot><div id=\"last\">last</div></x-slot>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-container-slot'\n});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-event-scoped\">\n    <template>\n      <div id=\"container\">\n        <div id=\"scoped\"></div>\n      </div>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-event-scoped',\n  fireComposed: function() {\n    return this.fire('composed', null, {node: this.$.scoped});\n  }\n});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-focusable-in-shadow\">\n    <template>\n      <input id=\"focusable\"></input>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-focusable-in-shadow'\n});\n</script>\n  </dom-module>\n\n<dom-module id=\"x-class-bindings\">\n<template>\n  <style>\n    .a {\n      border: 2px solid orange;\n    }\n\n    .aa {\n      border: 12px solid red;\n    }\n\n    .b {\n      padding: 4px;\n    }\n  </style>\n  <div>\n    <div id=\"class\" class$=\"[[clazz]] b\">class</div>\n    <div id=\"className\" class-name=\"[[clazz]] b\">class</div>\n  </div>\n</template>\n<script type=\"module\">\n  import { Polymer } from '../../polymer-legacy.js';\n  Polymer({\n    properties: {\n      clazz: {type: String}\n    },\n    is: 'x-class-bindings'\n  });\n</script>\n</dom-module>\n\n   <test-fixture id=\"scoped\">\n    <template>\n      <x-event-scoped></x-event-scoped>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"slot\">\n    <template>\n      <x-container-slot></x-container-slot>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"focusableInShadow\">\n    <template>\n      <x-focusable-in-shadow></x-focusable-in-shadow>\n    </template>\n  </test-fixture>\n\n<script type=\"module\">\nimport { dom } from '../../lib/legacy/polymer.dom.js';\nimport { useShadow, useNativeCustomElements, useNativeCSSProperties } from '../../lib/utils/settings.js';\n\nsuite('extended dom api', function() {\n  test('getEffectiveChildNodes', function() {\n    var el = fixture('slot');\n    var div = document.createElement('div');\n    dom(el).appendChild(div);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.deepEqual(dom(el).getEffectiveChildNodes(),\n      [div]);\n    assert.deepEqual(dom(el.$.container).getEffectiveChildNodes(),\n      [el.$.first, div, el.$.last]);\n    assert.deepEqual(dom(el.$.container.$.container).getEffectiveChildNodes(),\n      [el.$.first, div, el.$.last]);\n  });\n\n  test('queryDistributedElements', function() {\n    var el = fixture('slot');\n    var div = document.createElement('div');\n    dom(el).appendChild(div);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.deepEqual(dom(el).queryDistributedElements('foo'),\n      []);\n    assert.deepEqual(dom(el).queryDistributedElements('div'),\n      [div]);\n    assert.deepEqual(dom(el.$.container).queryDistributedElements('#first'),\n      [el.$.first]);\n    assert.deepEqual(dom(el.$.container.$.container).queryDistributedElements('#last'),\n      [el.$.last]);\n  });\n\n});\n\nsuite('distribution', function() {\n  test('getDistributedNodes', function() {\n    var el = fixture('slot');\n    var div = document.createElement('div');\n    dom(el).appendChild(div);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.deepEqual(dom(el.$.slot).getDistributedNodes(), [div]);\n    assert.deepEqual(dom(el.$.container.$.slot).getDistributedNodes(),\n      [el.$.first, div, el.$.last]);\n  });\n\n  test('getDestinationInsertionPoints', function() {\n    var el = fixture('slot');\n    var div = document.createElement('div');\n    dom(el).appendChild(div);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.deepEqual(dom(el.$.first).getDestinationInsertionPoints(),\n      [el.$.container.$.slot]);\n    assert.deepEqual(dom(div).getDestinationInsertionPoints(),\n      [el.$.slot, el.$.container.$.slot]);\n  });\n});\n\nsuite('events', function() {\n\n  test('localTarget, rootTarget, path', function() {\n    // skip if noPatch is not available\n    if (!window.ShadyDOM.wrap) {\n      this.skip();\n    }\n    var el = fixture('scoped');\n    el.addEventListener('composed', function(e) {\n      assert.equal(dom(e).rootTarget, el.$.scoped);\n      assert.equal(dom(e).localTarget, el);\n      let nodes = [];\n      let p = el.$.scoped;\n      while (p) {\n        nodes.push(p);\n        p = dom(p).parentNode || ShadyDOM.wrap(p).host;\n      }\n      nodes.push(window);\n      const path = dom(e).path;\n      assert.deepEqual(path, nodes);\n    });\n    ShadyDOM.flush();\n    el.fireComposed();\n  });\n\n  test('localTarget when target node and event listener node are distinct', function() {\n    // skip if noPatch is not available\n    if (!window.ShadyDOM.wrap) {\n      this.skip();\n    }\n    var el = fixture('scoped');\n    el.$.container.addEventListener('composed', function(e) {\n      assert.equal(dom(e).rootTarget, el.$.scoped);\n      assert.equal(dom(e).localTarget, el.$.scoped);\n    });\n    ShadyDOM.flush();\n    el.fireComposed();\n  });\n\n});\n\nsuite('activeElement getter', function() {\n  test('Retrieves `activeElement`', function() {\n    // skip if noPatch is not available\n    if (!window.ShadyDOM.wrap) {\n      this.skip();\n    }\n    var focusableInShadow = fixture('focusableInShadow');\n    ShadyDOM.wrap(focusableInShadow.$.focusable).focus();\n    var rootNode = ShadyDOM.wrap(focusableInShadow).getRootNode();\n    assert.equal(dom(rootNode).activeElement, focusableInShadow);\n    assert.equal(dom(dom(focusableInShadow).shadowRoot).activeElement, focusableInShadow.$.focusable);\n  });\n});\n\nsuite('legacy api', function() {\n  test('getEffectiveChildNodes', function() {\n    var el = fixture('slot');\n    var div = document.createElement('div');\n    var t = document.createTextNode('yo');\n    dom(el).appendChild(div);\n    dom(el).appendChild(t);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.deepEqual(el.getEffectiveChildNodes(),\n      [div, t]);\n    assert.deepEqual(el.$.container.getEffectiveChildNodes(),\n      [el.$.first, div, t, el.$.last]);\n  });\n\n  test('getEffectiveChildren', function() {\n    var el = fixture('slot');\n    var div = document.createElement('div');\n    dom(el).appendChild(div);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.deepEqual(el.getEffectiveChildNodes(),\n      [div]);\n    assert.deepEqual(el.$.container.getEffectiveChildNodes(),\n      [el.$.first, div, el.$.last]);\n  });\n\n  test('getEffectiveTextContent', function() {\n    var el = fixture('slot');\n    var t1 = document.createTextNode('a');\n    var t2 = document.createTextNode('b');\n    dom(el).appendChild(t1);\n    dom(el).appendChild(t2);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.deepEqual(el.getEffectiveTextContent(), 'ab');\n    assert.deepEqual(el.$.container.getEffectiveTextContent(), 'firstablast');\n  });\n\n  test('getContentChildNodes', function() {\n    var el = fixture('slot');\n    var div1 = document.createElement('div');\n    var t = document.createTextNode('');\n    var div2 = document.createElement('div');\n    dom(el).appendChild(div1);\n    dom(el).appendChild(t);\n    dom(el).appendChild(div2);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.deepEqual(el.getContentChildNodes(),\n      [div1, t, div2]);\n    assert.deepEqual(el.getContentChildNodes('slot'),\n      [div1, t, div2]);\n  });\n\n  test('getContentChildren', function() {\n    var el = fixture('slot');\n    var div1 = document.createElement('div');\n    var t = document.createTextNode('');\n    var div2 = document.createElement('div');\n    dom(el).appendChild(div1);\n    dom(el).appendChild(t);\n    dom(el).appendChild(div2);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.deepEqual(el.getContentChildren(),\n      [div1, div2]);\n    assert.deepEqual(el.getContentChildren('slot'),\n      [div1, div2]);\n  });\n\n  test('queryDistributedElements', function() {\n    var el = fixture('slot');\n    var div = document.createElement('div');\n    dom(el).appendChild(div);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.deepEqual(el.queryDistributedElements('foo'),\n      []);\n    assert.deepEqual(el.queryDistributedElements('div'),\n      [div]);\n    assert.deepEqual(el.$.container.queryDistributedElements('#first'),\n      [el.$.first]);\n  });\n\n  test('queryEffectiveChildren', function() {\n    var el = fixture('slot');\n    var div = document.createElement('div');\n    dom(el).appendChild(div);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.equal(el.queryEffectiveChildren('foo'),\n      null);\n    assert.deepEqual(el.queryEffectiveChildren('div'),\n      div);\n    assert.deepEqual(el.$.container.queryEffectiveChildren('#first'),\n      el.$.first);\n  });\n\n  test('queryAllEffectiveChildren', function() {\n    var el = fixture('slot');\n    var div1 = document.createElement('div');\n    var div2 = document.createElement('div');\n    dom(el).appendChild(div1);\n    dom(el).appendChild(div2);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.deepEqual(el.queryAllEffectiveChildren('foo'),\n      []);\n    assert.deepEqual(el.queryAllEffectiveChildren('div'),\n      [div1, div2]);\n    assert.deepEqual(el.$.container.queryAllEffectiveChildren('div'),\n      [el.$.first, div1, div2, el.$.last]);\n  });\n\n  test('isLightDescendant', function() {\n    var el = fixture('slot');\n    var div1 = document.createElement('div');\n    dom(el).appendChild(div1);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.equal(el.isLightDescendant(div1), true);\n    assert.equal(el.isLightDescendant(el.$.container), false);\n  });\n\n  test('isLocalDescendant', function() {\n    var el = fixture('slot');\n    var div1 = document.createElement('div');\n    dom(el).appendChild(div1);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.equal(el.isLocalDescendant(div1), false);\n    assert.equal(el.isLocalDescendant(el.$.container), true);\n  });\n\n  test('domHost', function() {\n    var el = fixture('slot');\n    assert.equal(el.domHost, document);\n    assert.equal(el.$.container.domHost, el);\n  });\n\n  test('legacy settings', function() {\n    assert.equal(useShadow, !(window.ShadyDOM));\n    assert.equal(useNativeCustomElements, !(window.customElements.polyfillWrapFlushCallback));\n    assert.equal(useNativeCSSProperties, Boolean(!window.ShadyCSS || window.ShadyCSS.nativeCss));\n  });\n\n});\n\nsuite('forwarded native api', function() {\n\n  let el;\n\n  setup(function() {\n    el = document.createElement('x-container-slot');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('accessors are available', function() {\n    const d = dom(el);\n    assert.isDefined(d.parentNode);\n    assert.isDefined(d.firstChild);\n    assert.isDefined(d.lastChild);\n    assert.isDefined(d.nextSibling);\n    assert.isDefined(d.previousSibling);\n    assert.isDefined(d.firstElementChild);\n    assert.isDefined(d.lastElementChild);\n    assert.isDefined(d.nextElementSibling);\n    assert.isDefined(d.previousElementSibling);\n    assert.isDefined(d.childNodes);\n    assert.isDefined(d.children);\n    assert.isDefined(d.classList);\n    assert.isDefined(d.textContent);\n    assert.isDefined(d.innerHTML);\n  });\n\n  test('cloneNode', function() {\n    const clone = dom(el).cloneNode(el);\n    assert.ok(clone);\n    assert.equal(clone.localName, 'x-container-slot');\n  });\n\n  test('appendChild', function() {\n    const d1 = document.createElement('div');\n    dom(el).appendChild(d1);\n    assert.equal(dom(el).firstChild, d1);\n    assert.equal(dom(d1).parentNode, el);\n  });\n\n  test('insertBefore', function() {\n    const d1 = document.createElement('div');\n    const d2 = document.createElement('div');\n    dom(el).appendChild(d1);\n    dom(el).insertBefore(d2, d1);\n    assert.equal(dom(d2).nextSibling, d1);\n  });\n\n  test('removeChild', function() {\n    const d1 = document.createElement('div');\n    dom(el).appendChild(d1);\n    dom(el).removeChild(d1);\n    assert.equal(dom(d1).parentNode, null);\n  });\n\n  test('replaceChild', function() {\n    const d1 = document.createElement('div');\n    const d2 = document.createElement('div');\n    dom(el).appendChild(d1);\n    dom(el).replaceChild(d2, d1);\n    assert.equal(dom(d1).parentNode, null);\n    assert.equal(dom(el).firstChild, d2);\n    assert.equal(dom(d2).parentNode, el);\n  });\n\n  test('replaceChild', function() {\n    dom(el).setAttribute('foo', 'foo');\n    assert.equal(el.getAttribute('foo'), 'foo');\n  });\n\n  test('replaceChild', function() {\n    dom(el).setAttribute('foo', 'foo');\n    dom(el).removeAttribute('foo');\n    assert.isFalse(el.hasAttribute('foo'));\n  });\n\n  test('querySelector', function() {\n    const d1 = document.createElement('div');\n    dom(el).appendChild(d1);\n    const query = dom(el).querySelector('div');\n    assert.equal(query, d1);\n  });\n\n  test('querySelectorAll', function() {\n    const d1 = document.createElement('div');\n    const d2 = document.createElement('div');\n    dom(el).appendChild(d1);\n    dom(el).appendChild(d2);\n    const query = dom(el).querySelectorAll('div');\n    assert.equal(query[0], d1);\n    assert.equal(query[1], d2);\n    assert.equal(query.length, 2);\n  });\n\n  test('tree accessors', function() {\n    const d1 = document.createElement('div');\n    const d2 = document.createElement('div');\n    dom(el).appendChild(d1);\n    dom(el).appendChild(d2);\n    const pel = dom(el);\n    const pd1 = dom(d1);\n    const pd2 = dom(d2);\n    assert.equal(pd1.parentNode, el);\n    assert.equal(pel.firstChild, d1);\n    assert.equal(pel.lastChild, d2);\n    assert.equal(pel.firstElementChild, d1);\n    assert.equal(pel.lastElementChild, d2);\n    assert.equal(pd1.nextSibling, d2);\n    assert.equal(pd2.previousSibling, d1);\n    assert.equal(pd1.nextElementSibling, d2);\n    assert.equal(pd2.previousElementSibling, d1);\n    assert.equal(pel.childNodes[0], d1);\n    assert.equal(pel.childNodes[1], d2);\n    assert.equal(pel.children[0], d1);\n    assert.equal(pel.children[1], d2);\n  });\n\n  test('innerHTML', function() {\n    dom(el).innerHTML = '<div></div>';\n    assert.equal(dom(el).firstChild.localName, 'div');\n  });\n\n  test('textContent', function() {\n    dom(el).innerHTML = 'hi';\n    assert.equal(dom(dom(el).firstChild).textContent, 'hi');\n  });\n\n  test('classList', function() {\n    dom(el).classList.add('foo');\n    assert.equal(el.className, 'foo');\n  });\n\n  test('className', function() {\n    dom(el).className = 'foo';\n    assert.isTrue(el.classList.contains('foo'));\n  });\n\n  test('class bindings work and remained scoped', function() {\n    const el = document.createElement('x-class-bindings');\n    document.body.appendChild(el);\n    assert.equal(getComputedStyle(el.$.class)['border-top-width'], '0px');\n    assert.equal(getComputedStyle(el.$.class)['padding-top'], '4px');\n    assert.isTrue(el.$.class.classList.contains('style-scope'));\n    assert.equal(getComputedStyle(el.$.className)['border-top-width'], '0px');\n    assert.equal(getComputedStyle(el.$.className)['padding-top'], '4px');\n    assert.isTrue(el.$.className.classList.contains('style-scope'));\n    el.clazz = 'a';\n    assert.equal(getComputedStyle(el.$.class)['border-top-width'], '2px');\n    assert.equal(getComputedStyle(el.$.class)['padding-top'], '4px');\n    assert.isTrue(el.$.class.classList.contains('style-scope'));\n    assert.equal(getComputedStyle(el.$.className)['border-top-width'], '2px');\n    assert.equal(getComputedStyle(el.$.className)['padding-top'], '4px');\n    assert.isTrue(el.$.className.classList.contains('style-scope'));\n    el.clazz = 'aa';\n    assert.equal(getComputedStyle(el.$.class)['border-top-width'], '12px');\n    assert.equal(getComputedStyle(el.$.class)['padding-top'], '4px');\n    assert.isTrue(el.$.class.classList.contains('style-scope'));\n    assert.equal(getComputedStyle(el.$.className)['border-top-width'], '12px');\n    assert.equal(getComputedStyle(el.$.className)['padding-top'], '4px');\n    assert.isTrue(el.$.className.classList.contains('style-scope'));\n    document.body.removeChild(el);\n  });\n\n});\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/polymer-dom-observeNodes.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n</head>\n<body>\n\n  <dom-module id='test-self-observe'>\n    <template>\n      <slot id=\"slot\"></slot>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nimport { dom } from '../../lib/legacy/polymer.dom.js';\nPolymer({\n  is:'test-self-observe',\n  attached: function() {\n    this._observer = dom(this).observeNodes(function(info) {\n      this.info = info;\n    });\n  },\n  detached: function() {\n    dom(this).unobserveNodes(this._observer);\n  }\n});\n</script>\n  </dom-module>\n\n  <dom-module id='test-static'>\n    <template>\n      <div>static</div>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is:'test-static'\n});\n</script>\n  </dom-module>\n\n  <dom-module id='test-slot'>\n    <template>\n      <span id=\"slotContainer\">[<slot id=\"slot\"></slot>]</span>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is:'test-slot'\n});\n</script>\n  </dom-module>\n\n  <dom-module id='test-slot1'>\n    <template>\n      <test-slot id=\"slot\"><slot></slot></test-slot>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is:'test-slot1'\n});\n</script>\n  </dom-module>\n\n  <dom-module id='test-slot2'>\n    <template>\n      <test-slot1 id=\"slot\"><slot></slot></test-slot1>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is:'test-slot2'\n});\n</script>\n  </dom-module>\n\n  <dom-module id='test-slot3'>\n    <template>\n      <test-slot2 id=\"slot\"><slot></slot></test-slot2>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is:'test-slot3'\n});\n</script>\n  </dom-module>\n\n  <dom-module id='test-slot-raw'>\n    <template>\n      <div id=\"slot\"><slot></slot></div>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is:'test-slot-raw'\n});\n</script>\n  </dom-module>\n\n  <dom-module id='test-slot-attr'>\n    <template>\n      [<slot id=\"slot\" name=\"d\"></slot>]\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is:'test-slot-attr'\n});\n</script>\n  </dom-module>\n\n  <dom-module id='test-slot-attr1'>\n    <template>\n      <test-slot-attr id=\"slot\"><slot name=\"c\" slot=\"d\"></slot></test-slot-attr>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is:'test-slot-attr1'\n});\n</script>\n  </dom-module>\n\n  <dom-module id='test-slot-attr2'>\n    <template>\n      <test-slot-attr1 id=\"slot\"><slot name=\"b\" slot=\"c\"></slot></test-slot-attr1>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is:'test-slot-attr2'\n});\n</script>\n  </dom-module>\n\n  <dom-module id='test-slot-attr3'>\n    <template>\n      <test-slot-attr2 id=\"slot\"><slot name=\"a\" slot=\"b\"></slot></test-slot-attr2>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is:'test-slot-attr3'\n});\n</script>\n  </dom-module>\n\n  <dom-module id='test-slot-attr-inside'>\n    <template>\n      <test-slot-attr3 id=\"slot\"><slot name=\"a\" slot=\"a\"></slot></test-slot-attr3>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is:'test-slot-attr-inside'\n});\n</script>\n  </dom-module>\n\n\n  <test-slot><div>A</div><div>B</div></test-slot>\n\n  <test-static><div>static A</div><div>static B</div></test-static>\n\n  <div id=\"staticDiv\"></div>\n\n<script type=\"module\">\nimport { dom } from '../../lib/legacy/polymer.dom.js';\n\nsuite('observeNodes', function() {\n\n  test('observe initial state of distributing element', function() {\n    var recordedA;\n    var el = document.querySelector('test-slot');\n    var observer1 = dom(el).observeNodes(function(info) {\n      recordedA = info;\n    });\n    observer1.flush();\n    assert.equal(recordedA.addedNodes.length, 2);\n    recordedA = null;\n    var recordedB;\n    var observer2 = dom(el).observeNodes(function(info) {\n      recordedB = info;\n    });\n    observer2.flush();\n    assert.equal(recordedA, null);\n    assert.equal(recordedB.addedNodes.length, 2);\n    dom(el).unobserveNodes(observer1);\n    dom(el).unobserveNodes(observer2);\n  });\n\n  test('observe initial state of non-distributing element', function() {\n    var recordedA;\n    var el = document.querySelector('test-static');\n    var observer1 = dom(el).observeNodes(function(info) {\n      recordedA = info;\n    });\n    observer1.flush();\n    assert.equal(recordedA.addedNodes.length, 2);\n    recordedA = null;\n    var recordedB;\n    var observer2 = dom(el).observeNodes(function(info) {\n      recordedB = info;\n    });\n    observer2.flush();\n    assert.equal(recordedA, null);\n    assert.equal(recordedB.addedNodes.length, 2);\n    dom(el).unobserveNodes(observer1);\n    dom(el).unobserveNodes(observer2);\n  });\n\n  test('observeNodes called in observed node context', function(done) {\n    var el = document.createElement('test-slot');\n    document.body.appendChild(el);\n    var observer = dom(el).observeNodes(function() {\n      assert.equal(this, el);\n      done();\n    });\n    // add\n    var d = document.createElement('div');\n    dom(el).appendChild(d);\n    observer.flush();\n  });\n\n  test('observe children changes to distributing element', function() {\n    var el = document.createElement('test-slot');\n    document.body.appendChild(el);\n\n    var recorded;\n    var observer = dom(el).observeNodes(function(info) {\n      recorded = info;\n    });\n    // add\n    var d = document.createElement('div');\n    var d1 = document.createElement('div');\n    dom(el).appendChild(d);\n    dom(el).appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 2);\n    assert.equal(recorded.removedNodes.length, 0);\n    assert.equal(recorded.addedNodes[0], d);\n    assert.equal(recorded.addedNodes[1], d1);\n    // remove\n    dom(el).removeChild(d);\n    dom(el).removeChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 0);\n    assert.equal(recorded.removedNodes.length, 2);\n    assert.equal(recorded.removedNodes[0], d);\n    assert.equal(recorded.removedNodes[1], d1);\n    // add\n    dom(el).appendChild(d);\n    dom(el).appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 2);\n    assert.equal(recorded.addedNodes[0], d);\n    assert.equal(recorded.addedNodes[1], d1);\n    // reset, unobserve and remove\n    recorded = null;\n    dom(el).unobserveNodes(observer);\n    dom(el).removeChild(d);\n    dom(el).removeChild(d1);\n    observer.flush();\n    assert.equal(recorded, null);\n    document.body.removeChild(el);\n  });\n\n  test('observe children changes to distributing element that provoke additional changes', function() {\n    var el = document.createElement('test-slot');\n    document.body.appendChild(el);\n\n    var recordedInfo, elAddedInObserver;\n    var observerCallCount = 0;\n    var observer = dom(el).observeNodes(function(info) {\n      observerCallCount++;\n      recordedInfo = info;\n      if (dom(info.target).childNodes.length < 5) {\n        elAddedInObserver = document.createElement('div');\n        dom(info.target).appendChild(elAddedInObserver);\n      }\n\n    });\n    // add\n    var d = document.createElement('div');\n    dom(el).appendChild(d);\n    while (observer.flush()) {\n      // re-flush until done\n    }\n    assert.equal(observerCallCount, 5);\n    assert.equal(recordedInfo.addedNodes.length, 1);\n    assert.equal(recordedInfo.addedNodes[0], elAddedInObserver);\n    assert.equal(dom(el).childNodes.length, 5);\n    document.body.removeChild(el);\n    dom(el).unobserveNodes(observer);\n  });\n\n  test('observe children changes to distributing element (async)', function(done) {\n    var el = document.createElement('test-slot');\n    document.body.appendChild(el);\n\n    var nodes = [];\n    var handle = dom(el).observeNodes(function(info) {\n      for (var i=0, at; i < info.removedNodes.length; i++) {\n        at = nodes.indexOf(info.removedNodes[i]);\n        assert.isAbove(at, -1);\n        nodes.splice(at, 1);\n      }\n      nodes = nodes.concat(info.addedNodes);\n    });\n    // add\n    var d = document.createElement('div');\n    var d1 = document.createElement('div');\n    dom(el).appendChild(d);\n    dom(el).appendChild(d1);\n    setTimeout(function() {\n      assert.sameMembers(el.getEffectiveChildNodes(), nodes);\n      // remove\n      dom(el).removeChild(d);\n      dom(el).removeChild(d1);\n      setTimeout(function() {\n        assert.sameMembers(el.getEffectiveChildNodes(), nodes);\n        // add\n        dom(el).appendChild(d);\n        dom(el).appendChild(d1);\n        setTimeout(function() {\n          assert.sameMembers(el.getEffectiveChildNodes(), nodes);\n          dom(el).unobserveNodes(handle);\n          dom(el).removeChild(d);\n          dom(el).removeChild(d1);\n          setTimeout(function() {\n            assert.notEqual(nodes.length, el.getEffectiveChildNodes().length);\n            document.body.removeChild(el);\n            done();\n          });\n        });\n      });\n    });\n  });\n\n  test('observe children changes to non-distributing element', function() {\n    var el = document.createElement('test-static');\n    document.body.appendChild(el);\n\n    var recorded;\n    var observer = dom(el).observeNodes(function(info) {\n      recorded = info;\n    });\n    // add\n    var d = document.createElement('div');\n    var d1 = document.createElement('div');\n    dom(el).appendChild(d);\n    dom(el).appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 2);\n    assert.equal(recorded.removedNodes.length, 0);\n    assert.equal(recorded.addedNodes[0], d);\n    assert.equal(recorded.addedNodes[1], d1);\n    // remove\n    dom(el).removeChild(d);\n    dom(el).removeChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 0);\n    assert.equal(recorded.removedNodes.length, 2);\n    assert.equal(recorded.removedNodes[0], d);\n    assert.equal(recorded.removedNodes[1], d1);\n    // add\n    dom(el).appendChild(d);\n    dom(el).appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 2);\n    assert.equal(recorded.addedNodes[0], d);\n    assert.equal(recorded.addedNodes[1], d1);\n    // reset, unobserve and remove\n    recorded = null;\n    dom(el).unobserveNodes(observer);\n    dom(el).removeChild(d);\n    dom(el).removeChild(d1);\n    observer.flush();\n    assert.equal(recorded, null);\n    document.body.removeChild(el);\n  });\n\n  test('observe changes to inner node wrapping <slot>', function() {\n    var el = document.createElement('test-slot');\n    document.body.appendChild(el);\n\n    var observedInfo;\n    var observer = dom(el.$.slotContainer).observeNodes(function(info) {\n      observedInfo = info;\n    });\n    observer.flush();\n    // add\n    var d = document.createElement('div');\n    var d1 = document.createElement('div');\n    dom(el).appendChild(d);\n    dom(el).appendChild(d1);\n    observer.flush();\n    assert.equal(observedInfo.target, el.$.slotContainer);\n    assert.equal(observedInfo.addedNodes.length, 2);\n    assert.equal(observedInfo.removedNodes.length, 0);\n    // remove\n    dom(el).removeChild(d);\n    dom(el).removeChild(d1);\n    observer.flush();\n    assert.equal(observedInfo.addedNodes.length, 0);\n    assert.equal(observedInfo.removedNodes.length, 2);\n    // add\n    dom(el).appendChild(d);\n    dom(el).appendChild(d1);\n    observer.flush();\n    assert.equal(observedInfo.addedNodes.length, 2);\n    assert.equal(observedInfo.removedNodes.length, 0);\n    // reset, unobserve and remove\n    observedInfo = null;\n    dom(el.$.slotContainer).unobserveNodes(observer);\n    dom(el).removeChild(d);\n    dom(el).removeChild(d1);\n    observer.flush();\n    assert.equal(observedInfo, null);\n    document.body.removeChild(el);\n  });\n\n  test('observe changes to <slot>', function() {\n    var el = document.createElement('test-slot');\n    document.body.appendChild(el);\n\n    var observedInfo;\n    var observer = dom(el.$.slot).observeNodes(function(info) {\n      observedInfo = info;\n    });\n    observer.flush();\n    // add\n    var d = document.createElement('div');\n    var d1 = document.createElement('div');\n    dom(el).appendChild(d);\n    dom(el).appendChild(d1);\n    observer.flush();\n    assert.equal(observedInfo.target, el.$.slot);\n    assert.equal(observedInfo.addedNodes.length, 2);\n    assert.equal(observedInfo.removedNodes.length, 0);\n    // remove\n    dom(el).removeChild(d);\n    dom(el).removeChild(d1);\n    observer.flush();\n    assert.equal(observedInfo.addedNodes.length, 0);\n    assert.equal(observedInfo.removedNodes.length, 2);\n    // add\n    dom(el).appendChild(d);\n    dom(el).appendChild(d1);\n    observer.flush();\n    assert.equal(observedInfo.addedNodes.length, 2);\n    assert.equal(observedInfo.removedNodes.length, 0);\n    // reset, unobserve and remove\n    observedInfo = null;\n    dom(el.$.slot).unobserveNodes(observer);\n    dom(el).removeChild(d);\n    dom(el).removeChild(d1);\n    observer.flush();\n    assert.equal(observedInfo, null);\n    document.body.removeChild(el);\n  });\n\n  test('observe effective children inside distributing element', function() {\n    var el = document.createElement('test-slot1');\n    document.body.appendChild(el);\n\n    var recorded;\n    var observer = dom(el.$.slot).observeNodes(function(info) {\n      recorded = info;\n    });\n    observer.flush();\n    // add\n    var d = document.createElement('div');\n    var d1 = document.createElement('div');\n    dom(el).appendChild(d);\n    dom(el).appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 2);\n    assert.equal(recorded.removedNodes.length, 0);\n    assert.equal(recorded.addedNodes[0], d);\n    assert.equal(recorded.addedNodes[1], d1);\n    // remove\n    dom(el).removeChild(d);\n    dom(el).removeChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 0);\n    assert.equal(recorded.removedNodes.length, 2);\n    assert.equal(recorded.removedNodes[0], d);\n    assert.equal(recorded.removedNodes[1], d1);\n    // add\n    dom(el).appendChild(d);\n    dom(el).appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 2);\n    assert.equal(recorded.addedNodes[0], d);\n    assert.equal(recorded.addedNodes[1], d1);\n    // reset, unobserve and remove\n    recorded = null;\n    dom(el.$.slot).unobserveNodes(observer);\n    dom(el).removeChild(d);\n    dom(el).removeChild(d1);\n    observer.flush();\n    assert.equal(recorded, null);\n    document.body.removeChild(el);\n  });\n\n  test('observe effective children changes when adding to another host', function() {\n    var el = document.createElement('test-slot1');\n    document.body.appendChild(el);\n\n    var recorded;\n    var observer = dom(el.$.slot).observeNodes(function(info) {\n      recorded = info;\n    });\n    observer.flush();\n    // add\n    var d = document.createElement('div');\n    var d1 = document.createElement('div');\n    dom(el).appendChild(d);\n    dom(el).appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 2);\n    assert.equal(recorded.removedNodes.length, 0);\n    assert.equal(recorded.addedNodes[0], d);\n    assert.equal(recorded.addedNodes[1], d1);\n    // add somewhere else... we should see these as removes\n    dom(document.body).appendChild(d);\n    dom(document.body).appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 0);\n    assert.equal(recorded.removedNodes.length, 2);\n    assert.equal(recorded.removedNodes[0], d);\n    assert.equal(recorded.removedNodes[1], d1);\n    // cleanup\n    dom(document.body).removeChild(d);\n    dom(document.body).removeChild(d1);\n    document.body.removeChild(el);\n    dom(el.$.slot).unobserveNodes(observer);\n  });\n\n  test('observe effective children changes in static slot when adding to another host', function() {\n    var el = document.createElement('staticDiv');\n    document.body.appendChild(el);\n\n    var recorded;\n    var observer = dom(el).observeNodes(function(info) {\n      recorded = info;\n    });\n    observer.flush();\n    // add\n    var d = document.createElement('div');\n    var d1 = document.createElement('div');\n    dom(el).appendChild(d);\n    dom(el).appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 2);\n    assert.equal(recorded.removedNodes.length, 0);\n    assert.equal(recorded.addedNodes[0], d);\n    assert.equal(recorded.addedNodes[1], d1);\n    // add somewhere else... we should see these as removes\n    dom(document.body).appendChild(d);\n    dom(document.body).appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 0);\n    assert.equal(recorded.removedNodes.length, 2);\n    assert.equal(recorded.removedNodes[0], d);\n    assert.equal(recorded.removedNodes[1], d1);\n    // cleanup\n    dom(document.body).removeChild(d);\n    dom(document.body).removeChild(d1);\n    document.body.removeChild(el);\n    dom(el).unobserveNodes(observer);\n  });\n\n  test('observe effective children inside deep distributing element', function() {\n    var el = document.createElement('test-slot3');\n    document.body.appendChild(el);\n\n    var recorded;\n    var slot = el.$.slot.$.slot.$.slot;\n    var observer = dom(slot).observeNodes(function(info) {\n      recorded = info;\n    });\n    // add\n    var d = document.createElement('div');\n    var d1 = document.createElement('div');\n    dom(el).appendChild(d);\n    dom(el).appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 2);\n    assert.equal(recorded.removedNodes.length, 0);\n    assert.equal(recorded.addedNodes[0], d);\n    assert.equal(recorded.addedNodes[1], d1);\n    // remove\n    dom(el).removeChild(d);\n    dom(el).removeChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 0);\n    assert.equal(recorded.removedNodes.length, 2);\n    assert.equal(recorded.removedNodes[0], d);\n    assert.equal(recorded.removedNodes[1], d1);\n    // add\n    dom(el).appendChild(d);\n    dom(el).appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 2);\n    assert.equal(recorded.addedNodes[0], d);\n    assert.equal(recorded.addedNodes[1], d1);\n    // reset, unobserve and remove\n    recorded = null;\n    dom(slot).unobserveNodes(observer);\n    dom(el).removeChild(d);\n    dom(el).removeChild(d1);\n    observer.flush();\n    assert.equal(recorded, null);\n    document.body.removeChild(el);\n  });\n\n  test('observe <slot> inside deep distributing element', function() {\n    var el = document.createElement('test-slot3');\n    document.body.appendChild(el);\n\n    var recorded;\n    var slot = el.$.slot.$.slot.$.slot.$.slot;\n    assert.equal(slot.localName, 'slot');\n    var observer = dom(slot).observeNodes(function(info) {\n      recorded = info;\n    });\n    // add\n    var d = document.createElement('div');\n    var d1 = document.createElement('div');\n    dom(el).appendChild(d);\n    dom(el).appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 2);\n    assert.equal(recorded.removedNodes.length, 0);\n    assert.equal(recorded.addedNodes[0], d);\n    assert.equal(recorded.addedNodes[1], d1);\n    // remove\n    dom(el).removeChild(d);\n    dom(el).removeChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 0);\n    assert.equal(recorded.removedNodes.length, 2);\n    assert.equal(recorded.removedNodes[0], d);\n    assert.equal(recorded.removedNodes[1], d1);\n    // add\n    dom(el).appendChild(d);\n    dom(el).appendChild(d1);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 2);\n    assert.equal(recorded.addedNodes[0], d);\n    assert.equal(recorded.addedNodes[1], d1);\n    // reset, unobserve and remove\n    recorded = null;\n    dom(slot).unobserveNodes(observer);\n    dom(el).removeChild(d);\n    dom(el).removeChild(d1);\n    observer.flush();\n    assert.equal(recorded, null);\n    document.body.removeChild(el);\n  });\n\n  test('observe effective children inside deep distributing element (async)', function(done) {\n    var el = document.createElement('test-slot3');\n    document.body.appendChild(el);\n\n    var recorded;\n    var slot = el.$.slot.$.slot.$.slot;\n    var observer = dom(slot).observeNodes(function(info) {\n      recorded = info;\n    });\n    // add\n    var d = document.createElement('div');\n    var d1 = document.createElement('div');\n    dom(el).appendChild(d);\n    dom(el).appendChild(d1);\n    setTimeout(function() {\n      assert.equal(recorded.addedNodes.length, 2);\n      assert.equal(recorded.removedNodes.length, 0);\n      assert.equal(recorded.addedNodes[0], d);\n      assert.equal(recorded.addedNodes[1], d1);\n      // remove\n      dom(el).removeChild(d);\n      dom(el).removeChild(d1);\n      setTimeout(function() {\n        assert.equal(recorded.addedNodes.length, 0);\n        assert.equal(recorded.removedNodes.length, 2);\n        assert.equal(recorded.removedNodes[0], d);\n        assert.equal(recorded.removedNodes[1], d1);\n        // add\n        dom(el).appendChild(d);\n        dom(el).appendChild(d1);\n        setTimeout(function() {\n          assert.equal(recorded.addedNodes.length, 2);\n          assert.equal(recorded.addedNodes[0], d);\n          assert.equal(recorded.addedNodes[1], d1);\n          // reset, unobserve and remove\n          recorded = null;\n          dom(slot).unobserveNodes(observer);\n          dom(el).removeChild(d);\n          dom(el).removeChild(d1);\n          setTimeout(function() {\n            assert.equal(recorded, null);\n            document.body.removeChild(el);\n            done();\n          });\n        });\n      });\n    });\n  });\n\n\n  test('observe effective children attr changes inside deep distributing element (async)', function(done) {\n    var el = document.createElement('test-slot-attr3');\n    document.body.appendChild(el);\n\n    var recorded;\n    var slot = el.$.slot.$.slot.$.slot;\n    var observer = dom(slot).observeNodes(function(info) {\n      recorded = info;\n    });\n    observer.flush();\n    recorded = null;\n    // add\n    var d = document.createElement('div');\n    var d1 = document.createElement('div');\n    dom(el).appendChild(d);\n    dom(el).appendChild(d1);\n    observer.flush();\n    assert.equal(recorded, null);\n    setTimeout(function() {\n      assert.equal(recorded, null);\n      dom(d).setAttribute('slot', 'a');\n      setTimeout(function() {\n        assert.equal(recorded.addedNodes.length, 1);\n        assert.equal(recorded.removedNodes.length, 0);\n        assert.equal(recorded.addedNodes[0], d);\n        dom(d).removeAttribute('slot');\n        setTimeout(function() {\n          assert.equal(recorded.addedNodes.length, 0);\n          assert.equal(recorded.removedNodes.length, 1);\n          assert.equal(recorded.removedNodes[0], d);\n          recorded = null;\n          dom(slot).unobserveNodes(observer);\n          dom(d).setAttribute('slot', 'a');\n          setTimeout(function() {\n            assert.equal(recorded, null);\n            document.body.removeChild(el);\n            done();\n          });\n        });\n      });\n    });\n  });\n\n  test('observe effective children attr changes inside deep distributing element without outer select (async)', function(done) {\n    var el = document.createElement('test-slot-attr-inside');\n    document.body.appendChild(el);\n\n    var recorded;\n    var slot = el.$.slot.$.slot.$.slot.$.slot;\n    var observer = dom(slot).observeNodes(function(info) {\n      recorded = info;\n    });\n    observer.flush();\n    recorded = null;\n    // add\n    var d = document.createElement('div');\n    var d1 = document.createElement('div');\n    dom(el).appendChild(d);\n    dom(el).appendChild(d1);\n    observer.flush();\n    assert.equal(recorded, null);\n    setTimeout(function() {\n      assert.equal(recorded, null);\n      dom(d).setAttribute('slot', 'a');\n      setTimeout(function() {\n        assert.equal(recorded.addedNodes.length, 1);\n        assert.equal(recorded.removedNodes.length, 0);\n        assert.equal(recorded.addedNodes[0], d);\n        dom(d).removeAttribute('slot');\n        setTimeout(function() {\n          assert.equal(recorded.addedNodes.length, 0);\n          assert.equal(recorded.removedNodes.length, 1);\n          assert.equal(recorded.removedNodes[0], d);\n          recorded = null;\n          dom(slot).unobserveNodes(observer);\n          dom(d).setAttribute('slot', 'a');\n          setTimeout(function() {\n            assert.equal(recorded, null);\n            document.body.removeChild(el);\n            done();\n          });\n        });\n      });\n    });\n  });\n\n  test('add/remove multiple observers', function() {\n    var el = document.createElement('test-slot1');\n    document.body.appendChild(el);\n\n    var r1 = 0;\n    var h1 = dom(el.$.slot).observeNodes(function() {\n      r1++;\n    });\n    var r2 = 0;\n    var h2 = dom(el.$.slot).observeNodes(function() {\n      r2++;\n    });\n    var r3 = 0;\n    var h3 = dom(el.$.slot).observeNodes(function() {\n      r3++;\n    });\n    // add\n    var d = document.createElement('div');\n    dom(el).appendChild(d);\n    h1.flush();\n    h2.flush();\n    h3.flush();\n    assert.equal(r1, 1);\n    assert.equal(r2, 1);\n    assert.equal(r3, 1);\n    dom(el.$.slot).unobserveNodes(h1);\n    d = document.createElement('div');\n    dom(el).appendChild(d);\n    h1.flush();\n    h2.flush();\n    h3.flush();\n    assert.equal(r1, 1);\n    assert.equal(r2, 2);\n    assert.equal(r3, 2);\n    dom(el.$.slot).unobserveNodes(h2);\n    d = document.createElement('div');\n    dom(el).appendChild(d);\n    h1.flush();\n    h2.flush();\n    h3.flush();\n    assert.equal(r1, 1);\n    assert.equal(r2, 2);\n    assert.equal(r3, 3);\n    dom(el.$.slot).unobserveNodes(h3);\n    d = document.createElement('div');\n    dom(el).appendChild(d);\n    h1.flush();\n    h2.flush();\n    h3.flush();\n    assert.equal(r1, 1);\n    assert.equal(r2, 2);\n    assert.equal(r3, 3);\n    h1 = dom(el.$.slot).observeNodes(h1.callback);\n    h2 = dom(el.$.slot).observeNodes(h2.callback);\n    h3 = dom(el.$.slot).observeNodes(h3.callback);\n    h1.flush();\n    h2.flush();\n    h3.flush();\n    assert.equal(r1, 2);\n    assert.equal(r2, 3);\n    assert.equal(r3, 4);\n    d = document.createElement('div');\n    dom(el).appendChild(d);\n    h1.flush();\n    h2.flush();\n    h3.flush();\n    assert.equal(r1, 3);\n    assert.equal(r2, 4);\n    assert.equal(r3, 5);\n    dom(el.$.slot).unobserveNodes(h3);\n    d = document.createElement('div');\n    dom(el).appendChild(d);\n    h1.flush();\n    h2.flush();\n    h3.flush();\n    assert.equal(r1, 4);\n    assert.equal(r2, 5);\n    assert.equal(r3, 5);\n    dom(el.$.slot).unobserveNodes(h2);\n    d = document.createElement('div');\n    dom(el).appendChild(d);\n    h1.flush();\n    h2.flush();\n    h3.flush();\n    assert.equal(r1, 5);\n    assert.equal(r2, 5);\n    assert.equal(r3, 5);\n    dom(el.$.slot).unobserveNodes(h1);\n    d = document.createElement('div');\n    dom(el).appendChild(d);\n    h1.flush();\n    h2.flush();\n    h3.flush();\n    assert.equal(r1, 5);\n    assert.equal(r2, 5);\n    assert.equal(r3, 5);\n  });\n\n  test('observe changes of target with dynamically added <slot>', function() {\n    var el = document.createElement('test-static');\n    document.body.appendChild(el);\n    var container = el.shadowRoot.childNodes[1];\n    var recorded = null;\n    var observer = dom(container).observeNodes(function(info) {\n      recorded = info;\n    });\n    var slot = document.createElement('slot');\n    container.appendChild(slot);\n    observer.flush();\n    recorded = null;\n    var child = document.createElement('div');\n    el.appendChild(child);\n    observer.flush();\n    assert.equal(recorded.addedNodes.length, 1);\n    assert.equal(recorded.addedNodes[0], child);\n    recorded = null;\n    el.removeChild(child);\n    observer.flush();\n    assert.equal(recorded.removedNodes.length, 1);\n    assert.equal(recorded.removedNodes[0], child);\n    recorded = null;\n    container.removeChild(slot);\n    observer.flush();\n    el.appendChild(child);\n    assert.equal(recorded, null);\n    dom(container).unobserveNodes(observer);\n    document.body.removeChild(el);\n  });\n\n  test('observe changes of target with dynamically added <slot> (flush/async)', function(done) {\n    var el = document.createElement('test-static');\n    document.body.appendChild(el);\n    var container = el.shadowRoot.childNodes[1];\n    var recorded = null;\n    var observer = dom(container).observeNodes(function(info) {\n      recorded = info;\n    });\n    var slot = document.createElement('slot');\n    container.appendChild(slot);\n    observer.flush();\n    recorded = null;\n    var child = document.createElement('div');\n    el.appendChild(child);\n    setTimeout(function() {\n      assert.equal(recorded.addedNodes.length, 1);\n      assert.equal(recorded.addedNodes[0], child);\n      done();\n    });\n  });\n\n  test('observe changes of target with dynamically added <slot> (async)', function(done) {\n    var el = document.createElement('test-static');\n    document.body.appendChild(el);\n    var container = el.shadowRoot.childNodes[1];\n    var recorded = null;\n    var observer = dom(container).observeNodes(function(info) {\n      recorded = info;\n    });\n    var slot = document.createElement('slot');\n    container.appendChild(slot);\n    observer.flush();\n    recorded = null;\n    var child = document.createElement('div');\n    el.appendChild(child);\n    setTimeout(function() {\n      assert.equal(recorded.addedNodes.length, 1);\n      assert.equal(recorded.addedNodes[0], child);\n      recorded = null;\n      el.removeChild(child);\n      setTimeout(function() {\n        assert.equal(recorded.removedNodes.length, 1);\n        assert.equal(recorded.removedNodes[0], child);\n        recorded = null;\n        container.removeChild(slot);\n        setTimeout(function() {\n          el.appendChild(child);\n          assert.equal(recorded, null);\n          dom(container).unobserveNodes(observer);\n          document.body.removeChild(el);\n          done();\n        });\n      });\n    });\n  });\n\n  test('element distributed to insertion point observing itself', function() {\n    var host = document.createElement('test-slot');\n    var el = document.createElement('test-self-observe');\n    host.appendChild(el);\n    document.body.appendChild(host);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.ok(el._observer);\n    var div = document.createElement('div');\n    el.appendChild(div);\n    el._observer.flush();\n    assert.equal(el.info.addedNodes[0], div);\n    document.body.removeChild(host);\n  });\n\n});\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/polymer-dom.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n</head>\n<body>\n\n  <dom-module id=\"x-slot\">\n    <template>\n      <div id=\"container\"><slot id=\"slot\"></slot></div>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-slot'\n});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-scoped-node\">\n    <template>\n      <div><div id=\"first\">first</div></div>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-scoped-node'\n});\n</script>\n\n  <dom-module id=\"x-container-slot\">\n    <template>\n      <x-slot id=\"container\"><div id=\"first\">first</div><slot id=\"slot\"></slot><div id=\"last\">last</div></x-slot>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-container-slot'\n});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-event-scoped\">\n    <template>\n      <div id=\"scoped\"></div>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-event-scoped',\n  fireComposed: function() {\n    return this.fire('composed', null, {node: this.$.scoped});\n  }\n});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-focusable-in-shadow\">\n    <template>\n      <input id=\"focusable\"></input>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-focusable-in-shadow'\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-class-bindings\">\n<template>\n  <style>\n    .a {\n      border: 2px solid orange;\n    }\n\n    .aa {\n      border: 12px solid red;\n    }\n\n    .b {\n      padding: 4px;\n    }\n  </style>\n  <div>\n    <div id=\"class\" class$=\"[[clazz]] b\">class</div>\n    <div id=\"className\" class-name=\"[[clazz]] b\">class</div>\n  </div>\n</template>\n<script type=\"module\">\n  import { Polymer } from '../../polymer-legacy.js';\n  Polymer({\n    properties: {\n      clazz: {type: String}\n    },\n    is: 'x-class-bindings'\n  });\n</script>\n</dom-module>\n\n   <test-fixture id=\"scoped\">\n    <template>\n      <x-event-scoped></x-event-scoped>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"slot\">\n    <template>\n      <x-container-slot></x-container-slot>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"focusableInShadow\">\n    <template>\n      <x-focusable-in-shadow></x-focusable-in-shadow>\n    </template>\n  </test-fixture>\n\n<script type=\"module\">\nimport { dom } from '../../lib/legacy/polymer.dom.js';\nimport { useShadow, useNativeCustomElements, useNativeCSSProperties } from '../../lib/utils/settings.js';\n\nsuite('extended dom api', function() {\n  test('getEffectiveChildNodes', function() {\n    var el = fixture('slot');\n    var div = document.createElement('div');\n    el.appendChild(div);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.deepEqual(dom(el).getEffectiveChildNodes(),\n      [div]);\n    assert.deepEqual(dom(el.$.container).getEffectiveChildNodes(),\n      [el.$.first, div, el.$.last]);\n    assert.deepEqual(dom(el.$.container.$.container).getEffectiveChildNodes(),\n      [el.$.first, div, el.$.last]);\n  });\n\n  test('queryDistributedElements', function() {\n    var el = fixture('slot');\n    var div = document.createElement('div');\n    el.appendChild(div);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.deepEqual(dom(el).queryDistributedElements('foo'),\n      []);\n    assert.deepEqual(dom(el).queryDistributedElements('div'),\n      [div]);\n    assert.deepEqual(dom(el.$.container).queryDistributedElements('#first'),\n      [el.$.first]);\n    assert.deepEqual(dom(el.$.container.$.container).queryDistributedElements('#last'),\n      [el.$.last]);\n  });\n\n});\n\nsuite('distribution', function() {\n  test('getDistributedNodes', function() {\n    var el = fixture('slot');\n    var div = document.createElement('div');\n    el.appendChild(div);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.deepEqual(dom(el.$.slot).getDistributedNodes(), [div]);\n    assert.deepEqual(dom(el.$.container.$.slot).getDistributedNodes(),\n      [el.$.first, div, el.$.last]);\n  });\n\n  test('getDestinationInsertionPoints', function() {\n    var el = fixture('slot');\n    var div = document.createElement('div');\n    el.appendChild(div);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.deepEqual(dom(el.$.first).getDestinationInsertionPoints(),\n      [el.$.container.$.slot]);\n    assert.deepEqual(dom(div).getDestinationInsertionPoints(),\n      [el.$.slot, el.$.container.$.slot]);\n  });\n});\n\nsuite('events', function() {\n\n  test('localTarget, rootTarget, path', function(done) {\n    var el = fixture('scoped');\n    el.addEventListener('composed', function(e) {\n      assert.equal(dom(e).rootTarget, el.$.scoped);\n      assert.equal(dom(e).localTarget, el);\n      let nodes = [];\n      let p = el.$.scoped;\n      while (p) {\n        nodes.push(p);\n        p = p.parentNode || p.host;\n      }\n      nodes.push(window);\n      assert.deepEqual(Array.from(dom(e).path), nodes);\n      done();\n    });\n    el.fireComposed();\n  });\n\n});\n\nsuite('activeElement getter', function() {\n  test('Retrieves `_activeElement` (ShadyDOM) or `activeElement`.', function() {\n    var focusableInShadow = fixture('focusableInShadow');\n    focusableInShadow.$.focusable.focus();\n    var rootNode = focusableInShadow.getRootNode();\n    assert.equal(dom(rootNode).activeElement, focusableInShadow);\n    assert.equal(dom(focusableInShadow.shadowRoot).activeElement, focusableInShadow.$.focusable);\n  });\n});\n\nsuite('legacy api', function() {\n  test('getEffectiveChildNodes', function() {\n    var el = fixture('slot');\n    var div = document.createElement('div');\n    var t = document.createTextNode('');\n    el.appendChild(div);\n    el.appendChild(t);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.deepEqual(el.getEffectiveChildNodes(),\n      [div, t]);\n    assert.deepEqual(el.$.container.getEffectiveChildNodes(),\n      [el.$.first, div, t, el.$.last]);\n  });\n\n  test('getEffectiveChildren', function() {\n    var el = fixture('slot');\n    var div = document.createElement('div');\n    el.appendChild(div);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.deepEqual(el.getEffectiveChildNodes(),\n      [div]);\n    assert.deepEqual(el.$.container.getEffectiveChildNodes(),\n      [el.$.first, div, el.$.last]);\n  });\n\n  test('getEffectiveTextContent', function() {\n    var el = fixture('slot');\n    var t1 = document.createTextNode('a');\n    var t2 = document.createTextNode('b');\n    el.appendChild(t1);\n    el.appendChild(t2);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.deepEqual(el.getEffectiveTextContent(), 'ab');\n    assert.deepEqual(el.$.container.getEffectiveTextContent(), 'firstablast');\n  });\n\n  test('getContentChildNodes', function() {\n    var el = fixture('slot');\n    var div1 = document.createElement('div');\n    var t = document.createTextNode('');\n    var div2 = document.createElement('div');\n    el.appendChild(div1);\n    el.appendChild(t);\n    el.appendChild(div2);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.deepEqual(el.getContentChildNodes(),\n      [div1, t, div2]);\n    assert.deepEqual(el.getContentChildNodes('slot'),\n      [div1, t, div2]);\n  });\n\n  test('getContentChildren', function() {\n    var el = fixture('slot');\n    var div1 = document.createElement('div');\n    var t = document.createTextNode('');\n    var div2 = document.createElement('div');\n    el.appendChild(div1);\n    el.appendChild(t);\n    el.appendChild(div2);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.deepEqual(el.getContentChildren(),\n      [div1, div2]);\n    assert.deepEqual(el.getContentChildren('slot'),\n      [div1, div2]);\n  });\n\n  test('queryDistributedElements', function() {\n    var el = fixture('slot');\n    var div = document.createElement('div');\n    el.appendChild(div);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.deepEqual(el.queryDistributedElements('foo'),\n      []);\n    assert.deepEqual(el.queryDistributedElements('div'),\n      [div]);\n    assert.deepEqual(el.$.container.queryDistributedElements('#first'),\n      [el.$.first]);\n  });\n\n  test('queryEffectiveChildren', function() {\n    var el = fixture('slot');\n    var div = document.createElement('div');\n    el.appendChild(div);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.equal(el.queryEffectiveChildren('foo'),\n      null);\n    assert.deepEqual(el.queryEffectiveChildren('div'),\n      div);\n    assert.deepEqual(el.$.container.queryEffectiveChildren('#first'),\n      el.$.first);\n  });\n\n  test('queryAllEffectiveChildren', function() {\n    var el = fixture('slot');\n    var div1 = document.createElement('div');\n    var div2 = document.createElement('div');\n    el.appendChild(div1);\n    el.appendChild(div2);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.deepEqual(el.queryAllEffectiveChildren('foo'),\n      []);\n    assert.deepEqual(el.queryAllEffectiveChildren('div'),\n      [div1, div2]);\n    assert.deepEqual(el.$.container.queryAllEffectiveChildren('div'),\n      [el.$.first, div1, div2, el.$.last]);\n  });\n\n  test('isLightDescendant', function() {\n    var el = fixture('slot');\n    var div1 = document.createElement('div');\n    el.appendChild(div1);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.equal(el.isLightDescendant(div1), true);\n    assert.equal(el.isLightDescendant(el.$.container), false);\n  });\n\n  test('isLocalDescendant', function() {\n    var el = fixture('slot');\n    var div1 = document.createElement('div');\n    el.appendChild(div1);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.equal(el.isLocalDescendant(div1), false);\n    assert.equal(el.isLocalDescendant(el.$.container), true);\n  });\n\n  test('domHost', function() {\n    var el = fixture('slot');\n    assert.equal(el.domHost, document);\n    assert.equal(el.$.container.domHost, el);\n  });\n\n  test('legacy settings', function() {\n    assert.equal(useShadow, !(window.ShadyDOM));\n    assert.equal(useNativeCustomElements, !(window.customElements.polyfillWrapFlushCallback));\n    assert.equal(useNativeCSSProperties, Boolean(!window.ShadyCSS || window.ShadyCSS.nativeCss));\n  });\n\n});\n\nsuite('forwarded native api', function() {\n\n  let el;\n\n  setup(function() {\n    el = document.createElement('x-container-slot');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('accessors are available', function() {\n    const d = dom(el);\n    assert.isDefined(d.parentNode);\n    assert.isDefined(d.firstChild);\n    assert.isDefined(d.lastChild);\n    assert.isDefined(d.nextSibling);\n    assert.isDefined(d.previousSibling);\n    assert.isDefined(d.firstElementChild);\n    assert.isDefined(d.lastElementChild);\n    assert.isDefined(d.nextElementSibling);\n    assert.isDefined(d.previousElementSibling);\n    assert.isDefined(d.childNodes);\n    assert.isDefined(d.children);\n    assert.isDefined(d.classList);\n    assert.isDefined(d.textContent);\n    assert.isDefined(d.innerHTML);\n    assert.isDefined(d.shadowRoot);\n  });\n\n  test('cloneNode', function() {\n    const clone = dom(el).cloneNode(el);\n    assert.ok(clone);\n    assert.equal(clone.localName, 'x-container-slot');\n  });\n\n  test('appendChild', function() {\n    const d1 = document.createElement('div');\n    dom(el).appendChild(d1);\n    assert.equal(dom(el).firstChild, d1);\n    assert.equal(dom(d1).parentNode, el);\n  });\n\n  test('insertBefore', function() {\n    const d1 = document.createElement('div');\n    const d2 = document.createElement('div');\n    dom(el).appendChild(d1);\n    dom(el).insertBefore(d2, d1);\n    assert.equal(dom(d2).nextSibling, d1);\n  });\n\n  test('removeChild', function() {\n    const d1 = document.createElement('div');\n    dom(el).appendChild(d1);\n    dom(el).removeChild(d1);\n    assert.equal(dom(d1).parentNode, null);\n  });\n\n  test('replaceChild', function() {\n    const d1 = document.createElement('div');\n    const d2 = document.createElement('div');\n    dom(el).appendChild(d1);\n    dom(el).replaceChild(d2, d1);\n    assert.equal(dom(d1).parentNode, null);\n    assert.equal(dom(el).firstChild, d2);\n    assert.equal(dom(d2).parentNode, el);\n  });\n\n  test('replaceChild', function() {\n    dom(el).setAttribute('foo', 'foo');\n    assert.equal(el.getAttribute('foo'), 'foo');\n  });\n\n  test('replaceChild', function() {\n    dom(el).setAttribute('foo', 'foo');\n    dom(el).removeAttribute('foo');\n    assert.isFalse(el.hasAttribute('foo'));\n  });\n\n  test('querySelector', function() {\n    const d1 = document.createElement('div');\n    dom(el).appendChild(d1);\n    const query = dom(el).querySelector('div');\n    assert.equal(query, d1);\n  });\n\n  test('querySelectorAll', function() {\n    const d1 = document.createElement('div');\n    const d2 = document.createElement('div');\n    dom(el).appendChild(d1);\n    dom(el).appendChild(d2);\n    const query = dom(el).querySelectorAll('div');\n    assert.equal(query[0], d1);\n    assert.equal(query[1], d2);\n    assert.equal(query.length, 2);\n  });\n\n  test('attachShadow', function() {\n    const el = document.createElement('div');\n    dom(el).attachShadow({mode: 'open'});\n    assert.isDefined(el.shadowRoot);\n  });\n\n  test('tree accessors', function() {\n    const d1 = document.createElement('div');\n    const d2 = document.createElement('div');\n    dom(el).appendChild(d1);\n    dom(el).appendChild(d2);\n    const pel = dom(el);\n    const pd1 = dom(d1);\n    const pd2 = dom(d2);\n    assert.equal(pd1.parentNode, el);\n    assert.equal(pel.firstChild, d1);\n    assert.equal(pel.lastChild, d2);\n    assert.equal(pel.firstElementChild, d1);\n    assert.equal(pel.lastElementChild, d2);\n    assert.equal(pd1.nextSibling, d2);\n    assert.equal(pd2.previousSibling, d1);\n    assert.equal(pd1.nextElementSibling, d2);\n    assert.equal(pd2.previousElementSibling, d1);\n    assert.equal(pel.childNodes[0], d1);\n    assert.equal(pel.childNodes[1], d2);\n    assert.equal(pel.children[0], d1);\n    assert.equal(pel.children[1], d2);\n  });\n\n  test('innerHTML', function() {\n    dom(el).innerHTML = '<div></div>';\n    assert.equal(dom(el).firstChild.localName, 'div');\n  });\n\n  test('textContent', function() {\n    dom(el).innerHTML = 'hi';\n    assert.equal(dom(dom(el).firstChild).textContent, 'hi');\n  });\n\n  test('classList', function() {\n    dom(el).classList.add('foo');\n    assert.equal(el.className, 'foo');\n  });\n\n  test('className', function() {\n    const el = document.createElement('x-scoped-node');\n    document.body.appendChild(el);\n    const testEl = el.$.first;\n    const testElDom = dom(testEl);\n    testElDom.className = 'foo';\n    assert.isTrue(testEl.classList.contains('foo'));\n    if (window['ShadyDOM']) {\n      assert.isTrue(testEl.classList.contains('style-scope'));\n    }\n    document.body.removeChild(el);\n  });\n\n  test('class bindings', function() {\n    const el = document.createElement('x-class-bindings');\n    document.body.appendChild(el);\n    assert.equal(getComputedStyle(el.$.class)['border-top-width'], '0px');\n    assert.equal(getComputedStyle(el.$.class)['padding-top'], '4px');\n    assert.equal(getComputedStyle(el.$.className)['border-top-width'], '0px');\n    assert.equal(getComputedStyle(el.$.className)['padding-top'], '4px');\n    el.clazz = 'a';\n    assert.equal(getComputedStyle(el.$.class)['border-top-width'], '2px');\n    assert.equal(getComputedStyle(el.$.class)['padding-top'], '4px');\n    assert.equal(getComputedStyle(el.$.className)['border-top-width'], '2px');\n    assert.equal(getComputedStyle(el.$.className)['padding-top'], '4px');\n    el.clazz = 'aa';\n    assert.equal(getComputedStyle(el.$.class)['border-top-width'], '12px');\n    assert.equal(getComputedStyle(el.$.class)['padding-top'], '4px');\n    assert.equal(getComputedStyle(el.$.className)['border-top-width'], '12px');\n    assert.equal(getComputedStyle(el.$.className)['padding-top'], '4px');\n    document.body.removeChild(el);\n  });\n\n});\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/polymer-element-with-apply-import.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport { PolymerElement } from '../../polymer-element.js';\n\nimport '@webcomponents/shadycss/entrypoints/apply-shim.js';\nimport '../../lib/elements/custom-style.js';\nimport { html } from '../../lib/utils/html-tag.js';\nclass ApplyElement extends PolymerElement {\n  static get template() {\n    return html`\n    <style>\n    :host {\n      display: block;\n      @apply --mixin;\n    }\n    </style>\n`;\n  }\n\n  static get is() {return 'apply-element';}\n}\ncustomElements.define('apply-element', ApplyElement);\nclass XOuter extends PolymerElement {\n  static get template() {\n    return html`\n    <style>\n    :host {\n      display: block;\n      @apply --mixin;\n      background-color: rgb(123, 123, 123);\n    }\n    :host > * {\n      --mixin: {\n        position: absolute;\n        margin: 50px;\n        height: 100px;\n        width: 100px;\n        background-color: rgb(255, 0, 0);\n      }\n    }\n    </style>\n    <apply-element></apply-element>\n`;\n  }\n\n  static get is() {return 'x-outer';}\n}\ncustomElements.define('x-outer', XOuter);\n"
  },
  {
    "path": "test/unit/polymer-element-with-apply.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"./polymer-element-with-apply-import.js\"></script>\n</head>\n<body>\n  <custom-style>\n    <style>\n    html {\n      --mixin: {\n        height: 200px;\n        width: 200px;\n        background-color: rgb(0, 0, 255);\n      }\n    }\n    </style>\n  </custom-style>\n\n  <test-fixture id=\"apply\">\n    <template>\n      <apply-element></apply-element>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"outer\">\n    <template>\n      <x-outer></x-outer>\n    </template>\n  </test-fixture>\n\n  <script type=\"module\">\nimport './polymer-element-with-apply-import.js';\nsuite('Polymer.Element with ApplyShim', function() {\n  test('mixin from custom style', function() {\n    var el = fixture('apply');\n    assert.equal(ShadyCSS.getComputedStyleValue(el, 'background-color'), 'rgb(0, 0, 255)');\n    assert.equal(ShadyCSS.getComputedStyleValue(el, 'height'), '200px');\n    assert.equal(ShadyCSS.getComputedStyleValue(el, 'width'), '200px');\n  });\n  test('nested', function() {\n    var el = fixture('outer');\n    var inner = el.shadowRoot.querySelector('apply-element');\n    assert.equal(ShadyCSS.getComputedStyleValue(el, 'background-color'), 'rgb(123, 123, 123)');\n    assert.equal(ShadyCSS.getComputedStyleValue(el, 'height'), '200px');\n    assert.equal(ShadyCSS.getComputedStyleValue(el, 'width'), '200px');\n\n    assert.equal(ShadyCSS.getComputedStyleValue(inner, 'background-color'), 'rgb(255, 0, 0)');\n    assert.equal(ShadyCSS.getComputedStyleValue(inner, 'height'), '100px');\n    assert.equal(ShadyCSS.getComputedStyleValue(inner, 'width'), '100px');\n    assert.equal(ShadyCSS.getComputedStyleValue(inner, 'margin-top'), '50px');\n  });\n});\n</script>\n</body>\n</html>"
  },
  {
    "path": "test/unit/polymer.element.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-element.js\"></script>\n<body>\n\n  <dom-module id=\"my-element\">\n    <template>\n      <div id=\"content\">{{prop}}</div>\n    </template>\n    <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\n\nclass MyElement extends PolymerElement {\n\n  static get is() { return 'my-element'; }\n\n  static get properties() {\n    return {\n      prop: {\n        value: 'base',\n        observer: '_propObserver'\n      },\n      computedPropDep: {\n        value: true\n      },\n      computedProp: {\n        computed: '_compute(computedPropDep)'\n      },\n      accessor: String,\n      noStomp: String\n    };\n  }\n\n  static get observers() {\n    return [\n      '_methodObserver(prop)'\n    ];\n  }\n\n  constructor() {\n    super();\n    this._propObserver = sinon.spy();\n    this._methodObserver = sinon.spy();\n    this._tapListener = sinon.spy();\n    this._calledConstructor++;\n  }\n\n  get noStomp() {\n    return 'noStomp';\n  }\n\n  connectedCallback() {\n    super.connectedCallback();\n    this._calledConnectedCallback++;\n  }\n\n  attributeChangedCallback() {\n    super.attributeChangedCallback.apply(this, arguments);\n    this._callAttributeChangedCallback++;\n  }\n\n  ready() {\n    super.ready();\n    this._ensureAttribute('tabIndex', 0);\n    this.addEventListener('click', (e) => this._tapListener(e));\n    this._calledReady++;\n  }\n\n  _compute(value) {\n    return value;\n  }\n}\n\nMyElement.prototype._calledConstructor = 0;\nMyElement.prototype._calledConnectedCallback = 0;\nMyElement.prototype._calledReady = 0;\nMyElement.prototype._callAttributeChangedCallback = 0;\n\ncustomElements.define(MyElement.is, MyElement);\n\nwindow.MyElement = MyElement;\n</script>\n  </dom-module>\n\n\n  <dom-module id=\"sub-element\">\n    <script type=\"module\">\nimport '../../polymer-element.js';\n\nclass SubElement extends window.MyElement {\n\n  static get is() { return 'sub-element'; }\n\n  static get properties() {\n    return {\n      prop: {\n        value: 'sub'\n      },\n      prop2: {\n        value: 'prop2',\n        observer: '_prop2Observer'\n      },\n      computedPropDep: {\n        computed: '_compute(prop2)'\n      }\n    };\n  }\n\n  static get observers() {\n    return [\n      '_subMethodObserver(prop, prop2)'\n    ];\n  }\n\n  constructor() {\n    super();\n    this._calledConstructor++;\n    this._prop2Observer = sinon.spy();\n    this._subMethodObserver = sinon.spy();\n  }\n\n  connectedCallback() {\n    super.connectedCallback();\n    this._calledConnectedCallback++;\n  }\n\n  ready() {\n    super.ready();\n    this._calledReady++;\n    this._ensureAttribute('role', 'button');\n    this.addEventListener('click', (e) => this._tapListener(e));\n  }\n\n}\n\ncustomElements.define(SubElement.is, SubElement);\n\nwindow.SubElement = SubElement;\n</script>\n  </dom-module>\n\n  <dom-module id=\"sub-mixin-element\">\n    <script type=\"module\">\nimport '../../polymer-element.js';\n\nfunction MyMixin(Base) {\n  return class extends Base {\n\n    static get properties() {\n      return {\n        prop: {\n          value: 'mixin'\n        },\n        mixin: {\n          value: 'mixin',\n          observer: '_mixinObserver'\n        }\n      };\n    }\n\n    static get observers() {\n      return [\n        '_mixinMethodObserver(mixin, prop, prop2)'\n      ];\n    }\n\n    constructor() {\n      super();\n      this._calledConstructor++;\n      this._mixinObserver = sinon.spy();\n      this._mixinMethodObserver = sinon.spy();\n    }\n\n    connectedCallback() {\n      super.connectedCallback();\n      this._calledConnectedCallback++;\n    }\n\n    ready() {\n      super.ready();\n      this._calledReady++;\n      this._ensureAttribute('mixinattr', 'mixinattr');\n      this.addEventListener('click', (e) => this._tapListener(e));\n    }\n\n  };\n}\n\nclass SubMixinElement extends MyMixin(window.SubElement) {\n\n  static get is() { return 'sub-mixin-element'; }\n\n  static get properties() {\n    return {\n      prop3: {\n        value: 'prop3',\n        observer: '_prop3Observer'\n      }\n    };\n  }\n\n  static get observers() {\n    return [\n      '_subMixinMethodObserver(mixin, prop, prop2, prop3)'\n    ];\n  }\n\n  constructor() {\n    super();\n    this._calledConstructor++;\n    this._prop3Observer = sinon.spy();\n    this._subMixinMethodObserver = sinon.spy();\n  }\n\n  connectedCallback() {\n    super.connectedCallback();\n    this._calledConnectedCallback++;\n  }\n\n  ready() {\n    super.ready();\n    this._calledReady++;\n    this._ensureAttribute('submixinattr', 'submixinattr');\n    this.addEventListener('click', (e) => this._tapListener(e));\n  }\n\n}\n\ncustomElements.define(SubMixinElement.is, SubMixinElement);\n\nwindow.SubMixinElement = SubMixinElement;\n</script>\n  </dom-module>\n\n  <script type=\"module\">\nimport { html } from '../../polymer-element.js';\n\nclass SubNewTemplate extends window.MyElement {\n  static get template() {\n    return html`\n      <h1>Sub template</h1>\n      <div id=\"subContent\">{{prop2}}</div>`;\n  }\n\n  static get properties() {\n    return {\n      prop2: {\n        value: 'prop2',\n      }\n    };\n  }\n}\n\ncustomElements.define('sub-new-template', SubNewTemplate);\n\n/**\n * Instead of overriding the static getter, this element has its template\n * assigned directly to the constructor.\n */\nclass SubNewTemplateAssigned extends window.MyElement {\n  static get properties() {\n    return {\n      prop2: {\n        value: 'prop2',\n      }\n    };\n  }\n}\n\nSubNewTemplateAssigned.template = html`\n  <h1>Sub template</h1>\n  <div id=\"subContent\">{{prop2}}</div>`;\n\ncustomElements.define('sub-new-template-assigned', SubNewTemplateAssigned);\n</script>\n\n  <template id=\"no-dom-module\">\n    <style>\n    :host {\n      display: block;\n      border: 10px solid rgb(123, 123, 123);\n    }\n    </style>\n    <div id=\"child\">Content</div>\n  </template>\n  <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nclass NoDomModule extends PolymerElement {\n  static get is() {return 'no-dom-module';}\n  static get template() {\n    return document.body.querySelector('template#no-dom-module');\n  }\n}\ncustomElements.define('no-dom-module', NoDomModule);\n</script>\n\n  <dom-module id=\"sub-extended-template\">\n    <script type=\"module\">\nimport '../../polymer-element.js';\n// Setting up property bind listeners in both base and sub class\n// is required to catch regression bug\nclass ElementWithBindListeners extends window.MyElement {\n  static get is() { return 'element-with-bind-listeners'; }\n}\nclass SubExtendedTemplate extends ElementWithBindListeners {\n  static get is() { return 'sub-extended-template'; }\n  static get template() {\n    if (!this.hasOwnProperty('_template')) {\n      const baseClass = Object.getPrototypeOf(this.prototype).constructor;\n      this._template = baseClass.template.cloneNode(true);\n      const newElement = document.createElement('div');\n      newElement.innerHTML = '<div id=\"subContent\" imaginary-prop$=\"{{prop}}\"\"></div>';\n      this._template.content.appendChild(newElement.firstChild);\n    }\n    return this._template;\n  }\n}\ncustomElements.define(ElementWithBindListeners.is, ElementWithBindListeners);\ncustomElements.define(SubExtendedTemplate.is, SubExtendedTemplate);\n</script>\n  </dom-module>\n\n  <test-fixture id=\"my-element-attr\">\n    <template>\n      <my-element prop=\"attr\" foo=\"foo\"></my-element>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"sub-element-attr\">\n    <template>\n      <sub-element prop=\"attr\" prop2=\"attr\"></sub-element>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"sub-mixin-element-attr\">\n    <template>\n      <sub-mixin-element prop=\"attr\" prop2=\"attr\" prop3=\"attr\"></sub-mixin-element>\n    </template>\n  </test-fixture>\n\n  <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nsuite('class extends Polymer.Element', function() {\n\n  var el;\n\n  setup(function() {\n    el = document.createElement('my-element');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('instanceof', function() {\n    assert.instanceOf(el, HTMLElement);\n    assert.instanceOf(el, PolymerElement);\n    assert.instanceOf(el, window.MyElement);\n  });\n\n  test('lifecycle', function() {\n    assert.equal(el._calledConstructor, 1);\n    assert.equal(el._calledConnectedCallback, 1);\n    assert.equal(el._calledReady, 1);\n    assert.equal(el._callAttributeChangedCallback, 0);\n  });\n\n  test('template', function() {\n    assert.equal(el.prop, 'base');\n    assert.equal(el.$.content.textContent, el.prop);\n  });\n\n  test('observers', function() {\n    assert.isTrue(el._propObserver.calledOnce);\n    assert.isTrue(el._propObserver.calledWith('base'));\n    assert.isTrue(el._methodObserver.calledOnce);\n    assert.isTrue(el._methodObserver.calledWith('base'));\n  });\n\n  test('listeners', function() {\n    el.dispatchEvent(new CustomEvent('click'));\n    assert.equal(el._tapListener.callCount, 1);\n  });\n\n  test('properties', function() {\n    assert.equal(el.prop, 'base');\n    assert.equal(el.computedPropDep, true);\n    assert.equal(el.computedProp, true);\n  });\n\n  test('attributes', function() {\n    const fixtureEl = fixture('my-element-attr');\n    assert.equal(fixtureEl.prop, 'attr');\n    assert.equal(fixtureEl._callAttributeChangedCallback, 1);\n    assert.isTrue(fixtureEl.hasAttribute('tabindex'));\n  });\n\n  test('reflecting attributes', function() {\n    const fixtureEl = fixture('my-element-attr');\n    fixtureEl.prop = 'propValue';\n    fixtureEl._propertyToAttribute('prop');\n    assert.equal(fixtureEl.getAttribute('prop'), 'propValue');\n  });\n\n  test('version', function() {\n    assert.isOk(el.constructor.polymerElementVersion);\n  });\n});\n\nsuite('subclass', function() {\n\n  let el;\n\n  setup(function() {\n    el = document.createElement('sub-element');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('instanceof', function() {\n    assert.instanceOf(el, HTMLElement);\n    assert.instanceOf(el, PolymerElement);\n    assert.instanceOf(el, window.MyElement);\n    assert.instanceOf(el, window.SubElement);\n  });\n\n  test('lifecycle', function() {\n    assert.equal(el._calledConstructor, 2);\n    assert.equal(el._calledConnectedCallback, 2);\n    assert.equal(el._calledReady, 2);\n    assert.equal(el._callAttributeChangedCallback, 0);\n  });\n\n  test('template', function() {\n    assert.equal(el.prop, 'sub');\n    assert.equal(el.$.content.textContent, el.prop);\n  });\n\n  test('observers', function() {\n    assert.isTrue(el._propObserver.calledOnce);\n    assert.isTrue(el._propObserver.calledWith('sub'));\n    assert.isTrue(el._methodObserver.calledOnce);\n    assert.isTrue(el._methodObserver.calledWith('sub'));\n    // sub\n    assert.isTrue(el._prop2Observer.calledOnce);\n    assert.isTrue(el._prop2Observer.calledWith('prop2'));\n    assert.isTrue(el._subMethodObserver.calledOnce);\n    assert.isTrue(el._subMethodObserver.calledWith('sub', 'prop2'));\n  });\n\n  test('listeners', function() {\n    el.dispatchEvent(new CustomEvent('click'));\n    assert.equal(el._tapListener.callCount, 2);\n  });\n\n  test('properties', function() {\n    assert.equal(el.prop, 'sub');\n    assert.equal(el.prop2, 'prop2');\n    assert.equal(el.computedPropDep, 'prop2');\n    assert.equal(el.computedProp, 'prop2', 'computedProp dependency cannot itself be a computed property');\n  });\n\n  test('attributes', function() {\n    const fixtureEl = fixture('sub-element-attr');\n    assert.equal(fixtureEl.prop, 'attr');\n    assert.equal(fixtureEl.prop2, 'attr');\n    assert.equal(fixtureEl._callAttributeChangedCallback, 2);\n    assert.isTrue(fixtureEl.hasAttribute('tabindex'));\n    assert.equal(fixtureEl.getAttribute('role'), 'button');\n  });\n\n});\n\nsuite('mixin', function() {\n\n  let el;\n\n  setup(function() {\n    el = document.createElement('sub-mixin-element');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('instanceof', function() {\n    assert.instanceOf(el, HTMLElement);\n    assert.instanceOf(el, PolymerElement);\n    assert.instanceOf(el, window.MyElement);\n    assert.instanceOf(el, window.SubElement);\n    assert.instanceOf(el, window.SubMixinElement);\n  });\n\n  test('lifecycle', function() {\n    assert.equal(el._calledConstructor, 4);\n    assert.equal(el._calledConnectedCallback, 4);\n    assert.equal(el._calledReady, 4);\n    assert.equal(el._callAttributeChangedCallback, 0);\n  });\n\n  test('template', function() {\n    assert.equal(el.prop, 'mixin');\n    assert.equal(el.$.content.textContent, el.prop);\n  });\n\n  test('observers', function() {\n    assert.isTrue(el._propObserver.calledOnce);\n    assert.isTrue(el._propObserver.calledWith('mixin'));\n    assert.isTrue(el._methodObserver.calledOnce);\n    assert.isTrue(el._methodObserver.calledWith('mixin'));\n    // sub\n    assert.isTrue(el._prop2Observer.calledOnce);\n    assert.isTrue(el._prop2Observer.calledWith('prop2'));\n    assert.isTrue(el._subMethodObserver.calledOnce);\n    assert.isTrue(el._subMethodObserver.calledWith('mixin', 'prop2'));\n    // mixin\n    assert.isTrue(el._mixinObserver.calledOnce);\n    assert.isTrue(el._mixinObserver.calledWith('mixin'));\n    assert.isTrue(el._mixinMethodObserver.calledOnce);\n    assert.isTrue(el._mixinMethodObserver.calledWith('mixin', 'mixin', 'prop2'));\n    // submixin\n    assert.isTrue(el._prop3Observer.calledOnce);\n    assert.isTrue(el._prop3Observer.calledWith('prop3'));\n    assert.isTrue(el._subMixinMethodObserver.calledOnce);\n    assert.isTrue(el._subMixinMethodObserver.calledWith('mixin', 'mixin', 'prop2', 'prop3'));\n\n  });\n\n  test('listeners', function() {\n    el.dispatchEvent(new CustomEvent('click'));\n    assert.equal(el._tapListener.callCount, 4);\n  });\n\n  test('attributes', function() {\n    const fixtureEl = fixture('sub-mixin-element-attr');\n    assert.equal(fixtureEl.prop, 'attr');\n    assert.equal(fixtureEl.prop2, 'attr');\n    assert.equal(fixtureEl.prop3, 'attr');\n    assert.equal(fixtureEl._callAttributeChangedCallback, 3);\n    assert.isTrue(fixtureEl.hasAttribute('tabindex'));\n    assert.equal(fixtureEl.getAttribute('role'), 'button');\n    assert.equal(fixtureEl.getAttribute('mixinattr'), 'mixinattr');\n    assert.equal(fixtureEl.getAttribute('submixinattr'), 'submixinattr');\n  });\n\n});\n\nsuite('subclass new template', function() {\n  let el;\n\n  setup(function() {\n    el = document.createElement('sub-new-template');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('template', function() {\n    assert.equal(el.prop2, 'prop2');\n    assert.equal(el.$.subContent.textContent, el.prop2);\n    assert.notOk(el.$.content);\n  });\n\n  suite('use without dom-module', function() {\n    let el;\n\n    setup(function() {\n      el = document.createElement('no-dom-module');\n      document.body.appendChild(el);\n    });\n\n    teardown(function() {\n      document.body.removeChild(el);\n    });\n\n    test('template', function() {\n      assert.ok(el.$.child);\n      assert.equal(el.$.child.textContent, 'Content');\n      assert.equal(window.ShadyCSS.getComputedStyleValue(el, 'border-top-width'), '10px');\n    });\n  });\n});\n\nsuite('subclass new template assigned', function() {\n  let el;\n\n  setup(function() {\n    el = document.createElement('sub-new-template-assigned');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('template', function() {\n    assert.equal(el.prop2, 'prop2');\n    assert.equal(el.$.subContent.textContent, el.prop2);\n    assert.notOk(el.$.content);\n  });\n});\n\nsuite('extend sub-class template', function() {\n  let el, baseEl;\n  setup(function() {\n    el = document.createElement('sub-extended-template');\n    document.body.appendChild(el);\n    baseEl = document.createElement('element-with-bind-listeners');\n    document.body.appendChild(baseEl);\n  });\n  teardown(function() {\n    document.body.removeChild(el);\n    document.body.removeChild(baseEl);\n  });\n  test('has original template', function() {\n    assert.equal(el.prop, 'base');\n    assert.equal(el.$.content.textContent, el.prop);\n  });\n  test('has new element', function() {\n    assert.ok(el.$.subContent);\n    assert.equal(el.$.subContent.getAttribute('imaginary-prop'), 'base');\n  });\n  test('base doesnt have new element', function() {\n    assert.notOk(baseEl.$.subContent);\n  });\n});\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/polymer.legacyelement.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n<body>\n\n  <dom-module id=\"my-element\">\n    <template>\n      <div id=\"content\"></div>\n    </template>\n    <script type=\"module\">\nimport { LegacyElementMixin } from '../../lib/legacy/legacy-element-mixin.js';\n\nclass MyElement extends LegacyElementMixin(HTMLElement) {\n\n  static get is() { return 'my-element'; }\n\n  static get properties() {\n    return {\n      prop: {\n        value: 'base'\n      }\n    };\n  }\n\n  created() {\n    super.created();\n    this._calledCreated++;\n  }\n\n  attached() {\n    super.attached();\n    this._calledAttached++;\n  }\n\n  attributeChanged() {\n    super.attributeChanged.apply(this, arguments);\n    this._callAttributeChanged++;\n  }\n\n  ready() {\n    super.ready();\n    this._calledReady++;\n  }\n}\n\nMyElement.prototype._calledCreated = 0;\nMyElement.prototype._calledAttached = 0;\nMyElement.prototype._calledReady = 0;\nMyElement.prototype._callAttributeChanged = 0;\n\ncustomElements.define(MyElement.is, MyElement);\n\nwindow.MyElement = MyElement;\n</script>\n  </dom-module>\n\n\n  <dom-module id=\"sub-element\">\n    <script type=\"module\">\n\nclass SubElement extends window.MyElement {\n\n  static get is() { return 'sub-element'; }\n\n  created() {\n    super.created();\n    this._calledCreated++;\n  }\n\n  attached() {\n    super.attached();\n    this._calledAttached++;\n  }\n\n  ready() {\n    super.ready();\n    this._calledReady++;\n  }\n\n}\n\ncustomElements.define(SubElement.is, SubElement);\n\nwindow.SubElement = SubElement;\n</script>\n  </dom-module>\n\n  <test-fixture id=\"my-element-attr\">\n    <template>\n      <my-element prop=\"attr\"></my-element>\n    </template>\n  </test-fixture>\n\n  <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nimport { ElementMixin } from '../../lib/mixins/element-mixin.js';\nimport { LegacyElementMixin } from '../../lib/legacy/legacy-element-mixin.js';\nsuite('class extends Polymer.LegacyElementMixin(HTMLElement)', function() {\n\n  var el;\n\n  setup(function() {\n    el = document.createElement('my-element');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('instanceof', function() {\n    assert.instanceOf(el, HTMLElement);\n    assert.instanceOf(el, PolymerElement);\n    assert.instanceOf(el, window.MyElement);\n  });\n\n  test('lifecycle', function() {\n    assert.equal(el._calledCreated, 1);\n    assert.equal(el._calledAttached, 1);\n    assert.equal(el._calledReady, 1);\n    assert.equal(el._callAttributeChanged, 0);\n  });\n\n  test('attributes', function() {\n    var fixtureEl = fixture('my-element-attr');\n    assert.equal(fixtureEl.prop, 'attr');\n    assert.equal(fixtureEl._callAttributeChanged, 1);\n  });\n\n});\n\nsuite('subclass', function() {\n\n  var el;\n\n  setup(function() {\n    el = document.createElement('sub-element');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('instanceof', function() {\n    assert.instanceOf(el, HTMLElement);\n    assert.instanceOf(el, PolymerElement);\n    assert.instanceOf(el, window.MyElement);\n    assert.instanceOf(el, window.SubElement);\n  });\n\n  test('lifecycle', function() {\n    assert.equal(el._calledCreated, 2);\n    assert.equal(el._calledAttached, 2);\n    assert.equal(el._calledReady, 2);\n    assert.equal(el._callAttributeChanged, 0);\n  });\n\n});\n\nsuite('misc', function() {\n\n  test('Polymer.ElementMixin caches', function() {\n    assert.equal(PolymerElement, ElementMixin(HTMLElement));\n     assert.equal(ElementMixin(HTMLElement),\n       ElementMixin(HTMLElement));\n  });\n\n   test('Polymer.LegacyElementMixin caches', function() {\n     assert.equal(LegacyElementMixin(HTMLElement),\n       LegacyElementMixin(HTMLElement));\n   });\n\n});\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/polymer.properties-mixin-with-property-accessors.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../lib/mixins/properties-mixin.js\"></script>\n  <script type=\"module\" src=\"../../lib/mixins/property-accessors.js\"></script>\n<body>\n\n  <dom-module id=\"my-element\">\n    <script type=\"module\">\nimport { PropertiesMixin } from '../../lib/mixins/properties-mixin.js';\nimport { PropertyAccessors } from '../../lib/mixins/property-accessors.js';\n\nclass MyElement extends PropertyAccessors(PropertiesMixin(HTMLElement)) {\n\n  static get properties() {\n    return {\n      prop: String\n    };\n  }\n\n  constructor() {\n    super();\n    this._propertiesChanged = sinon.spy();\n    this._tapListener = sinon.spy();\n    this._calledConstructor++;\n    this.prop = 'prop';\n  }\n\n  connectedCallback() {\n    super.connectedCallback();\n    this._calledConnectedCallback++;\n  }\n\n  attributeChangedCallback() {\n    super.attributeChangedCallback.apply(this, arguments);\n    this._callAttributeChangedCallback++;\n  }\n\n  ready() {\n    super.ready();\n    this._ensureAttribute('tabIndex', 0);\n    this.addEventListener('click', (e) => this._tapListener(e));\n    this._calledReady++;\n  }\n\n}\n\nMyElement.prototype._calledConstructor = 0;\nMyElement.prototype._calledConnectedCallback = 0;\nMyElement.prototype._calledReady = 0;\nMyElement.prototype._callAttributeChangedCallback = 0;\n\ncustomElements.define('my-element', MyElement);\n\nwindow.MyElement = MyElement;\n</script>\n  </dom-module>\n\n\n  <dom-module id=\"sub-element\">\n    <script type=\"module\">\nimport '../../lib/mixins/properties-mixin.js';\nimport '../../lib/mixins/property-accessors.js';\n\nclass SubElement extends window.MyElement {\n\n  static get properties() {\n    return {\n      prop2: String\n    };\n  }\n\n  constructor() {\n    super();\n    this._calledConstructor++;\n    this.prop = 'sub';\n    this.prop2 = 'prop2';\n  }\n\n  connectedCallback() {\n    super.connectedCallback();\n    this._calledConnectedCallback++;\n  }\n\n  ready() {\n    super.ready();\n    this._calledReady++;\n    this._ensureAttribute('role', 'button');\n    this.addEventListener('click', (e) => this._tapListener(e));\n  }\n\n}\n\ncustomElements.define('sub-element', SubElement);\n\nwindow.SubElement = SubElement;\n</script>\n  </dom-module>\n\n  <dom-module id=\"sub-mixin-element\">\n    <script type=\"module\">\nimport '../../lib/mixins/properties-mixin.js';\nimport '../../lib/mixins/property-accessors.js';\n\nfunction MyMixin(Base) {\n  return class extends Base {\n\n    static get properties() {\n      return {\n        mixin: Number\n      };\n    }\n\n    constructor() {\n      super();\n      this._calledConstructor++;\n      this.mixin = 'mixin';\n    }\n\n    connectedCallback() {\n      super.connectedCallback();\n      this._calledConnectedCallback++;\n    }\n\n    ready() {\n      super.ready();\n      this._calledReady++;\n      this._ensureAttribute('mixinattr', 'mixinattr');\n      this.addEventListener('click', (e) => this._tapListener(e));\n    }\n\n  };\n}\n\nclass SubMixinElement extends MyMixin(window.SubElement) {\n\n  static get properties() {\n    return {\n      prop3: String,\n      camelCase: String\n    };\n  }\n\n  constructor() {\n    super();\n    this._calledConstructor++;\n    this.prop3 = 'prop3';\n  }\n\n  connectedCallback() {\n    super.connectedCallback();\n    this._calledConnectedCallback++;\n  }\n\n  ready() {\n    super.ready();\n    this._calledReady++;\n    this._ensureAttribute('submixinattr', 'submixinattr');\n    this.addEventListener('click', (e) => this._tapListener(e));\n  }\n\n}\n\ncustomElements.define('sub-mixin-element', SubMixinElement);\n\nwindow.SubMixinElement = SubMixinElement;\n</script>\n  </dom-module>\n\n  <test-fixture id=\"my-element-attr\">\n    <template>\n      <my-element prop=\"attr\"></my-element>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"sub-element-attr\">\n    <template>\n      <sub-element prop=\"attr\" prop2=\"attr\"></sub-element>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"sub-mixin-element-attr\">\n    <template>\n      <sub-mixin-element prop=\"attr\" prop2=\"attr\" prop3=\"attr\" mixin=\"5\" camel-case=\"camelCase\"></sub-mixin-element>\n    </template>\n  </test-fixture>\n\n  <script type=\"module\">\nimport '../../lib/mixins/properties-mixin.js';\nimport '../../lib/mixins/property-accessors.js';\nsuite('class extends Polymer.PropertiesMixin', function() {\n\n  let el;\n\n  setup(function() {\n    el = document.createElement('my-element');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('instanceof', function() {\n    assert.instanceOf(el, HTMLElement);\n    assert.instanceOf(el, window.MyElement);\n  });\n\n  test('lifecycle', function() {\n    assert.equal(el._calledConstructor, 1);\n    assert.equal(el._calledConnectedCallback, 1);\n    assert.equal(el._calledReady, 1);\n    assert.equal(el._callAttributeChangedCallback, 0);\n  });\n\n  test('listeners', function() {\n    el.dispatchEvent(new CustomEvent('click'));\n    assert.equal(el._tapListener.callCount, 1);\n  });\n\n  test('properties', function() {\n    assert.equal(el.prop, 'prop');\n    assert.isTrue(el._propertiesChanged.calledOnce);\n    assert.deepEqual(el._propertiesChanged.args[0][0], {prop: 'prop'});\n  });\n\n  test('attributes', function() {\n    const fixtureEl = fixture('my-element-attr');\n    assert.equal(fixtureEl.prop, 'attr');\n    assert.equal(fixtureEl._callAttributeChangedCallback, 1);\n    assert.isTrue(fixtureEl.hasAttribute('tabindex'));\n  });\n\n});\n\nsuite('subclass', function() {\n\n  let el;\n\n  setup(function() {\n    el = document.createElement('sub-element');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('instanceof', function() {\n    assert.instanceOf(el, HTMLElement);\n    assert.instanceOf(el, window.MyElement);\n    assert.instanceOf(el, window.SubElement);\n  });\n\n  test('lifecycle', function() {\n    assert.equal(el._calledConstructor, 2);\n    assert.equal(el._calledConnectedCallback, 2);\n    assert.equal(el._calledReady, 2);\n    assert.equal(el._callAttributeChangedCallback, 0);\n  });\n\n  test('listeners', function() {\n    el.dispatchEvent(new CustomEvent('click'));\n    assert.equal(el._tapListener.callCount, 2);\n  });\n\n  test('properties', function() {\n    assert.equal(el.prop, 'sub');\n    assert.equal(el.prop2, 'prop2');\n    assert.isTrue(el._propertiesChanged.calledOnce);\n    assert.deepEqual(el._propertiesChanged.args[0][0], {prop: 'sub', prop2: 'prop2'});\n  });\n\n  test('attributes', function() {\n    const fixtureEl = fixture('sub-element-attr');\n    assert.equal(fixtureEl.prop, 'attr');\n    assert.equal(fixtureEl.prop2, 'attr');\n    assert.equal(fixtureEl._callAttributeChangedCallback, 2);\n    assert.isTrue(fixtureEl.hasAttribute('tabindex'));\n    assert.equal(fixtureEl.getAttribute('role'), 'button');\n  });\n\n});\n\nsuite('mixin', function() {\n\n  let el;\n\n  setup(function() {\n    el = document.createElement('sub-mixin-element');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('instanceof', function() {\n    assert.instanceOf(el, HTMLElement);\n    assert.instanceOf(el, window.MyElement);\n    assert.instanceOf(el, window.SubElement);\n    assert.instanceOf(el, window.SubMixinElement);\n  });\n\n  test('lifecycle', function() {\n    assert.equal(el._calledConstructor, 4);\n    assert.equal(el._calledConnectedCallback, 4);\n    assert.equal(el._calledReady, 4);\n    assert.equal(el._callAttributeChangedCallback, 0);\n  });\n\n  test('listeners', function() {\n    el.dispatchEvent(new CustomEvent('click'));\n    assert.equal(el._tapListener.callCount, 4);\n  });\n\n  test('properties', function() {\n    assert.equal(el.prop, 'sub');\n    assert.equal(el.prop2, 'prop2');\n    assert.equal(el.mixin, 'mixin');\n    assert.equal(el.prop3, 'prop3');\n    assert.isTrue(el._propertiesChanged.calledOnce);\n    assert.deepEqual(el._propertiesChanged.args[0][0], {prop: 'sub', prop2: 'prop2', mixin: 'mixin', prop3: 'prop3'});\n  });\n\n  test('attributes', function() {\n    const fixtureEl = fixture('sub-mixin-element-attr');\n    assert.strictEqual(fixtureEl.prop, 'attr');\n    assert.strictEqual(fixtureEl.prop2, 'attr');\n    assert.strictEqual(fixtureEl.prop3, 'attr');\n    assert.strictEqual(fixtureEl.camelCase, 'camelCase');\n    assert.strictEqual(fixtureEl.mixin, 5);\n    assert.equal(fixtureEl._callAttributeChangedCallback, 5);\n    assert.isTrue(fixtureEl.hasAttribute('tabindex'));\n    assert.equal(fixtureEl.getAttribute('role'), 'button');\n    assert.equal(fixtureEl.getAttribute('mixinattr'), 'mixinattr');\n  });\n\n});\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/polymer.properties-mixin.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../lib/mixins/properties-mixin.js\"></script>\n  <body>\n\n  <test-fixture id=\"my-element-attr\">\n    <template>\n      <my-element prop=\"attr\" camelCase=\"camelCase\"></my-element>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"sub-element-attr\">\n    <template>\n      <sub-element prop=\"attr\" prop2=\"attr\" camelCase=\"camelCase\" camelCase2=\"camelCase2\" custom-observed-attr=\"custom\"></sub-element>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"sub-mixin-element-attr\">\n    <template>\n      <sub-mixin-element prop=\"attr\" prop2=\"attr\" prop3=\"attr\" mixin=\"5\" custom-observed-attr=\"custom\"></sub-mixin-element>\n    </template>\n  </test-fixture>\n\n  <script type=\"module\">\nimport { PropertiesMixin } from '../../lib/mixins/properties-mixin.js';\n\nclass Glar {}\nclass Blar {}\n\nclass MyElement extends PropertiesMixin(HTMLElement) {\n\n  static get properties() {\n    this._calledProperties++;\n\n    return {\n      prop: String,\n      noStomp: String,\n      id: String,\n      camelCase: String,\n      boo: Boolean,\n      num: Number,\n      glar: Glar,\n      blar: Blar\n    };\n  }\n\n  constructor() {\n    super();\n    this._propertiesChanged = sinon.spy();\n    this._tapListener = sinon.spy();\n    this._calledConstructor++;\n    this.prop = 'prop';\n    this.noStomp = 'stomped';\n  }\n\n  _deserializeValue(value, type) {\n    if (type == Glar) {\n      return 'glar';\n    }\n    return super._deserializeValue(value, type);\n  }\n\n  get noStomp() {\n    return 'noStomp';\n  }\n\n  set noStomp(value) {}\n\n  get id() {\n    return this._getProperty('id');\n  }\n\n  set id(value) {\n    this._setProperty('id', value);\n    // cannot call super cuz older browsers\n    this._propertyToAttribute('id');\n  }\n\n  connectedCallback() {\n    super.connectedCallback();\n    this._calledConnectedCallback++;\n  }\n\n  attributeChangedCallback() {\n    super.attributeChangedCallback.apply(this, arguments);\n    this._callAttributeChangedCallback++;\n  }\n\n  ready() {\n    super.ready();\n    this.addEventListener('click', (e) => this._tapListener(e));\n    this._calledReady++;\n  }\n\n}\n\nMyElement.prototype._calledConstructor = 0;\nMyElement.prototype._calledConnectedCallback = 0;\nMyElement.prototype._calledReady = 0;\nMyElement.prototype._callAttributeChangedCallback = 0;\n\nMyElement.constructor.prototype._calledProperties = 0;\n\ncustomElements.define('my-element', MyElement);\n\nwindow.MyElement = MyElement;\n\nclass SubElement extends window.MyElement {\n\n  static get observedAttributes() {\n    return ['custom-observed-attr'].concat(super.observedAttributes);\n  }\n\n  static get properties() {\n    return {\n      prop2: String,\n      camelCase2: String\n    };\n  }\n\n  constructor() {\n    super();\n    this._calledConstructor++;\n    this.prop = 'sub';\n    this.prop2 = 'prop2';\n  }\n\n  connectedCallback() {\n    super.connectedCallback();\n    this._calledConnectedCallback++;\n  }\n\n  ready() {\n    super.ready();\n    this._calledReady++;\n    this.addEventListener('click', (e) => this._tapListener(e));\n  }\n\n}\n\ncustomElements.define('sub-element', SubElement);\n\nwindow.SubElement = SubElement;\n\nfunction MyMixin(Base) {\n  return class extends Base {\n\n    static get properties() {\n      return {\n        mixin: Number\n      };\n    }\n\n    constructor() {\n      super();\n      this._calledConstructor++;\n      this.mixin = 'mixin';\n    }\n\n    connectedCallback() {\n      super.connectedCallback();\n      this._calledConnectedCallback++;\n    }\n\n    ready() {\n      super.ready();\n      this._calledReady++;\n      this.addEventListener('click', (e) => this._tapListener(e));\n    }\n\n  };\n}\n\nclass SubMixinElement extends MyMixin(window.SubElement) {\n\n  static get properties() {\n    return {\n      prop3: String,\n      camelCase: String\n    };\n  }\n\n  constructor() {\n    super();\n    this._calledConstructor++;\n    this.prop3 = 'prop3';\n  }\n\n  connectedCallback() {\n    super.connectedCallback();\n    this._calledConnectedCallback++;\n  }\n\n  ready() {\n    super.ready();\n    this._calledReady++;\n    this.addEventListener('click', (e) => this._tapListener(e));\n  }\n\n}\n\ncustomElements.define('sub-mixin-element', SubMixinElement);\n\nwindow.SubMixinElement = SubMixinElement;\n\nsuite('class extends Polymer.PropertiesMixin', function() {\n\n  let el;\n\n  setup(function() {\n    el = document.createElement('my-element');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('instanceof', function() {\n    assert.instanceOf(el, HTMLElement);\n    assert.instanceOf(el, window.MyElement);\n  });\n\n  test('lifecycle', function() {\n    assert.equal(el._calledConstructor, 1);\n    assert.equal(el._calledConnectedCallback, 1);\n    assert.equal(el._calledReady, 1);\n    assert.equal(el._callAttributeChangedCallback, 0);\n    assert.equal(el.constructor._calledProperties, 1);\n  });\n\n  test('listeners', function() {\n    el.dispatchEvent(new CustomEvent('click'));\n    assert.equal(el._tapListener.callCount, 1);\n  });\n\n  test('properties', function() {\n    assert.equal(el.prop, 'prop');\n    assert.equal(el.noStomp, 'noStomp');\n    assert.isTrue(el._propertiesChanged.calledOnce);\n    assert.deepEqual(el._propertiesChanged.args[0][0], {prop: 'prop'});\n  });\n\n  test('properties: accessor for native property', function() {\n    // old browsers with broken native properties on instances\n    // cannot pass this test.\n    if (el.hasOwnProperty('id')) {\n      this.skip();\n    }\n    el.setAttribute('id', 'yo');\n    assert.equal(el.id, 'yo');\n    el._flushProperties();\n    assert.isTrue(el._propertiesChanged.calledTwice);\n    assert.deepEqual(el._propertiesChanged.args[1][1], {id: 'yo'});\n  });\n\n  test('attributes', function() {\n    const fixtureEl = fixture('my-element-attr');\n    assert.equal(fixtureEl.prop, 'attr');\n    assert.equal(fixtureEl.camelCase, 'camelCase');\n    assert.equal(fixtureEl._callAttributeChangedCallback, 2);\n    fixtureEl.removeAttribute('prop');\n    assert.equal(fixtureEl.prop, null);\n  });\n\n  test('deserialize standard types', function() {\n    el.setAttribute('boo', '');\n    assert.equal(el.boo, true);\n    el.removeAttribute('boo');\n    assert.equal(el.boo, false);\n    el.setAttribute('prop', '1');\n    assert.equal(el.prop, '1');\n    el.setAttribute('num', '1');\n    assert.equal(el.num, 1);\n    el.setAttribute('num', '0');\n    assert.equal(el.num, 0);\n  });\n\n  test('deserialize class constructor type', function() {\n    el.setAttribute('blar', 'a');\n    assert.equal(el.blar, 'a');\n  });\n\n  test('deserialize custom type via `_deserializeValue`', function() {\n    el.setAttribute('glar', 'b');\n    assert.equal(el.glar, 'glar');\n  });\n\n  test('reflecting attributes', function() {\n    const fixtureEl = fixture('my-element-attr');\n    fixtureEl.prop = 'propValue';\n    fixtureEl._propertyToAttribute('prop');\n    assert.equal(fixtureEl.getAttribute('prop'), 'propValue');\n  });\n\n});\n\nsuite('subclass', function() {\n\n  let el;\n\n  setup(function() {\n    el = document.createElement('sub-element');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('instanceof', function() {\n    assert.instanceOf(el, HTMLElement);\n    assert.instanceOf(el, window.MyElement);\n    assert.instanceOf(el, window.SubElement);\n  });\n\n  test('lifecycle', function() {\n    assert.equal(el._calledConstructor, 2);\n    assert.equal(el._calledConnectedCallback, 2);\n    assert.equal(el._calledReady, 2);\n    assert.equal(el._callAttributeChangedCallback, 0);\n  });\n\n  test('listeners', function() {\n    el.dispatchEvent(new CustomEvent('click'));\n    assert.equal(el._tapListener.callCount, 2);\n  });\n\n  test('properties', function() {\n    assert.equal(el.prop, 'sub');\n    assert.equal(el.prop2, 'prop2');\n    assert.isTrue(el._propertiesChanged.calledOnce);\n    assert.deepEqual(el._propertiesChanged.args[0][0], {prop: 'sub', prop2: 'prop2'});\n  });\n\n  test('attributes', function() {\n    const fixtureEl = fixture('sub-element-attr');\n    assert.equal(fixtureEl.prop, 'attr');\n    assert.equal(fixtureEl.prop2, 'attr');\n    assert.equal(fixtureEl.camelCase, 'camelCase');\n    assert.equal(fixtureEl.camelCase2, 'camelCase2');\n    assert.equal(fixtureEl._callAttributeChangedCallback, 5);\n  });\n\n});\n\nsuite('mixin', function() {\n\n  let el;\n\n  setup(function() {\n    el = document.createElement('sub-mixin-element');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('instanceof', function() {\n    assert.instanceOf(el, HTMLElement);\n    assert.instanceOf(el, window.MyElement);\n    assert.instanceOf(el, window.SubElement);\n    assert.instanceOf(el, window.SubMixinElement);\n  });\n\n  test('lifecycle', function() {\n    assert.equal(el._calledConstructor, 4);\n    assert.equal(el._calledConnectedCallback, 4);\n    assert.equal(el._calledReady, 4);\n    assert.equal(el._callAttributeChangedCallback, 0);\n  });\n\n  test('listeners', function() {\n    el.dispatchEvent(new CustomEvent('click'));\n    assert.equal(el._tapListener.callCount, 4);\n  });\n\n  test('properties', function() {\n    assert.equal(el.prop, 'sub');\n    assert.equal(el.prop2, 'prop2');\n    assert.equal(el.mixin, 'mixin');\n    assert.equal(el.prop3, 'prop3');\n    assert.isTrue(el._propertiesChanged.calledOnce);\n    assert.deepEqual(el._propertiesChanged.args[0][0], {prop: 'sub', prop2: 'prop2', mixin: 'mixin', prop3: 'prop3'});\n  });\n\n  test('attributes', function() {\n    const fixtureEl = fixture('sub-mixin-element-attr');\n    assert.strictEqual(fixtureEl.prop, 'attr');\n    assert.strictEqual(fixtureEl.prop2, 'attr');\n    assert.strictEqual(fixtureEl.prop3, 'attr');\n    assert.strictEqual(fixtureEl.mixin, 5);\n    assert.equal(fixtureEl._callAttributeChangedCallback, 5);\n  });\n\n});\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/properties-changed.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n<body>\n\n<x-foo prop1=\"a\" prop2=\"b\"></x-foo>\n\n<script type=\"module\">\nimport { PropertiesChanged } from '../../lib/mixins/properties-changed.js';\nclass XFoo extends PropertiesChanged(HTMLElement) {\n  static get observedAttributes() {\n    return ['prop1', 'prop2'];\n  }\n  constructor() {\n    super();\n    this._propertiesChanged = sinon.spy();\n  }\n  connectedCallback() {\n    this._enableProperties();\n  }\n\n  attributeChangedCallback(name, old, value) {\n    if (value !== old) {\n      this._setProperty(name, value);\n    }\n  }\n\n  get prop1() {\n    return this._getProperty('prop1');\n  }\n\n  set prop1(value) {\n    this.setAttribute('prop1', value);\n  }\n\n  get prop2() {\n    return this._getProperty('prop2');\n  }\n\n  set prop2(value) {\n    this.setAttribute('prop2', value);\n  }\n}\nwindow.XFoo = XFoo;\ncustomElements.define('x-foo', XFoo);\n\nclass ShouldPropertiesChange extends PropertiesChanged(HTMLElement) {\n  constructor() {\n    super();\n    this._propertiesChanged = sinon.spy();\n  }\n\n  connectedCallback() {\n    this._enableProperties();\n    //this._flushProperties();\n  }\n\n  _shouldPropertiesChange() {\n    return true;\n  }\n}\n\ncustomElements.define('should-properties-change', ShouldPropertiesChange);\n</script>\n\n<script type=\"module\">\n\nsuite('properties-changed', function() {\n\n  test('attributes reflected to properties via upgrade', function() {\n    var el = document.querySelector('x-foo');\n    assert.equal(el.prop1, 'a');\n    assert.equal(el.prop2, 'b');\n  });\n\n  test('setting properties results in _propertiesChanged', function(done) {\n    var el = document.createElement('x-foo');\n    document.body.appendChild(el);\n    el.prop1 = 'a';\n    el.prop2 = 'b';\n    assert.equal(el._propertiesChanged.callCount, 0, '_propertiesChanged is not async');\n    setTimeout(function() {\n      assert.isTrue(el._propertiesChanged.calledOnce);\n      assert.equal(el._propertiesChanged.getCall(0).args[0].prop1, 'a');\n      assert.equal(el._propertiesChanged.getCall(0).args[0].prop2, 'b');\n      assert.equal(el._propertiesChanged.getCall(0).args[1].prop1, 'a');\n      assert.equal(el._propertiesChanged.getCall(0).args[1].prop2, 'b');\n      assert.equal(el._propertiesChanged.getCall(0).args[2].prop1, undefined);\n      assert.equal(el._propertiesChanged.getCall(0).args[2].prop2, undefined);\n      assert.equal(el.prop1, 'a');\n      assert.equal(el.prop2, 'b');\n      el.prop1 = 'aa';\n      setTimeout(function() {\n        assert.isTrue(el._propertiesChanged.calledTwice);\n        assert.equal(el._propertiesChanged.getCall(1).args[0].prop1, 'aa');\n        assert.equal(el._propertiesChanged.getCall(1).args[0].prop2, 'b');\n        assert.equal(el._propertiesChanged.getCall(1).args[1].prop1, 'aa');\n        assert.equal(el._propertiesChanged.getCall(1).args[2].prop1, 'a');\n        assert.isFalse('prop2' in el._propertiesChanged.getCall(1).args[1]);\n        assert.isFalse('prop2' in el._propertiesChanged.getCall(1).args[2]);\n        done();\n      });\n    });\n  });\n\n  test('setting attributes results in _propertiesChanged', function(done) {\n    var el = document.createElement('x-foo');\n    document.body.appendChild(el);\n    el.setAttribute('prop1', 'a');\n    el.setAttribute('prop2', 'b');\n    setTimeout(function() {\n      assert.isTrue(el._propertiesChanged.calledOnce);\n      assert.equal(el._propertiesChanged.getCall(0).args[0].prop1, 'a');\n      assert.equal(el._propertiesChanged.getCall(0).args[0].prop2, 'b');\n      assert.equal(el._propertiesChanged.getCall(0).args[1].prop1, 'a');\n      assert.equal(el._propertiesChanged.getCall(0).args[1].prop2, 'b');\n      assert.equal(el._propertiesChanged.getCall(0).args[2].prop1, undefined);\n      assert.equal(el._propertiesChanged.getCall(0).args[2].prop2, undefined);\n      assert.equal(el.prop1, 'a');\n      assert.equal(el.prop2, 'b');\n      el.setAttribute('prop1', 'aa');\n      setTimeout(function() {\n        assert.isTrue(el._propertiesChanged.calledTwice);\n        assert.equal(el._propertiesChanged.getCall(1).args[0].prop1, 'aa');\n        assert.equal(el._propertiesChanged.getCall(1).args[0].prop2, 'b');\n        assert.equal(el._propertiesChanged.getCall(1).args[1].prop1, 'aa');\n        assert.equal(el._propertiesChanged.getCall(1).args[2].prop1, 'a');\n        assert.isFalse('prop2' in el._propertiesChanged.getCall(1).args[1]);\n        assert.isFalse('prop2' in el._propertiesChanged.getCall(1).args[2]);\n        done();\n      });\n\n    });\n  });\n\n  test('shouldPropertiesChange', function(done) {\n    const el = document.createElement('should-properties-change');\n    document.body.appendChild(el);\n    assert.isTrue(el._propertiesChanged.calledOnce);\n    el._invalidateProperties();\n    setTimeout(function() {\n      assert.isTrue(el._propertiesChanged.calledTwice);\n      el._setProperty('foo', true);\n      setTimeout(function() {\n        assert.isTrue(el._propertiesChanged.calledThrice);\n        done();\n      });\n    });\n  });\n});\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/property-accessors.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n<body>\n\n<x-foo prop1=\"a\" prop2=\"b\"></x-foo>\n\n<script type=\"module\">\nimport { PropertyAccessors } from '../../lib/mixins/property-accessors.js';\nclass XFoo extends PropertyAccessors(HTMLElement) {\n  static get observedAttributes() {\n    return ['prop1', 'prop2'];\n  }\n  constructor() {\n    super();\n    this._propertiesChanged = sinon.spy();\n  }\n  connectedCallback() {\n    this._enableProperties();\n  }\n}\nXFoo.createPropertiesForAttributes();\nwindow.XFoo = XFoo;\ncustomElements.define('x-foo', XFoo);\n</script>\n\n<script type=\"module\">\n\nsuite('property-accessors', function() {\n\n  test('createPropertiesForAttributes creates accessors', function() {\n    assert.ok(Object.getOwnPropertyDescriptor(window.XFoo.prototype, 'prop1'));\n    assert.ok(Object.getOwnPropertyDescriptor(window.XFoo.prototype, 'prop2'));\n  });\n\n  test('attributes reflected to properties via upgrade', function() {\n    var el = document.querySelector('x-foo');\n    assert.equal(el.prop1, 'a');\n    assert.equal(el.prop2, 'b');\n  });\n\n  test('setting properties results in _propertiesChanged', function(done) {\n    var el = document.createElement('x-foo');\n    document.body.appendChild(el);\n    el.prop1 = 'a';\n    el.prop2 = 'b';\n    assert.equal(el._propertiesChanged.callCount, 0, '_propertiesChanged is not async');\n    setTimeout(function() {\n      assert.isTrue(el._propertiesChanged.calledOnce);\n      assert.equal(el._propertiesChanged.getCall(0).args[0].prop1, 'a');\n      assert.equal(el._propertiesChanged.getCall(0).args[0].prop2, 'b');\n      assert.equal(el._propertiesChanged.getCall(0).args[1].prop1, 'a');\n      assert.equal(el._propertiesChanged.getCall(0).args[1].prop2, 'b');\n      assert.equal(el._propertiesChanged.getCall(0).args[2].prop1, undefined);\n      assert.equal(el._propertiesChanged.getCall(0).args[2].prop2, undefined);\n      assert.equal(el.prop1, 'a');\n      assert.equal(el.prop2, 'b');\n      el.prop1 = 'aa';\n      setTimeout(function() {\n        assert.isTrue(el._propertiesChanged.calledTwice);\n        assert.equal(el._propertiesChanged.getCall(1).args[0].prop1, 'aa');\n        assert.equal(el._propertiesChanged.getCall(1).args[0].prop2, 'b');\n        assert.equal(el._propertiesChanged.getCall(1).args[1].prop1, 'aa');\n        assert.equal(el._propertiesChanged.getCall(1).args[2].prop1, 'a');\n        assert.isFalse('prop2' in el._propertiesChanged.getCall(1).args[1]);\n        assert.isFalse('prop2' in el._propertiesChanged.getCall(1).args[2]);\n        done();\n      });\n    });\n  });\n\n  test('setting attributes results in _propertiesChanged', function(done) {\n    var el = document.createElement('x-foo');\n    document.body.appendChild(el);\n    el.setAttribute('prop1', 'a');\n    el.setAttribute('prop2', 'b');\n    setTimeout(function() {\n      assert.isTrue(el._propertiesChanged.calledOnce);\n      assert.equal(el._propertiesChanged.getCall(0).args[0].prop1, 'a');\n      assert.equal(el._propertiesChanged.getCall(0).args[0].prop2, 'b');\n      assert.equal(el._propertiesChanged.getCall(0).args[1].prop1, 'a');\n      assert.equal(el._propertiesChanged.getCall(0).args[1].prop2, 'b');\n      assert.equal(el._propertiesChanged.getCall(0).args[2].prop1, undefined);\n      assert.equal(el._propertiesChanged.getCall(0).args[2].prop2, undefined);\n      assert.equal(el.prop1, 'a');\n      assert.equal(el.prop2, 'b');\n      el.setAttribute('prop1', 'aa');\n      setTimeout(function() {\n        assert.isTrue(el._propertiesChanged.calledTwice);\n        assert.equal(el._propertiesChanged.getCall(1).args[0].prop1, 'aa');\n        assert.equal(el._propertiesChanged.getCall(1).args[0].prop2, 'b');\n        assert.equal(el._propertiesChanged.getCall(1).args[1].prop1, 'aa');\n        assert.equal(el._propertiesChanged.getCall(1).args[2].prop1, 'a');\n        assert.isFalse('prop2' in el._propertiesChanged.getCall(1).args[1]);\n        assert.isFalse('prop2' in el._propertiesChanged.getCall(1).args[2]);\n        done();\n      });\n\n    });\n  });\n\n  suite('testing for deserialization of date', function() {\n    let date;\n\n    setup(function() {\n      date = new Date();\n    });\n\n    test('can handle string timestamp', function() {\n      const deserializedDate = window.XFoo.prototype._deserializeValue(String(date.getTime()), Date);\n      assert.equal(deserializedDate.getTime(), date.getTime());\n    });\n\n    test('can handle number timestamp', function() {\n      const deserializedDate = window.XFoo.prototype._deserializeValue(date.getTime(), Date);\n      assert.equal(deserializedDate.getTime(), date.getTime());\n    });\n\n    test('can handle full date', function() {\n      const deserializedDate = window.XFoo.prototype._deserializeValue(date.toString(), Date);\n      assert.equal(deserializedDate.toString(), date.toString());\n    });\n  });\n\n});\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/property-effects-elements.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\nimport { StrictBindingParser } from '../../lib/mixins/strict-binding-parser.js';\nimport { Polymer } from '../../lib/legacy/polymer-fn.js';\nimport { html } from '../../lib/utils/html-tag.js';\nimport { PolymerElement } from '../../polymer-element.js';\nimport { MutableDataBehavior } from '../../lib/legacy/mutable-data-behavior.js';\nimport { MutableData } from '../../lib/mixins/mutable-data.js';\nlet ComputingBehavior = {\n  properties: {\n    computeFromBehavior: Function\n  },\n  computeFromBehavior: function(value) {\n    return 'computed:' + value;\n  }\n};\nPolymer({\n  _template: html`\n    <div id=\"boundChild\" value=\"{{ value }}\" negvalue=\"{{!bool}}\" attrvalue\\$=\"{{attrvalue}}\" sanitize-value=\"{{sanitizeValue}}\" computedvalue=\"{{computedvalue}}\" computedvaluetwo=\"{{computedvaluetwo}}\" camel-case=\"{{value}}\" computed-inline=\"{{computeInline(value,add, divide)}}\" computed-inline2=\"{{computeInline(value, add,divide)}}\" computed-inline3=\"{{computeInline(value, add,\n                                        divide )}}\" computedattribute\\$=\"{{computeInline(value, add,divide)}}\" computedattribute2\\$=\"{{computeInline(\n                               value, add, divide)}}\" neg-computed-inline=\"{{!computeInline(value,add,divide)}}\" computed-negative-number=\"{{computeNegativeNumber(-1)}}\" computed-negative-literal=\"{{computeNegativeNumber(-A)}}\" computed-wildcard=\"{{computeWildcard(a, b.*)}}\" style\\$=\"{{boundStyle}}\" data-id\\$=\"{{dataSetId}}\" custom-event-value=\"{{customEventValue::custom}}\" custom-event-object-value=\"{{customEventObject.value::change}}\" computed-from-mixed-literals=\"{{computeFromLiterals(3, &quot;foo&quot;, bool)}}\" computed-from-pure-literals=\"{{computeFromLiterals( 3, &quot;foo&quot;)}}\" computed-from-tricky-function=\"{{\\$computeTrickyFunctionFromLiterals( 3, &quot;foo&quot;)}}\" computed-from-tricky-literals=\"{{computeFromTrickyLiterals(3, 'tricky\\\\,\\\\'zot\\\\'')}}\" computed-from-tricky-literals2=\"{{computeFromTrickyLiterals(3,&quot;tricky\\\\,'zot'&quot; )}}\" computed-from-tricky-literals3=\"{{computeFromTrickyLiterals(3,\n                                          &quot;tricky\\\\,'zot'&quot; )}}\" computed-from-no-args=\"{{computeFromNoArgs( )}}\" no-computed=\"{{foobared(noInlineComputed)}}\" compoundattr1\\$=\"{{cpnd1}}{{ cpnd2 }}{{cpnd3.prop}}{{ computeCompound(cpnd4, cpnd5, 'literalComputed')}}\" compoundattr2\\$=\"literal1 {{cpnd1}} literal2 {{cpnd2}}{{cpnd3.prop}} literal3 {{computeCompound(cpnd4, cpnd5, 'literalComputed')}} literal4\" compoundattr3\\$=\"[yes/no]: {{cpnd1}}, {{computeCompound('world', 'username ', 'Hello {0} ')}}\" computed-from-behavior=\"{{computeFromBehavior(value)}}\" computed-dynamic-fn=\"{{dynamicFn('hello', 'username')}}\">\n      Test\n      <!-- Malformed bindings to be ignored -->\n      {{really.long.identifier.in.malformed.binding.should.be.ignored]}\n      {{computeFromLiterals(3, 'really.long.literal.in.malformed.binding.should.be.ignored)]}\n      <!-- Should still parse -->\n      {{computeFromLiterals(3, 'foo', bool)}}\n      </div>\n      <x-prop id=\"boundProps\" prop1=\"{{cpnd1}}{{ cpnd2 }}{{cpnd3.prop}}{{ computeCompound(cpnd4, cpnd5, 'literalComputed')}}\" prop2=\"literal1 {{cpnd1}} literal2 {{cpnd2}}{{cpnd3.prop}} literal3 {{computeCompound(cpnd4, cpnd5, 'literalComputed')}} literal4\"></x-prop>\n      <span id=\"boundText\">{{text}}</span>\n      <span id=\"sanitizeText\">{{sanitizeText}}</span>\n      <span idtest=\"\" id=\"{{boundId}}\"></span>\n      <s id=\"computedContent\">{{computeFromTrickyLiterals(3, 'tricky\\\\,\\\\'zot\\\\'')}}</s>\n      <s id=\"computedContent2\">{{computeFromTrickyLiterals(\"(\",3)}}</s>\n      <input id=\"boundInput\" value=\"{{text::input}}\">\n      <textarea id=\"boundTextArea\" value=\"{{text::input}}\"></textarea>\n      <div id=\"compound1\">{{cpnd1}}{{cpnd2}}{{cpnd3.prop}}{{computeCompound(cpnd4, cpnd5, 'literalComputed')}}</div>\n      <div id=\"compound2\">\n        literal1 {{cpnd1}} literal2 {{cpnd2}}{{cpnd3.prop}} literal3 {{computeCompound(cpnd4, cpnd5, 'literalComputed')}} literal4\n      </div>\n      <span id=\"boundWithDash\">{{objectWithDash.binding-with-dash}}</span>\n      <script id=\"scriptWithBinding\">\n        /* eslint-disable no-unused-vars */\n        function foo() {\n          return \"We have a {{binding}} here\";\n        }\n        /* eslint-enable no-unused-vars */\n      </script>\n      <style id=\"styleWithBinding\">\n        :host {\n          content: '[[binding]]'\n        }\n      </style>\n      <span id=\"boundWithSlash\">[[objectWithSlash.binding/with/slash]]</span>\n      <span id=\"jsonContent\">[[\"Jan\", 31],[\"Feb\", 28],[\"Mar\", 31]]</span>\n      <span id=\"nonEnglishUnicode\">{{objectWithNonEnglishUnicode.商品名}}</span>\n      <span id=\"booleanTrue\">foo(field, true): {{computeWithBoolean(otherValue, true)}}</span>\n      <span id=\"booleanFalse\">foo(field, false): {{computeWithBoolean(otherValue, false)}}</span>\n`,\n\n  is: 'x-basic',\n  behaviors: [ComputingBehavior],\n\n  properties: {\n    value: {\n      type: Number,\n      observer: 'valueChanged',\n      value: 10\n    },\n    computedvalue: {\n      computed: 'computeValue(value)',\n      observer: 'computedvalueChanged'\n    },\n    computedvaluetwo: {\n      computed: 'computeValue(valuetwo)',\n      observer: 'computedvaluetwoChanged'\n    },\n    notifyingvalue: {\n      type: Number,\n      notify: true,\n      observer: 'notifyingvalueChanged'\n    },\n    notifyingvalueWithDefault: {\n      notify: true,\n      value: 99\n    },\n    computednotifyingvalue: {\n      type: Number,\n      notify: true,\n      // Naming here is to test that a private setter is not created for\n      // computed properties\n      computed: '_setComputednotifyingvalue(notifyingvalue)'\n    },\n    computedFromMultipleValues: {\n      type: Number,\n      notify: true,\n      computed: 'computeFromMultipleValues(sum1, sum2, divide)',\n      observer: 'computedFromMultipleValuesChanged'\n    },\n    camelNotifyingValue: {\n      type: Number,\n      notify: true\n    },\n    readonlyvalue: {\n      type: Number,\n      readOnly: true,\n      notify: true,\n      observer: 'readonlyvalueChanged'\n    },\n    notifierWithoutComputing: {\n      type: Number,\n      observer: 'notifierWithoutComputingChanged',\n      notify: true,\n      value: 0\n    },\n    add: {\n      value: 20\n    },\n    divide: {\n      value: 2\n    },\n    customEventValue: {\n      type: Number,\n      observer: 'customEventValueChanged'\n    },\n    customEventObject: {\n      type: Object,\n      value: function() { return {}; }\n    },\n    boundId: {\n      type: String,\n      value: 'span'\n    },\n    noObserver: {\n      observer: 'foobared'\n    },\n    noComputedProp: {\n      computed: 'foobared(noComputed)'\n    },\n    objectWithDash: {\n      type: Object\n    },\n    title: {\n      observer: 'titleChanged'\n    },\n    dynamicFn: {\n      type: Function\n    }\n  },\n\n  observers: [\n    'multipleDepChangeHandler(dep1, dep2, dep3)',\n    'customEventObjectValueChanged(customEventObject.value)',\n    'foobared(noComplexObserver.*)'\n  ],\n\n  created: function() {\n    this.observerCounts = {\n      valueChanged: 0,\n      computedvalueChanged: 0,\n      computedvaluetwoChanged: 0,\n      notifyingvalueChanged: 0,\n      readonlyvalueChanged: 0,\n      computedFromMultipleValuesChanged: 0,\n      multipleDepChangeHandler: 0,\n      customEventValueChanged: 0,\n      customEventObjectValueChanged: 0,\n      notifierWithoutComputingChanged: 0\n    };\n    this.titleChanged = sinon.spy();\n    this._dynamicFnCalled = false;\n  },\n\n  ready: function() {\n    this.isReady = true;\n  },\n\n  clearObserverCounts: function() {\n    for (var i in this.observerCounts) {\n      this.observerCounts[i] = 0;\n    }\n  },\n\n  valueChanged: function(val, old) {\n    this.observerCounts.valueChanged++;\n    assert.equal(arguments.length, 2, 'observer argument length wrong');\n    assert.equal(val, this.value, 'observer value argument wrong');\n    assert.equal(old, this._value, 'observer old argument wrong');\n    this._value = val;\n  },\n\n  computeValue: function(val) {\n    return val + 1;\n  },\n\n  computedvalueChanged: function(val, old) {\n    this.observerCounts.computedvalueChanged++;\n    assert.equal(arguments.length, 2, 'observer argument length wrong');\n    assert.equal(val, this.computedvalue, 'observer value argument wrong');\n    assert.equal(old, this._computedvalue, 'observer old argument wrong');\n    this._computedvalue = val;\n  },\n\n  computedvaluetwoChanged: function(val, old) {\n    this.observerCounts.computedvaluetwoChanged++;\n    assert.equal(arguments.length, 2, 'observer argument length wrong');\n    assert.equal(val, this.computedvaluetwo, 'observer value argument wrong');\n    assert.equal(old, this._computedvaluetwo, 'observer old argument wrong');\n    this._computedvaluetwo = val;\n  },\n\n  notifyingvalueChanged: function(val, old) {\n    this.observerCounts.notifyingvalueChanged++;\n    assert.equal(arguments.length, 2, 'observer argument length wrong');\n    assert.equal(val, this.notifyingvalue, 'observer value argument wrong');\n    assert.equal(old, this._notifyingvalue, 'observer old argument wrong');\n    this._notifyingvalue = val;\n  },\n\n  readonlyvalueChanged: function(val, old) {\n    this.observerCounts.readonlyvalueChanged++;\n    assert.equal(arguments.length, 2, 'observer argument length wrong');\n    assert.equal(val, this.readonlyvalue, 'observer value argument wrong');\n    assert.equal(old, this._readonlyvalue, 'observer old argument wrong');\n    this._readonlyvalue = val;\n  },\n\n  notifierWithoutComputingChanged: function() {\n    this.observerCounts.notifierWithoutComputingChanged++;\n  },\n\n  _setComputednotifyingvalue: function(val) {\n    return val + 2;\n  },\n\n  computeFromMultipleValues: function(sum1, sum2, divide) {\n    assert.equal(arguments.length, 3, 'observer argument length wrong');\n    assert.equal(sum1, this.sum1, 'observer value argument wrong');\n    assert.equal(sum2, this.sum2, 'observer value argument wrong');\n    assert.equal(divide, this.divide, 'observer value argument wrong');\n    if (!isNaN(sum1) && !isNaN(sum2) && !isNaN(divide)) {\n      return (sum1 + sum2) / divide;\n    }\n  },\n\n  computedFromMultipleValuesChanged: function(val, old) {\n    this.observerCounts.computedFromMultipleValuesChanged++;\n    assert.equal(arguments.length, 2, 'observer argument length wrong');\n    assert.equal(val, this.computedFromMultipleValues, 'observer value argument wrong');\n    assert.equal(old, this._computedFromMultipleValues, 'observer old argument wrong');\n    this._computedFromMultipleValues = val;\n  },\n\n  multipleDepChangeHandler: function(dep1, dep2, dep3) {\n    this.observerCounts.multipleDepChangeHandler++;\n    assert.equal(arguments.length, 3, 'observer argument length wrong');\n    assert.equal(dep1, this.dep1, 'dependency 1 argument wrong');\n    assert.equal(dep2, this.dep2, 'dependency 2 argument wrong');\n    assert.equal(dep3, this.dep3, 'dependency 3 argument wrong');\n  },\n\n  computeInline: function(value, add, divide) {\n    assert.equal(arguments.length, 3, 'observer argument length wrong');\n    assert.equal(value, this.value, 'dependency 1 argument wrong');\n    assert.equal(add, this.add, 'dependency 2 argument wrong');\n    assert.equal(divide, this.divide, 'dependency 3 argument wrong');\n    return (value + add) / divide;\n  },\n\n  customEventValueChanged: function(val, old) {\n    this.observerCounts.customEventValueChanged++;\n    assert.equal(arguments.length, 2, 'observer argument length wrong');\n    assert.equal(val, this.customEventValue, 'observer value argument wrong');\n    assert.equal(old, this._customEventValue, 'observer old argument wrong');\n    this._customEventValue = val;\n  },\n\n  customEventObjectValueChanged: function(val) {\n    this.observerCounts.customEventObjectValueChanged++;\n    assert.equal(arguments.length, 1, 'observer argument length wrong');\n    assert.equal(val, this.customEventObject.value, 'observer value argument wrong');\n    // note, no `old` argument for path observers\n  },\n\n  computeFromLiterals: function(num, str) {\n    assert.equal(num, 3);\n    assert.equal(str, 'foo');\n    return num + str;\n  },\n\n  $computeTrickyFunctionFromLiterals: function(num, str) {\n    assert.equal(num, 3);\n    assert.equal(str, 'foo');\n    return num + str;\n  },\n\n  computeFromTrickyLiterals: function(a, b) {\n    return a + b;\n  },\n\n  computeFromNoArgs: function() {\n    return 'no args!';\n  },\n\n  computeNegativeNumber: function (num) {\n    return num;\n  },\n\n  computeCompound: function(a, b, c) {\n    return '' + (c || '') + (b || '') + (a || '');\n  },\n\n  computeWildcard: function(a, bInfo) {\n    return a + (bInfo && bInfo.base ? bInfo.base.value  : 0);\n  },\n\n  computeWithBoolean: function(value, bool) {\n    return bool ? value : value * 2;\n  },\n\n  fireCustomNotifyingEvent: function() {\n    this.customNotifyingValue = 'changed!';\n    this.dispatchEvent(new CustomEvent('custom-notifying-value-changed'),\n      {value: this.customNotifyingValue});\n  },\n\n  dynamicFn: function() {}\n});\n\nclass XBasicWithStrictBindingParser extends StrictBindingParser(customElements.get('x-basic')) {\n  static get is() { return 'x-basic-strict-binding-parser'; }\n}\ncustomElements.define(XBasicWithStrictBindingParser.is, XBasicWithStrictBindingParser);\nPolymer({\n  _template: html`\n    <x-basic id=\"basic1\" value=\"{{boundvalue}}\" notifyingvalue=\"{{boundnotifyingvalue}}\" notifyingvalue-with-default=\"{{boundnotifyingvalueWithDefault}}\" camel-notifying-value=\"{{boundnotifyingvalue}}\" computedvalue=\"{{boundcomputedvalue}}\" computednotifyingvalue=\"{{boundcomputednotifyingvalue}}\" readonlyvalue=\"{{boundreadonlyvalue}}\" custom-notifying-value=\"{{boundCustomNotifyingValue}}\">\n    </x-basic>\n    <x-basic id=\"basic2\" value=\"[[boundvalue]]\" notifyingvalue=\"[[boundnotifyingvalue]]\" computedvalue=\"[[boundcomputedvalue]]\" computednotifyingvalue=\"[[boundcomputednotifyingvalue]]\">\n    </x-basic>\n    <x-basic id=\"basic3\" notifyingvalue=\"{{computedValue}}\" computedvalue=\"{{value}}\">\n    </x-basic>\n    <x-basic id=\"basic4\" notifyingvalue=\"{{!negatedValue}}\">\n    </x-basic>\n`,\n\n  is: 'x-compose',\n\n  observers: [\n    'boundvalueChanged(boundvalue)',\n    'boundnotifyingvalueChanged(boundnotifyingvalue)',\n    'boundcomputedvalueChanged(boundcomputedvalue)',\n    'boundcomputednotifyingvalueChanged(boundcomputednotifyingvalue)',\n    'boundreadonlyvalueChanged(boundreadonlyvalue)',\n    'boundCustomNotifyingValueChanged(boundCustomNotifyingValue)',\n    'boundnotifyingvalueWithDefaultChanged(boundnotifyingvalueWithDefault)'\n  ],\n\n  properties: {\n    a: {\n      value: 10\n    },\n    b: {\n      value: 20\n    },\n    computedValue: {\n      computed: 'computeComputedValue(a, b)'\n    },\n    negatedValue: {\n      value: false\n    }\n  },\n\n  created: function() {\n    this.observerCounts = {\n      boundvalueChanged: 0,\n      boundnotifyingvalueChanged: 0,\n      boundcomputedvalueChanged: 0,\n      boundcomputednotifyingvalueChanged: 0,\n      boundreadonlyvalueChanged: 0,\n      boundCustomNotifyingValueChanged: 0,\n      boundnotifyingvalueWithDefault: 0\n    };\n  },\n\n  computeComputedValue: function(a, b) {\n    return a + b;\n  },\n\n  clearObserverCounts: function() {\n    for (var i in this.observerCounts) {\n      this.observerCounts[i] = 0;\n    }\n  },\n\n  assertClientsReady: function() {\n    assert.isTrue(this.$.basic1.isReady, 'basic1 not `ready` by observer time');\n    assert.isTrue(this.$.basic2.isReady, 'basic2 element not `ready` by observer time');\n    assert.isTrue(this.$.basic3.isReady, 'basic3 element not `ready` by observer time');\n    assert.isTrue(this.$.basic4.isReady, 'basic4 element not `ready` by observer time');\n  },\n\n  boundvalueChanged: function() {\n    this.assertClientsReady();\n    this.observerCounts.boundvalueChanged++;\n  },\n\n  boundnotifyingvalueChanged: function() {\n    this.assertClientsReady();\n    this.observerCounts.boundnotifyingvalueChanged++;\n  },\n\n  boundcomputedvalueChanged: function() {\n    this.assertClientsReady();\n    this.observerCounts.boundcomputedvalueChanged++;\n  },\n\n  boundcomputednotifyingvalueChanged: function() {\n    this.assertClientsReady();\n    this.observerCounts.boundcomputednotifyingvalueChanged++;\n  },\n\n  boundreadonlyvalueChanged: function() {\n    this.assertClientsReady();\n    this.observerCounts.boundreadonlyvalueChanged++;\n  },\n\n  boundCustomNotifyingValueChanged: function() {\n    this.assertClientsReady();\n    this.observerCounts.boundCustomNotifyingValueChanged++;\n  },\n\n  boundnotifyingvalueWithDefaultChanged: function() {\n    this.assertClientsReady();\n    this.observerCounts.boundnotifyingvalueWithDefault++;\n  }\n});\nPolymer({\n  _template: html`\n    <slot name=\"drawer\"></slot>\n    <div id=\"before\"></div>\n    <x-basic id=\"basic1\" on-notifyingvalue-with-default-changed=\"handleNotify\">\n    </x-basic>\n    <div id=\"later\"></div>\n`,\n\n  is: 'x-handle-notify-event',\n\n  properties: {\n    prop: {\n      observer: 'propChanged'\n    }\n  },\n\n  created: function() {\n    this.readySpy = sinon.spy();\n    this.afterSettingProp = sinon.spy();\n    this.propChanged = sinon.spy();\n    this.handleNotify = sinon.spy(function() {\n      this.prop = 'prop';\n      this.afterSettingProp();\n    });\n  },\n\n  ready: function() {\n    this.readySpy();\n  }\n});\nPolymer({\n  is: 'x-reflect',\n  properties: {\n    reflectedobject: {\n      type: Object,\n      reflectToAttribute: true\n    },\n    reflectedarray: {\n      type: Array,\n      reflectToAttribute: true\n    },\n    reflectedNumber: {\n      type: Number,\n      reflectToAttribute: true\n    },\n    reflectedstring: {\n      type: String,\n      reflectToAttribute: true\n    },\n    reflectedboolean: {\n      type: Boolean,\n      reflectToAttribute: true\n    },\n    reflecteddate: {\n      type: Date,\n      reflectToAttribute: true\n    }\n  }\n});\nPolymer({\n  is: 'x-prop',\n  properties: {\n    prop1: {\n      value: 'default',\n      observer: 'prop1Changed'\n    },\n    prop2: {\n      value: 'default',\n      observer: function(newProp, oldProp) { return this.prop2Changed(newProp, oldProp); }\n    }\n  },\n  created: function() {\n    this.prop1Changed = sinon.spy();\n    this.prop2Changed = sinon.spy();\n  }\n});\nPolymer({\n  is: 'x-notifies1',\n  properties: {\n    notifies: {\n      notify: true\n    }\n  },\n  ready: function() {\n    this.notifies = 'readyValue';\n  }\n});\nPolymer({\n  _template: html`\n    <x-notifies1 id=\"notifies1\" notifies=\"{{shouldChange}}\"></x-notifies1>\n`,\n\n  is: 'x-notifies2',\n\n  properties: {\n    notifies: {\n      notify: true\n    }\n  }\n});\nPolymer({\n  _template: html`\n    <x-notifies2 id=\"notifies2\" notifies=\"{{shouldNotChange}}\"></x-notifies2>\n`,\n\n  is: 'x-notifies3',\n\n  properties: {\n    shouldNotChange: {\n      observer: 'shouldNotChangeChanged'\n    }\n  },\n\n  shouldNotChangeChanged: function() { }\n});\nPolymer({\n  _template: html`\n    <p>©</p>\n    <p id=\"binding\">{{myText}}</p>\n`,\n\n  is: \"x-entity-and-binding\",\n\n  properties: {\n    myText: {\n      type: String,\n      value: 'binding'\n    }\n  }\n});\nPolymer({\n  _template: html`\n    <input id=\"input\" value\\$=\"{{inputValue}}\">\n`,\n\n  is: 'x-input-value'\n});\nPolymer({\n  _template: html`\n    <div id=\"check\">{{isAttached}}</div>\n`,\n\n  is: 'x-bind-is-attached',\n\n  properties: {\n    isAttached: {\n      observer: '_isAttachedChanged'\n    }\n  },\n\n  _isAttachedChanged: function() {}\n});\nvar invocations = [];\nPolymer({\n  _template: html`\n    <x-order-of-effects id=\"child\" base=\"{{base}}\"></x-order-of-effects>\n`,\n\n  is: 'x-order-of-effects-grand-parent',\n  initializeWhenCreated: true,\n\n  properties: {\n    base: {\n      observer: '_childPropertyChanged'\n    }\n  },\n\n  _childPropertyChanged: function() {\n    invocations.push('notify');\n  }\n});\nPolymer({\n  _template: html`\n    <x-order-of-effects-child prop1=\"[[base]]\" prop2=\"[[_computedAnnotation(base)]]\"></x-order-of-effects-child>\n`,\n\n  is: 'x-order-of-effects',\n  initializeWhenCreated: true,\n\n  properties: {\n    base: {\n      type: String,\n      observer: '_observer',\n      notify: true,\n      reflectToAttribute: true\n    },\n    computed: {\n      type: String,\n      computed: '_computed(base)'\n    }\n  },\n\n  observers: ['_complexObserver(base)'],\n\n  created: function() {\n    this.invocations = invocations;\n  },\n\n  attributeChanged(name) {\n    if (name == 'base') {\n      invocations.push('reflect');\n    }\n  },\n\n  _computed: function(base) {\n    invocations.push('compute');\n    return base;\n  },\n\n  _computedAnnotation: function(base) {\n    return base;\n  },\n\n  _observer: function() {\n    invocations.push('observe');\n  },\n\n  _complexObserver: function() {\n    invocations.push('observe');\n  }\n});\nPolymer({\n  is: 'x-order-of-effects-child',\n  properties: {\n    prop1: {\n      observer: '_prop1Changed'\n    },\n    prop2: {\n      observer: '_prop2Changed'\n    }\n  },\n  _prop1Changed: function() {\n    invocations.push('propagate');\n  },\n  _prop2Changed: function() {\n    invocations.push('propagate');\n  }\n});\nvar TranslateBehavior = {\n  properties: {\n    translateMessage: {\n      type: Function,\n      computed: '_computeTranslateFn(translator)'\n    }\n  }\n};\nPolymer({\n  _template: html`\n    <div id=\"check\">[[translateMessage('Hello World.')]]</div>\n`,\n\n  is: 'x-bind-computed-property',\n  behaviors: [TranslateBehavior],\n\n  properties: {\n    translator: {\n      type: Function,\n      value: function() {\n        return function(message) {\n          return 'translated: ' + message;\n        };\n      }\n    }\n  },\n\n  _computeTranslateFn: function(translator) {\n    return function(message) {\n      return translator(message);\n    };\n  }\n});\nPolymer({\n  _template: html`\n    <div id=\"check\">[[translateMessage(message)]]</div>\n`,\n\n  is: 'x-bind-computed-property-late-translator',\n\n  properties: {\n    message: {\n      type: String,\n      value: 'Hello'\n    },\n    translateMessage: {\n      type: Function,\n      computed: '_computeTranslateFn(translator)'\n    },\n    translator: {\n      type: Function\n    }\n  },\n\n  _computeTranslateFn: function(translator) {\n    return function(message) {\n      return translator(message);\n    };\n  }\n});\nPolymer({\n  _template: html`\n    <div -u-p-c-a-s-e\\$=\"[[UPCASE]]\"></div>\n`,\n\n  is: 'x-bind-bad-attribute-name',\n\n  properties: {\n    UPCASE: {\n      type: String,\n      value: 'foo'\n    }\n  }\n});\nPolymer({\n  _template: html`\n    <template is=\"dom-if\" if=\"[[visible]]\">\n      <p>[[translateMessage('text')]]</p>\n    </template>\n`,\n\n  is: 'x-child-template-with-dynamic-fn',\n\n  properties: {\n    translateMessage: {\n      type: Function,\n      value: function () {\n        return function(str) {\n          return str;\n        };\n      }\n    },\n    visible: {\n      type: Boolean,\n      value: true\n    }\n  }\n});\nPolymer({\n  is: 'x-propagate',\n  properties: {\n    value: {\n      type: Number,\n      value: -1\n    }\n  },\n  observers: [\n    '_boundOne(value)',\n    '_boundTwo(value)'\n  ],\n  _boundOne: function(value) {\n    if (value < 0) {\n      this.value = 1;\n    }\n  },\n  _boundTwo: function(value) {\n    if (value < 0) {\n      this.value = 2;\n    }\n  }\n});\nclass XRaw extends HTMLElement {\n  constructor() {\n    super();\n    this._value = null;\n    this.valueChangedCount = 0;\n    this.valueChanged = sinon.spy();\n    this.arrayChanged = sinon.spy();\n    this.compoundChanged = sinon.spy();\n  }\n  get value() {\n    return this._value;\n  }\n  set value(value) {\n    this._value = value;\n    this.valueChanged(value);\n    this.notify();\n  }\n  get compound() {\n    return this._compound;\n  }\n  set compound(value) {\n    this._compound = value;\n    this.compoundChanged(value);\n  }\n  increment() {\n    this._value++;\n    this.notify();\n  }\n  notify() {\n    this.dispatchEvent(new CustomEvent('value-changed'));\n  }\n  set array(value) {\n    this.arrayChanged(value);\n    this.textContent = value;\n  }\n}\ncustomElements.define('x-raw', XRaw);\n\nPolymer({\n  is: 'x-polymer',\n  created: function() {\n    this.arrayChanged = sinon.spy();\n    this.compoundChanged = sinon.spy();\n  },\n  observers: ['compoundChanged(compound)'],\n  set array(value) {\n    this._array = value;\n    this.arrayChanged(value);\n  },\n  get array() {\n    return this._array;\n  }\n});\n\nPolymer({\n  _template: html`\n    <x-polymer id=\"polymer\" array=\"{{array}}\" compound=\"**{{array}}**\">{{array}}</x-polymer>\n    <x-raw id=\"raw\" array=\"{{array}}\" value=\"{{value}}\" compound=\"**{{array}}**\"></x-raw>\n`,\n\n  is: 'x-interop',\n\n  properties: {\n    value: {\n      value: 10\n    },\n    array: {\n      value: function() {\n        return [1,2,3];\n      }\n    }\n  }\n});\n\nPolymer({\n  is: 'x-template-proto',\n  _template: (function() {\n    let template = document.createElement('template');\n    template.innerHTML = '<div id=\"div\" on-click=\"clicked\">{{bound}}</div>';\n    return template;\n  })(),\n  properties: {\n    bound: {\n      value: 'yes'\n    }\n  },\n  clicked: sinon.spy()\n});\n\nlet TemplateBehavior = {\n  _template: (function() {\n    let template = document.createElement('template');\n    template.innerHTML = '<div id=\"div\" on-click=\"clicked\">{{bound}}</div>';\n    return template;\n  })(),\n  properties: {\n    bound: {\n      value: 'yes'\n    }\n  },\n  clicked: sinon.spy()\n};\n\nPolymer({\n  is: 'x-template-behavior',\n  behaviors: [TemplateBehavior]\n});\n\nPolymer({\n  _template: html`\n    <x-immutable-b b=\"[[a.b]]\" x=\"[[a.x]]\" id=\"b\"></x-immutable-b>\n`,\n\n  is: 'x-immutable-a',\n  observers: ['aChanged(a)', 'xChanged(x)'],\n\n  created() {\n    this.aChanged = sinon.spy();\n    this.xChanged = sinon.spy();\n  }\n});\nclass XImmutableB extends PolymerElement {\n  static get template() {\n    return html`\n    <x-immutable-c c=\"[[b.c]]\" x=\"[[b.x]]\" id=\"c\">\n  </x-immutable-c>\n`;\n  }\n\n  static get is() { return 'x-immutable-b'; }\n  static get observers() { return ['bChanged(b)', 'xChanged(x)']; }\n  constructor() {\n    super();\n    this.bChanged = sinon.spy();\n    this.xChanged = sinon.spy();\n  }\n}\ncustomElements.define('x-immutable-b', XImmutableB);\nPolymer({\n  is: 'x-immutable-c',\n  observers: ['cChanged(c)', 'xChanged(x)'],\n  created() {\n    this.cChanged = sinon.spy();\n    this.xChanged = sinon.spy();\n  }\n});\nPolymer({\n  _template: html`\n    <x-mutable-b b=\"[[a.b]]\" x=\"[[a.x]]\" id=\"b\"></x-mutable-b>\n`,\n\n  is: 'x-mutable-a',\n  behaviors: [MutableDataBehavior],\n  observers: ['aChanged(a)', 'xChanged(x)'],\n\n  created() {\n    this.aChanged = sinon.spy();\n    this.xChanged = sinon.spy();\n  }\n});\nclass XMutableB extends MutableData(PolymerElement) {\n  static get template() {\n    return html`\n    <x-mutable-c c=\"[[b.c]]\" x=\"[[b.x]]\" id=\"c\">\n  </x-mutable-c>\n`;\n  }\n\n  static get is() { return 'x-mutable-b'; }\n  static get observers() { return ['bChanged(b)', 'xChanged(x)']; }\n  constructor() {\n    super();\n    this.bChanged = sinon.spy();\n    this.xChanged = sinon.spy();\n  }\n}\ncustomElements.define('x-mutable-b', XMutableB);\nPolymer({\n  is: 'x-mutable-c',\n  behaviors: [MutableDataBehavior],\n  observers: ['cChanged(c)', 'xChanged(x)'],\n  created() {\n    this.cChanged = sinon.spy();\n    this.xChanged = sinon.spy();\n  }\n});\n\nclass SuperObserverElement extends PolymerElement {\n  static get is() { return 'super-observer-element'; }\n  static get properties() {\n    return {\n      prop: {\n        value: 'String',\n        observer() {\n          this.__observerCalled++;\n        }\n      }\n    };\n  }\n}\nSuperObserverElement.prototype.__observerCalled = 0;\ncustomElements.define(SuperObserverElement.is, SuperObserverElement);\n\nclass SubObserverElement extends SuperObserverElement {\n  static get is() { return 'sub-observer-element'; }\n}\ncustomElements.define(SubObserverElement.is, SubObserverElement);\n\ncustomElements.define('x-computed-ordering', class extends PolymerElement {\n  static get properties() {\n    return {\n      a: {type: Number, value: 1000},\n      // b: {type: Number, value: 100}, // Intentionally undeclared; init in ctor\n      c: {type: Number, value: 10},\n      d: {type: Number, value: 1},\n      abbcd: {computed: 'computeABBCD(a, b, bcd)', observer: 'abbcdChanged'},\n      bcd: {computed: 'computeBCD(bc, d)', observer: 'bcdChanged'},\n      bc: {computed: 'computeBC(b, c)', observer: 'bcChanged'},\n      circIn: {type: Number},\n      circA: {computed: 'computeCircA(circIn, circB)'},\n      circB: {computed: 'computeCircA(circIn, circA)'},\n\n      x: {type: Number, value: 2},\n      y: {type: Number, value: 20},\n      z: {type: Number, value: 200},\n      xy: {computed: 'computeXY(x, y)', observer: 'xyChanged'},\n      computeXY: {computed: 'computeComputeXY(z)'}\n    };\n  }\n  constructor() {\n    super();\n    this.b = 100;\n    sinon.spy(this, 'computeABBCD');\n    sinon.spy(this, 'computeBCD');\n    sinon.spy(this, 'computeBC');\n    this.abbcdChanged = sinon.spy();\n    this.bcdChanged = sinon.spy();\n    this.bcChanged = sinon.spy();\n\n    this.computeXYSpy = sinon.spy();\n    this.xyChanged = sinon.spy();\n  }\n  computeABBCD(a, b, bcd) {\n    return a + b + bcd;\n  }\n  computeBCD(bc, d) {\n    return bc + d;\n  }\n  computeBC(b, c) {\n    return b + c;\n  }\n  computeCircA(circIn, circB) {\n    return circIn + (circB || 0);\n  }\n  computeCircB(circIn, circA) {\n    return circIn + (circA || 0);\n  }\n  computeComputeXY(z) {\n    return function computeYZ(x, y) {\n      this.computeXYSpy(x, y);\n      return x + y + z;\n    };\n  }\n});\n  \nclass SVGElement extends PolymerElement {\n  static get template() {\n    return html`\n    <svg id=\"svg\" viewBox=\"[[value]]\"></svg>\n`;\n  }\n\n  static get is() { return 'svg-element'; }\n  static get properties() {\n    return {\n      value: {\n        type: String,\n        value: '0 0 50 50'\n      }\n    };\n  }\n}\ncustomElements.define(SVGElement.is, SVGElement);\n"
  },
  {
    "path": "test/unit/property-effects-template.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-element.js\"></script>\n  <script type=\"module\" src=\"../../lib/mixins/gesture-event-listeners.js\"></script>\n  <script type=\"module\" src=\"../../lib/elements/dom-if.js\"></script>\n<body>\n\n<script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nimport '../../lib/mixins/gesture-event-listeners.js';\nimport '../../lib/elements/dom-if.js';\nclass XElementChild extends PolymerElement {\n  ready() {\n    super.ready();\n    window.lifecycleOrder.log(this, 'ready');\n  }\n}\ncustomElements.define('x-element-child', XElementChild);\n</script>\n\n<dom-module id=\"x-element\">\n  <template>\n    [[prop]] - [[path]]\n    <x-element-child id=\"noBinding\" log></x-element>\n    <x-element-child id=\"hasBinding\" prop=\"{{prop}}\" path=\"{{path}}\" log></x-element>\n    <x-element-child id=\"events\" on-click=\"handleClick\" on-tap=\"handleTap\"></x-element-child>\n  </template>\n  <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nimport '../../lib/mixins/gesture-event-listeners.js';\nimport '../../lib/elements/dom-if.js';\nclass XElement extends PolymerElement {\n  static get is() { return 'x-element'; }\n  static get observers() { return ['propChanged(prop)', 'pathChanged(path)']; }\n  static get properties() { return { prop: { notify: true }, path: { notify: true } }; }\n  constructor() {\n    super();\n    this.propChanged = sinon.spy();\n    this.pathChanged = sinon.spy();\n  }\n  ready() {\n    super.ready();\n    this.readied = true;\n    window.lifecycleOrder.log(this, 'ready');\n  }\n}\ncustomElements.define('x-element', XElement);\n</script>\n</dom-module>\n\n<dom-module id=\"x-runtime\">\n  <template>\n    <!-- Main template content -->\n    <style>\n      x-element {\n        display: block;\n        border-bottom: 10px solid orange;\n      }\n    </style>\n    <x-element id=\"first\"></x-element>\n    <x-element id=\"textBinding\">[[prop]] - [[obj.path]] - [[compute(prop, obj.path)]]</x-element>\n    <x-element id=\"propBinding\" prop=\"{{prop}}\" log=\"proto\"></x-element>\n    <x-element id=\"pathBinding\" path=\"{{obj.path}}\"></x-element>\n    <x-element id=\"compoundPropBinding\" compound=\"[[prop]] - [[obj.path]] - [[compute(prop, obj.path)]]\"></x-element>\n    <x-element id=\"events\" on-click=\"handleClick\" on-tap=\"handleTap\"></x-element>\n    <template id=\"domIf\" is=\"dom-if\" if=\"[[prop]]\">\n      <x-element id=\"ifElement\" prop=\"{{prop}}\" path=\"{{obj.path}}\"></x-element>\n    </template>\n    <!-- Nested template in Shadow DOM for runtime stamping -->\n    <template id=\"templateFromShadowDom\">\n      <x-element early=\"[[earlyProp]]\" id=\"first\"></x-element>\n      <x-element id=\"events\" on-click=\"handleClick\" on-tap=\"handleTap\"></x-element>\n      <template id=\"domIf\" is=\"dom-if\" if=\"[[prop]]\">\n        <x-element id=\"ifElementSD\" prop=\"{{prop}}\" path=\"{{obj.path}}\"></x-element>\n      </template>\n      <span></span><span></span><span></span><span></span>\n      <x-element id=\"compoundPropBinding\" compound=\"[[prop]] - [[obj.path]] - [[compute(prop, obj.path)]]\"></x-element>\n      <x-element id=\"pathBinding\" path=\"{{obj.path}}\"></x-element>\n      <x-element id=\"propBinding\" prop=\"{{prop}}\" log=\"shadow\"></x-element>\n      <x-element id=\"textBinding\">[[prop]] - [[obj.path]] - [[compute(prop, obj.path)]]</x-element>\n    </template>\n  </template>\n  <!-- Template in light DOM for runtime stamping -->\n  <template id=\"templateFromLightDom\">\n    <x-element id=\"first\"></x-element>\n    <span></span><span></span><span></span><span></span>\n    <x-element id=\"compoundPropBinding\" compound=\"[[prop]] - [[obj.path]] - [[compute(prop, obj.path)]]\"></x-element>\n    <x-element id=\"pathBinding\" path=\"{{obj.path}}\"></x-element>\n    <x-element id=\"propBinding\" prop=\"{{prop}}\" log=\"light\"></x-element>\n    <x-element id=\"textBinding\">[[prop]] - [[obj.path]] - [[compute(prop, obj.path)]]</x-element>\n    <x-element id=\"events\" on-click=\"handleClick\" on-tap=\"handleTap\"></x-element>\n    <template id=\"domIf\" is=\"dom-if\" if=\"[[prop]]\">\n      <x-element id=\"ifElementLD\" prop=\"{{prop}}\" path=\"{{obj.path}}\"></x-element>\n    </template>\n  </template>\n  <template id=\"templateWithDifferentProps\">\n    <div id=\"bound\">[[otherProp]]</div>\n  </template>\n  <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nimport { GestureEventListeners } from '../../lib/mixins/gesture-event-listeners.js';\nimport '../../lib/elements/dom-if.js';\nimport { DomModule } from '../../lib/elements/dom-module.js';\nclass XRuntime extends GestureEventListeners(PolymerElement) {\n  static get is() { return 'x-runtime'; }\n  static get observers() { return ['propChanged(prop)', 'pathChanged(obj.path)']; }\n  constructor() {\n    super();\n    this.propChanged = sinon.spy();\n    this.pathChanged = sinon.spy();\n    this.prop = 'prop';\n    this.obj = {path: 'obj.path'};\n  }\n  ready() {\n    super.setAttribute('log', '');\n    super.ready();\n    window.lifecycleOrder.log(this, 'ready');\n  }\n  compute(a, b) {\n    return `[${a} - ${b}]`;\n  }\n  stampTemplateFromShadow() {\n    let dom = this._stampTemplate(this.$.templateFromShadowDom);\n    this.shadowRoot.appendChild(dom);\n    return dom;\n  }\n  stampTemplateAndSetPropFromShadow() {\n    let dom = this._stampTemplate(this.$.templateFromShadowDom);\n    this.earlyProp = 'early';\n    this.shadowRoot.appendChild(dom);\n    return dom;\n  }\n  stampTemplateFromLight() {\n    let dom = this._stampTemplate(DomModule.import(this.localName, '#templateFromLightDom'));\n    this.shadowRoot.appendChild(dom);\n    return dom;\n  }\n  stampTemplateWithDifferentProps() {\n    let dom = this._stampTemplate(DomModule.import(this.localName, '#templateWithDifferentProps'));\n    this.shadowRoot.appendChild(dom);\n    return dom;\n  }\n  stampNoAppend() {\n    return this._stampTemplate(this.$.templateFromShadowDom);\n  }\n}\ncustomElements.define('x-runtime', XRuntime);\n</script>\n</dom-module>\n\n<script type=\"module\">\n  import { PolymerElement, html } from '../../polymer-element.js';\n  customElements.define('x-runtime-nested', class extends PolymerElement {\n    static get template() {\n      return html`<template id=\"t1\">\n        <span>t1-[[prop1]]</span>\n        <template id=\"t2\">\n          <span>t2-[[prop2]]</span>\n          <template id=\"t3\">\n            <span>t3-[[prop3]]</span>\n          </template>\n        </template>\n      </template>`;\n    }\n    static get properties() {\n      return {\n        prop1: { value: 'prop1'},\n        prop2: { value: 'prop2'},\n        prop3: { value: 'prop3'}\n      };\n    }\n  });\n</script>\n\n<template id=\"custom-template\">\n  <x-special name=\"el1\" special=\"attr1\" binding=\"[[prop]]\" on-event=\"handler\"></x-special>\n  <div name=\"el2\" special=\"attr2\">\n    <div name=\"el3\" special=\"attr3\">\n      <x-special name=\"el4\" special=\"attr4\"></x-special>\n    </div>\n    <div></div><div></div><div></div>\n    <div name=\"el5\" binding=\"[[prop]]\" on-event=\"handler\"></div>\n    <template name=\"el6\">\n      <div>\n        <x-special name=\"t-el\" special=\"t-attr\" binding=\"[[prop]]\" on-event=\"handler\"></x-special>\n      </div>\n    </template>\n  </div>\n  <x-special name=\"el7\" special=\"attr5\"><x-special name=\"el8\" special=\"attr6\"></x-special></x-special>\n</template>\n<script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nimport '../../lib/mixins/gesture-event-listeners.js';\nimport '../../lib/elements/dom-if.js';\nclass XParsing extends PolymerElement {\n  static get template() { return document.getElementById('custom-template'); }\n  static _parseTemplateNodeAttribute(node, templateInfo, nodeInfo, name, value) {\n    if (name == 'special') {\n      nodeInfo.specialAttr = value;\n      node.removeAttribute('special');\n      node.setAttribute('had-special', '');\n      return true;\n    } else {\n      return super._parseTemplateNodeAttribute(node, templateInfo, nodeInfo, name, value);\n    }\n  }\n  static _parseTemplateNode(node, templateInfo, nodeInfo) {\n    let noted = super._parseTemplateNode(node, templateInfo, nodeInfo);\n    if (node.localName == 'x-special') {\n      noted = nodeInfo.specialNode = true;\n    }\n    return noted;\n  }\n  _bindTemplate(template, instanceBinding) {\n    return this.templateInfoForTesting = super._bindTemplate(template, instanceBinding);\n  }\n}\ncustomElements.define('x-parsing', XParsing);\n\nclass XEffects extends XParsing {\n  static get template() { return document.getElementById('custom-template'); }\n  static _parseTemplateNodeAttribute(node, templateInfo, nodeInfo, name, value) {\n    let noted = super._parseTemplateNodeAttribute(node, templateInfo, nodeInfo, name, value);\n    if (nodeInfo.specialAttr) {\n      this._addTemplatePropertyEffect(templateInfo, 'attr', {\n        fn(inst, property, props, oldProps, info, hasPaths, nodeList) {\n          nodeList[nodeInfo.infoIndex].specialAttr = props[property];\n        }\n      });\n    }\n    return noted;\n  }\n  static _parseTemplateNode(node, templateInfo, nodeInfo) {\n    let noted = super._parseTemplateNode(node, templateInfo, nodeInfo);\n    if (nodeInfo.specialNode) {\n      this._addTemplatePropertyEffect(templateInfo, 'node', {\n        fn(inst, property, props, oldProps, info, hasPaths, nodeList) {\n          nodeList[nodeInfo.infoIndex].specialNode = props[property];\n        }\n      });\n    }\n    return noted;\n  }\n}\ncustomElements.define('x-effects', XEffects);\n</script>\n\n<dom-module id=\"x-binding\">\n  <template>\n    <x-element id=\"standard1\" prop=\"[[prop]]\" path=\"[[obj.path]]\"></x-element>\n    <x-element id=\"custom1\" prop='[{\"a\": \"prop\", \"b\": \"prop2\"}]'></x-element>\n    <div>\n      <x-element id=\"standard2\" prop=\"[[prop]]\" path=\"[[obj.path]]\"></x-element>\n      <x-element id=\"custom2\" prop='[{\"a\": \"prop\", \"b\": \"prop2\"}]'></x-element>\n    </div>\n    <template id=\"domIf\" is=\"dom-if\" if=\"[[prop2]]\" restamp>\n      <x-element id=\"standard3\" prop=\"[[prop]]\" path=\"[[obj.path]]\"></x-element>\n      <x-element id=\"custom3\" prop='[{\"a\": \"prop\", \"b\": \"prop2\"}]'></x-element>\n    </template>\n  </template>\n  <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nimport '../../lib/mixins/gesture-event-listeners.js';\nimport '../../lib/elements/dom-if.js';\nclass XBinding extends PolymerElement {\n  static get is() { return 'x-binding'; }\n  constructor() {\n    super();\n    this.prop = true;\n    this.obj = {path: 'obj.path'};\n    this.prop2 = true;\n  }\n  static _parseBindings(text, templateInfo) {\n    if (text.slice(0,2) == '[{' && text.slice(-2) == '}]') {\n      let bindingData = JSON.parse(text.slice(1,-1));\n      let dependencies = Object.keys(bindingData).map(n=>bindingData[n]);\n      return [{dependencies, bindingData}];\n    } else {\n      return super._parseBindings(text, templateInfo);\n    }\n  }\n  static _evaluateBinding(scope, part, path, props, oldProps, hasPaths) {\n    if (part.bindingData) {\n      return Object.keys(part.bindingData)\n        .map(n => scope[part.bindingData[n]] ? n : '')\n        .filter(c => Boolean(c))\n        .join(' ');\n    } else {\n      return super._evaluateBinding(scope, part, path, props, oldProps, hasPaths);\n    }\n  }\n}\ncustomElements.define(XBinding.is, XBinding);\n</script>\n</dom-module>\n\n<script type=\"module\">\nimport {PolymerElement, html} from '../../polymer-element.js';\nimport '../../lib/mixins/gesture-event-listeners.js';\nimport '../../lib/elements/dom-if.js';\nimport {setLegacyOptimizations} from '../../lib/utils/settings.js';\n\nsuite('runtime template stamping', function() {\n\n  let el;\n\n  setup(function() {\n    window.lifecycleOrder = {\n      log(el, lifecycle) {\n        if (this.shouldLog(el)) {\n          let list = this[lifecycle] = this[lifecycle] || [];\n          list.push(this.idFor(el));\n        }\n      },\n      shouldLog(el) {\n        let host = el.getRootNode().host;\n        return (!host || this.shouldLog(host)) && el.hasAttribute('log');\n      },\n      idFor(el) {\n        let host = el.getRootNode().host;\n        host = host && host.localName !== 'x-runtime' ? host : null;\n        let id = el.getAttribute('log') || el.id;\n        return (host ? this.idFor(host) + '|' : '') + el.localName + (id ? '#' + id : '');\n      }\n    };\n    el = document.createElement('x-runtime');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  function assertStampingCorrect(el, $, type) {\n    // Text binding\n    assert.equal($.textBinding.textContent, 'prop - obj.path - [prop - obj.path]');\n    // Property binding\n    assert.equal($.propBinding.prop, 'prop');\n    assert.equal($.propBinding.propChanged.callCount, 1);\n    assert.equal($.propBinding.propChanged.firstCall.args[0], 'prop');\n    // Path binding\n    assert.equal($.pathBinding.path, 'obj.path');\n    assert.equal($.pathBinding.pathChanged.callCount, 1);\n    assert.equal($.pathBinding.pathChanged.firstCall.args[0], 'obj.path');\n    // Compound property binding\n    assert.equal($.compoundPropBinding.compound, 'prop - obj.path - [prop - obj.path]');\n    // Observers\n    assert.equal(el.propChanged.callCount, 1);\n    assert.equal(el.propChanged.firstCall.args[0], 'prop');\n    assert.equal(el.pathChanged.callCount, 1);\n    assert.equal(el.pathChanged.firstCall.args[0], 'obj.path');\n    // Event handlers\n    el.handleClick = sinon.spy();\n    el.handleTap = sinon.spy();\n    $.events.click();\n    assert.equal(el.handleClick.callCount, 1);\n    assert.equal(el.handleTap.callCount, 1);\n    // Nested dom-* template\n    $.domIf.render();\n    let ifElement = el.shadowRoot.querySelector(`#ifElement${type||''}`);\n    assert.equal(ifElement.prop, 'prop');\n    assert.equal(ifElement.path, 'obj.path');\n    // Styling correct\n    assert.equal(getComputedStyle($.textBinding).borderBottomWidth, '10px');\n  }\n\n  test('prototypical stamping', () => {\n    assertStampingCorrect(el, el.$);\n    let stamped = el.shadowRoot.querySelectorAll('x-element#first');\n    assert.equal(stamped.length, 1);\n    assert.equal(stamped[0], el.$.first);\n    // Lifecycle order correct\n    assert.deepEqual(window.lifecycleOrder.ready, [\n      'x-element#proto|x-element-child#noBinding',\n      'x-element#proto|x-element-child#hasBinding',\n      'x-element#proto',\n      'x-runtime'\n    ]);\n  });\n\n  test('runtime stamp template (from shadow dom)', () => {\n    let dom = el.stampTemplateFromShadow();\n    assertStampingCorrect(el, el.$);\n    assertStampingCorrect(el, dom.$, 'SD');\n    let stamped = el.shadowRoot.querySelectorAll('x-element#first');\n    assert.equal(stamped.length, 2);\n    assert.equal(stamped[0], el.$.first);\n    assert.equal(stamped[1], dom.$.first);\n    assert.deepEqual(window.lifecycleOrder.ready, [\n      'x-element#proto|x-element-child#noBinding',\n      'x-element#proto|x-element-child#hasBinding',\n      'x-element#proto',\n      'x-runtime',\n      'x-element#shadow|x-element-child#noBinding',\n      'x-element#shadow|x-element-child#hasBinding',\n      'x-element#shadow'\n    ]);\n  });\n\n  test('runtime stamp and remove multiple templates (from shadow dom)', () => {\n    let stamped;\n    // Stamp template\n    let dom1 = el.stampTemplateFromShadow();\n    assertStampingCorrect(el, el.$);\n    assertStampingCorrect(el, dom1.$, 'SD');\n    stamped = el.shadowRoot.querySelectorAll('x-element#first');\n    assert.equal(stamped.length, 2);\n    assert.equal(stamped[0], el.$.first);\n    assert.equal(stamped[1], dom1.$.first);\n    // Unstamp\n    el._removeBoundDom(dom1);\n    for (let n in dom1.$) {\n      assert.notOk(dom1.$[n].parentNode, null);\n    }\n    stamped = el.shadowRoot.querySelectorAll('x-element#first');\n    assert.equal(stamped.length, 1);\n    assert.equal(stamped[0], el.$.first);\n    // Stamp again\n    let dom2 = el.stampTemplateFromShadow();\n    assertStampingCorrect(el, el.$);\n    assertStampingCorrect(el, dom2.$, 'SD');\n    stamped = el.shadowRoot.querySelectorAll('x-element#first');\n    assert.equal(stamped.length, 2);\n    assert.equal(stamped[0], el.$.first);\n    assert.equal(stamped[1], dom2.$.first);\n    // Stamp again\n    let dom3 = el.stampTemplateFromShadow();\n    assertStampingCorrect(el, el.$);\n    assertStampingCorrect(el, dom2.$, 'SD');\n    assertStampingCorrect(el, dom3.$, 'SD');\n    stamped = el.shadowRoot.querySelectorAll('x-element#first');\n    assert.equal(stamped.length, 3);\n    assert.equal(stamped[0], el.$.first);\n    assert.equal(stamped[1], dom2.$.first);\n    assert.equal(stamped[2], dom3.$.first);\n    assert.deepEqual(window.lifecycleOrder.ready, [\n      'x-element#proto|x-element-child#noBinding',\n      'x-element#proto|x-element-child#hasBinding',\n      'x-element#proto',\n      'x-runtime',\n      'x-element#shadow|x-element-child#noBinding',\n      'x-element#shadow|x-element-child#hasBinding',\n      'x-element#shadow',\n      'x-element#shadow|x-element-child#noBinding',\n      'x-element#shadow|x-element-child#hasBinding',\n      'x-element#shadow',\n      'x-element#shadow|x-element-child#noBinding',\n      'x-element#shadow|x-element-child#hasBinding',\n      'x-element#shadow'\n    ]);\n    // Unstamp\n    el._removeBoundDom(dom2);\n    el._removeBoundDom(dom3);\n    for (let n in dom2.$) {\n      assert.notOk(dom1.$[n].parentNode, null);\n    }\n    for (let n in dom3.$) {\n      assert.notOk(dom1.$[n].parentNode, null);\n    }\n    stamped = el.shadowRoot.querySelectorAll('x-element#first');\n    assert.equal(stamped.length, 1);\n    assert.equal(stamped[0], el.$.first);\n  });\n\n  test('runtime stamp template and set prop before attaching (from shadow dom)', () => {\n    let dom = el.stampTemplateAndSetPropFromShadow();\n    assertStampingCorrect(el, el.$);\n    assertStampingCorrect(el, dom.$, 'SD');\n    let stamped = el.shadowRoot.querySelectorAll('x-element#first');\n    assert.equal(stamped.length, 2);\n    assert.equal(stamped[0], el.$.first);\n    assert.equal(stamped[1], dom.$.first);\n    assert.deepEqual(window.lifecycleOrder.ready, [\n      'x-element#proto|x-element-child#noBinding',\n      'x-element#proto|x-element-child#hasBinding',\n      'x-element#proto',\n      'x-runtime',\n      'x-element#shadow|x-element-child#noBinding',\n      'x-element#shadow|x-element-child#hasBinding',\n      'x-element#shadow'\n    ]);\n  });\n\n  test('runtime stamp and remove multiple templates and set prop before attaching (from shadow dom)', () => {\n    let stamped;\n    // Stamp template\n    let dom1 = el.stampTemplateAndSetPropFromShadow();\n    assertStampingCorrect(el, el.$);\n    assertStampingCorrect(el, dom1.$, 'SD');\n    stamped = el.shadowRoot.querySelectorAll('x-element#first');\n    assert.equal(stamped.length, 2);\n    assert.equal(stamped[0], el.$.first);\n    assert.equal(stamped[1], dom1.$.first);\n    // Unstamp\n    el._removeBoundDom(dom1);\n    for (let n in dom1.$) {\n      assert.notOk(dom1.$[n].parentNode, null);\n    }\n    stamped = el.shadowRoot.querySelectorAll('x-element#first');\n    assert.equal(stamped.length, 1);\n    assert.equal(stamped[0], el.$.first);\n    // Stamp again\n    let dom2 = el.stampTemplateAndSetPropFromShadow();\n    assertStampingCorrect(el, el.$);\n    assertStampingCorrect(el, dom2.$, 'SD');\n    stamped = el.shadowRoot.querySelectorAll('x-element#first');\n    assert.equal(stamped.length, 2);\n    assert.equal(stamped[0], el.$.first);\n    assert.equal(stamped[1], dom2.$.first);\n    // Stamp again\n    let dom3 = el.stampTemplateAndSetPropFromShadow();\n    assertStampingCorrect(el, el.$);\n    assertStampingCorrect(el, dom2.$, 'SD');\n    assertStampingCorrect(el, dom3.$, 'SD');\n    stamped = el.shadowRoot.querySelectorAll('x-element#first');\n    assert.equal(stamped.length, 3);\n    assert.equal(stamped[0], el.$.first);\n    assert.equal(stamped[1], dom2.$.first);\n    assert.equal(stamped[2], dom3.$.first);\n    assert.deepEqual(window.lifecycleOrder.ready, [\n      'x-element#proto|x-element-child#noBinding',\n      'x-element#proto|x-element-child#hasBinding',\n      'x-element#proto',\n      'x-runtime',\n      'x-element#shadow|x-element-child#noBinding',\n      'x-element#shadow|x-element-child#hasBinding',\n      'x-element#shadow',\n      'x-element#shadow|x-element-child#noBinding',\n      'x-element#shadow|x-element-child#hasBinding',\n      'x-element#shadow',\n      'x-element#shadow|x-element-child#noBinding',\n      'x-element#shadow|x-element-child#hasBinding',\n      'x-element#shadow'\n    ]);\n    // Unstamp\n    el._removeBoundDom(dom2);\n    el._removeBoundDom(dom3);\n    for (let n in dom2.$) {\n      assert.notOk(dom1.$[n].parentNode, null);\n    }\n    for (let n in dom3.$) {\n      assert.notOk(dom1.$[n].parentNode, null);\n    }\n    stamped = el.shadowRoot.querySelectorAll('x-element#first');\n    assert.equal(stamped.length, 1);\n    assert.equal(stamped[0], el.$.first);\n  });\n\n  test('runtime stamp template (from light dom)', () => {\n    let dom = el.stampTemplateFromLight();\n    assertStampingCorrect(el, el.$);\n    assertStampingCorrect(el, dom.$, 'LD');\n    let stamped = el.shadowRoot.querySelectorAll('x-element#first');\n    assert.equal(stamped.length, 2);\n    assert.equal(stamped[0], el.$.first);\n    assert.equal(stamped[1], dom.$.first);\n    assert.deepEqual(window.lifecycleOrder.ready, [\n      'x-element#proto|x-element-child#noBinding',\n      'x-element#proto|x-element-child#hasBinding',\n      'x-element#proto',\n      'x-runtime',\n      'x-element#light|x-element-child#noBinding',\n      'x-element#light|x-element-child#hasBinding',\n      'x-element#light'\n    ]);\n  });\n\n  test('runtime stamp and remove multiple templates (from light dom)', () => {\n    let stamped;\n    // Stamp template\n    let dom1 = el.stampTemplateFromLight();\n    assertStampingCorrect(el, el.$);\n    assertStampingCorrect(el, dom1.$, 'LD');\n    stamped = el.shadowRoot.querySelectorAll('x-element#first');\n    assert.equal(stamped.length, 2);\n    assert.equal(stamped[0], el.$.first);\n    assert.equal(stamped[1], dom1.$.first);\n    // Unstamp\n    el._removeBoundDom(dom1);\n    for (let n in dom1.$) {\n      assert.notOk(dom1.$[n].parentNode, null);\n    }\n    // Stamp again\n    let dom2 = el.stampTemplateFromLight();\n    assertStampingCorrect(el, el.$);\n    assertStampingCorrect(el, dom2.$, 'LD');\n    stamped = el.shadowRoot.querySelectorAll('x-element#first');\n    assert.equal(stamped.length, 2);\n    assert.equal(stamped[0], el.$.first);\n    assert.equal(stamped[1], dom2.$.first);\n    // Stamp again\n    let dom3 = el.stampTemplateFromLight();\n    assertStampingCorrect(el, el.$);\n    assertStampingCorrect(el, dom2.$, 'LD');\n    assertStampingCorrect(el, dom3.$, 'LD');\n    stamped = el.shadowRoot.querySelectorAll('x-element#first');\n    assert.equal(stamped.length, 3);\n    assert.equal(stamped[0], el.$.first);\n    assert.equal(stamped[1], dom2.$.first);\n    assert.equal(stamped[2], dom3.$.first);\n    assert.deepEqual(window.lifecycleOrder.ready, [\n      'x-element#proto|x-element-child#noBinding',\n      'x-element#proto|x-element-child#hasBinding',\n      'x-element#proto',\n      'x-runtime',\n      'x-element#light|x-element-child#noBinding',\n      'x-element#light|x-element-child#hasBinding',\n      'x-element#light',\n      'x-element#light|x-element-child#noBinding',\n      'x-element#light|x-element-child#hasBinding',\n      'x-element#light',\n      'x-element#light|x-element-child#noBinding',\n      'x-element#light|x-element-child#hasBinding',\n      'x-element#light'\n    ]);\n    // Unstamp\n    el._removeBoundDom(dom2);\n    el._removeBoundDom(dom3);\n    for (let n in dom2.$) {\n      assert.notOk(dom1.$[n].parentNode, null);\n    }\n    for (let n in dom3.$) {\n      assert.notOk(dom1.$[n].parentNode, null);\n    }\n    stamped = el.shadowRoot.querySelectorAll('x-element#first');\n    assert.equal(stamped.length, 1);\n    assert.equal(stamped[0], el.$.first);\n  });\n\n  function assertPropValues(el, prop, value, count) {\n    let e = el.$[prop + 'Binding'];\n    assert.equal(e[prop], value);\n    assert.equal(e[prop + 'Changed'].callCount, count);\n    assert.equal(e[prop + 'Changed'].getCall(count-1).args[0], value);\n    assert.equal(e.$.hasBinding[prop], value);\n  }\n\n  function assertAllPropValues(el, ld, sd, prop, value, count) {\n    assertPropValues(el, prop, value, count);\n    assertPropValues(ld, prop, value, count);\n    assertPropValues(sd, prop, value, count);\n  }\n\n  test('downward runtime binding', () => {\n    let sd = el.stampTemplateFromShadow();\n    let ld = el.stampTemplateFromLight();\n    assertAllPropValues(el, sd, ld, 'prop', 'prop', 1);\n    assertAllPropValues(el, sd, ld, 'path', 'obj.path', 1);\n    el.prop = 'prop+';\n    assertAllPropValues(el, sd, ld, 'prop', 'prop+', 2);\n    assertAllPropValues(el, sd, ld, 'path', 'obj.path', 1);\n    el.obj = {path: 'obj.path+'};\n    assertAllPropValues(el, sd, ld, 'prop', 'prop+', 2);\n    assertAllPropValues(el, sd, ld, 'path', 'obj.path+', 2);\n    el.set('obj.path', 'obj.path++');\n    assertAllPropValues(el, sd, ld, 'prop', 'prop+', 2);\n    assertAllPropValues(el, sd, ld, 'path', 'obj.path++', 3);\n  });\n\n  test('two-way runtime binding', () => {\n    let sd = el.stampTemplateFromShadow();\n    let ld = el.stampTemplateFromLight();\n    assertAllPropValues(el, sd, ld, 'prop', 'prop', 1);\n    assertAllPropValues(el, sd, ld, 'path', 'obj.path', 1);\n    el.$.propBinding.prop = 'prop+';\n    assertAllPropValues(el, sd, ld, 'prop', 'prop+', 2);\n    assertAllPropValues(el, sd, ld, 'path', 'obj.path', 1);\n    sd.$.propBinding.prop = 'prop++';\n    assertAllPropValues(el, sd, ld, 'prop', 'prop++', 3);\n    assertAllPropValues(el, sd, ld, 'path', 'obj.path', 1);\n    ld.$.propBinding.prop = 'prop+++';\n    assertAllPropValues(el, sd, ld, 'prop', 'prop+++', 4);\n    assertAllPropValues(el, sd, ld, 'path', 'obj.path', 1);\n    el.$.pathBinding.path = 'obj.path+';\n    assertAllPropValues(el, sd, ld, 'prop', 'prop+++', 4);\n    assertAllPropValues(el, sd, ld, 'path', 'obj.path+', 2);\n    sd.$.pathBinding.path = 'obj.path++';\n    assertAllPropValues(el, sd, ld, 'prop', 'prop+++', 4);\n    assertAllPropValues(el, sd, ld, 'path', 'obj.path++', 3);\n    ld.$.pathBinding.path = 'obj.path+++';\n    assertAllPropValues(el, sd, ld, 'prop', 'prop+++', 4);\n    assertAllPropValues(el, sd, ld, 'path', 'obj.path+++', 4);\n  });\n\n  test('accessors for non-prototypically bound properties created', () => {\n    // First element\n    let dom = el.stampTemplateWithDifferentProps();\n    el.otherProp = 'otherProp';\n    assert.equal(dom.$.bound.textContent, 'otherProp');\n    // Second element\n    let el2 = document.createElement('x-runtime');\n    document.body.appendChild(el2);\n    let dom2 = el2.stampTemplateWithDifferentProps();\n    el2.otherProp = 'otherProp';\n    assert.equal(dom2.$.bound.textContent, 'otherProp');\n    document.body.removeChild(el2);\n  });\n\n  test('prototypical stamping not affected by runtime stamping', () => {\n    assertStampingCorrect(el, el.$);\n    let stamped = el.shadowRoot.querySelectorAll('x-element#first');\n    assert.equal(stamped.length, 1);\n    assert.equal(stamped[0], el.$.first);\n    // Lifecycle order correct\n    assert.deepEqual(window.lifecycleOrder.ready, [\n      'x-element#proto|x-element-child#noBinding',\n      'x-element#proto|x-element-child#hasBinding',\n      'x-element#proto',\n      'x-runtime'\n    ]);\n  });\n\n  test('runtime stamped templates ready before append', () => {\n    const dom = el.stampNoAppend();\n    assert.isTrue(dom.querySelector('x-element').readied);\n  });\n\n});\n\nsuite('nested runtime template stamping', () => {\n\n  let el;\n\n  // Accumulates any spans that are stamped into a single ordered set; once\n  // added, a span is never removed, so we can test that updates stop happening\n  // when bound DOM is removed\n  const spans = new Set();\n  const accumulatedContent = () => {\n    Array.from(el.shadowRoot.querySelectorAll('span')).forEach(s => spans.add(s));\n    const content = [];\n    spans.forEach(e => content.push(e.textContent));\n    return content;\n  };\n\n  setup(() => {\n    el = document.createElement('x-runtime-nested');\n    document.body.appendChild(el);\n  });\n  teardown(() => {\n    document.body.removeChild(el);\n  });\n\n  test('nested stamping', () => {\n    // Stamp 1\n    const dom1 = el._stampTemplate(el.shadowRoot.querySelector('#t1'));\n    el.shadowRoot.appendChild(dom1);\n    assert.deepEqual(accumulatedContent(), ['t1-prop1']);\n    // Stamp 2\n    const dom2 = el._stampTemplate(el.shadowRoot.querySelector('#t2'));\n    el.shadowRoot.appendChild(dom2);\n    assert.deepEqual(accumulatedContent(), ['t1-prop1', 't2-prop2']);\n    // Stamp 3-1\n    const dom3_1 = el._stampTemplate(el.shadowRoot.querySelector('#t3'));\n    el.shadowRoot.appendChild(dom3_1);\n    assert.deepEqual(accumulatedContent(), ['t1-prop1', 't2-prop2', 't3-prop3']);\n    // Stamp 3_2\n    const dom3_2 = el._stampTemplate(el.shadowRoot.querySelector('#t3'));\n    el.shadowRoot.appendChild(dom3_2);\n    assert.deepEqual(accumulatedContent(), ['t1-prop1', 't2-prop2', 't3-prop3', 't3-prop3']);\n    // Stamp 3_3\n    const dom3_3 = el._stampTemplate(el.shadowRoot.querySelector('#t3'));\n    el.shadowRoot.appendChild(dom3_3);\n    assert.deepEqual(accumulatedContent(), ['t1-prop1', 't2-prop2', 't3-prop3', 't3-prop3', 't3-prop3']);\n    // Modify all\n    el.setProperties({\n      prop1: el.prop1 + '*',\n      prop2: el.prop2 + '*',\n      prop3: el.prop3 + '*'\n    });\n    assert.deepEqual(accumulatedContent(), ['t1-prop1*', 't2-prop2*', 't3-prop3*', 't3-prop3*', 't3-prop3*']);\n    // Remove 3-1 & modify all\n    el._removeBoundDom(dom3_1);\n    el.setProperties({\n      prop1: el.prop1 + '*',\n      prop2: el.prop2 + '*',\n      prop3: el.prop3 + '*'\n    });\n    assert.deepEqual(accumulatedContent(), ['t1-prop1**', 't2-prop2**', 't3-prop3*', 't3-prop3**', 't3-prop3**']);\n    // Remove 3-3 & modify all\n    el._removeBoundDom(dom3_3);\n    el.setProperties({\n      prop1: el.prop1 + '*',\n      prop2: el.prop2 + '*',\n      prop3: el.prop3 + '*'\n    });\n    assert.deepEqual(accumulatedContent(), ['t1-prop1***', 't2-prop2***', 't3-prop3*', 't3-prop3***', 't3-prop3**']);\n    // Stamp 3-4\n    const dom3_4 = el._stampTemplate(el.shadowRoot.querySelector('#t3'));\n    el.shadowRoot.appendChild(dom3_4);\n    assert.deepEqual(accumulatedContent(), ['t1-prop1***', 't2-prop2***', 't3-prop3*', 't3-prop3***', 't3-prop3**', 't3-prop3***']);\n    // Modify all\n    el.setProperties({\n      prop1: el.prop1 + '*',\n      prop2: el.prop2 + '*',\n      prop3: el.prop3 + '*'\n    });\n    assert.deepEqual(accumulatedContent(), ['t1-prop1****', 't2-prop2****', 't3-prop3*', 't3-prop3****', 't3-prop3**', 't3-prop3****']);\n  });\n});\n\nsuite('template parsing hooks', () => {\n\n  test('custom parsing', () => {\n    let el = document.createElement('x-parsing');\n    document.body.appendChild(el);\n    let templateInfo = el.templateInfoForTesting;\n    let nodeInfoList = templateInfo.nodeInfoList;\n    let nodeList = templateInfo.nodeList;\n    // The node order is depth-first bottom up but not a guarantee or generally\n    // important; as such, just ensure all expected nodes are there, then\n    // loop to\n    assert.sameMembers(nodeList.map(e=>e.getAttribute('name')),\n      ['el1', 'el2', 'el3', 'el4', 'el5', 'el6', 'el7', 'el8']);\n    for (let i=0; i<nodeList.length; i++) {\n      let node = nodeList[i];\n      let nodeInfo = nodeInfoList[i];\n      let templateNodeInfo;\n      switch (node.getAttribute('name')) {\n        case 'el1':\n          assert.equal(nodeInfo.specialNode, true);\n          assert.equal(nodeInfo.specialAttr, 'attr1');\n          assert.equal(nodeInfo.bindings.length, 1);\n          assert.equal(nodeInfo.events.length, 1);\n          break;\n        case 'el2':\n          assert.equal(nodeInfo.specialAttr, 'attr2');\n          break;\n        case 'el3':\n          assert.equal(nodeInfo.specialAttr, 'attr3');\n          break;\n        case 'el4':\n          assert.equal(nodeInfo.specialNode, true);\n          assert.equal(nodeInfo.specialAttr, 'attr4');\n          break;\n        case 'el5':\n          assert.equal(nodeInfo.bindings.length, 1);\n          assert.equal(nodeInfo.events.length, 1);\n          break;\n        case 'el6':\n          assert.isOk(nodeInfo.templateInfo);\n          assert.equal(nodeInfo.templateInfo.nodeInfoList.length, 1);\n          templateNodeInfo = nodeInfo.templateInfo.nodeInfoList[0];\n          assert.equal(templateNodeInfo.bindings.length, 1);\n          assert.equal(templateNodeInfo.events.length, 1);\n          assert.equal(templateNodeInfo.specialAttr, 't-attr');\n          assert.equal(templateNodeInfo.specialNode, true);\n          break;\n        case 'el7':\n          assert.equal(nodeInfo.specialNode, true);\n          assert.equal(nodeInfo.specialAttr, 'attr5');\n          break;\n        case 'el8':\n          assert.equal(nodeInfo.specialNode, true);\n          assert.equal(nodeInfo.specialAttr, 'attr6');\n          break;\n        default:\n          throw new Error('unexpected node was recorded');\n      }\n    }\n  });\n\n  test('custom template effects', () => {\n    let el = document.createElement('x-effects');\n    document.body.appendChild(el);\n\n    assert.equal(Array.from(el.shadowRoot.querySelectorAll('x-special')).length, 4);\n    Array.from(el.shadowRoot.querySelectorAll('x-special')).forEach(e => {\n      assert.notOk(e.isSpecialNode);\n    });\n    el.node = 'node!';\n    Array.from(el.shadowRoot.querySelectorAll('x-special')).forEach(e => {\n      assert.equal(e.specialNode, 'node!');\n    });\n\n    assert.equal(Array.from(el.shadowRoot.querySelectorAll('[had-special]')).length, 6);\n    Array.from(el.shadowRoot.querySelectorAll('[had-special]')).forEach(e => {\n      assert.notOk(e.hasSpecialAttr);\n    });\n    el.attr = 'attr!';\n    Array.from(el.shadowRoot.querySelectorAll('[had-special]')).forEach(e => {\n      assert.equal(e.specialAttr, 'attr!');\n    });\n    document.body.removeChild(el);\n  });\n\n  test('custom template binding', () => {\n    let el = document.createElement('x-binding');\n    document.body.appendChild(el);\n    el.$.domIf.render();\n    assert.equal(el.$.standard1.prop, true);\n    assert.equal(el.$.standard2.prop, true);\n    assert.equal(el.shadowRoot.querySelector('#standard3').prop, true);\n    assert.equal(el.$.standard1.path, 'obj.path');\n    assert.equal(el.$.standard2.path, 'obj.path');\n    assert.equal(el.shadowRoot.querySelector('#standard3').path, 'obj.path');\n    assert.equal(el.$.custom1.prop, 'a b');\n    assert.equal(el.$.custom2.prop, 'a b');\n    assert.equal(el.shadowRoot.querySelector('#custom3').prop, 'a b');\n    el.prop = false;\n    assert.equal(el.$.standard1.prop, false);\n    assert.equal(el.$.standard2.prop, false);\n    assert.equal(el.shadowRoot.querySelector('#standard3').prop, false);\n    assert.equal(el.$.standard1.path, 'obj.path');\n    assert.equal(el.$.standard2.path, 'obj.path');\n    assert.equal(el.shadowRoot.querySelector('#standard3').path, 'obj.path');\n    assert.equal(el.$.custom1.prop, 'b');\n    assert.equal(el.$.custom2.prop, 'b');\n    assert.equal(el.shadowRoot.querySelector('#custom3').prop, 'b');\n    el.prop = true;\n    assert.equal(el.$.standard1.prop, true);\n    assert.equal(el.$.standard2.prop, true);\n    assert.equal(el.shadowRoot.querySelector('#standard3').prop, true);\n    assert.equal(el.$.standard1.path, 'obj.path');\n    assert.equal(el.$.standard2.path, 'obj.path');\n    assert.equal(el.shadowRoot.querySelector('#standard3').path, 'obj.path');\n    assert.equal(el.$.custom1.prop, 'a b');\n    assert.equal(el.$.custom2.prop, 'a b');\n    assert.equal(el.shadowRoot.querySelector('#custom3').prop, 'a b');\n    document.body.removeChild(el);\n  });\n});\n\nsuite('textarea placeholder bug', function() {\n  class PlaceholderBase extends PolymerElement {\n    static get template() {\n      return html`<textarea id=\"textarea\" placeholder=\"[[value]]\"></textarea>`;\n    }\n    static get properties() {\n      return {value: {type: String}};\n    }\n  }\n  test('placeholder binding does not leak to textContent', function() {\n    customElements.define('placeholder-duplicate', class extends PlaceholderBase {});\n    const el = document.createElement('placeholder-duplicate');\n    document.body.appendChild(el);\n    const textarea = el.$.textarea;\n    el.value = 'before';\n    textarea.value = 'Hello!';\n    el.value = 'after';\n    assert.equal(textarea.value, 'Hello!');\n  });\n  suite('legacyOptimizations', function() {\n    suiteSetup(function() {\n      setLegacyOptimizations(true);\n    });\n    suiteTeardown(function() {\n      setLegacyOptimizations(false);\n    });\n    test('textarea placeholder binding works with legacyOptimizations', function() {\n      customElements.define('placeholder-bug', class extends PlaceholderBase {});\n      const el = document.createElement('placeholder-bug');\n      document.body.appendChild(el);\n      assert.doesNotThrow(() => {el.value = 'bar';});\n    });\n  });\n});\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/property-effects.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n  <script type=\"module\" src=\"./property-effects-elements.js\"></script>\n<body>\n<dom-repeat id=\"class-repeat\" items='[\"class1\", \"class2\"]'>\n  <template>\n    <div class$=[[item]] clazz$=\"[[item]]\">[[item]]</div>\n  </template>\n</dom-repeat>\n\n<script type=\"module\">\nimport './property-effects-elements.js';\nimport { Polymer, html } from '../../polymer-legacy.js';\nimport { setSanitizeDOMValue, sanitizeDOMValue, getSanitizeDOMValue, setLegacyWarnings, legacyUndefined, setLegacyUndefined, setOrderedComputed, orderedComputed } from '../../lib/utils/settings.js';\nimport { PropertyEffects } from '../../lib/mixins/property-effects.js';\nimport { flush } from '../../lib/utils/flush.js';\n\nsetLegacyUndefined(Boolean(window.location.search.match('legacyUndefined')));\nsetOrderedComputed(Boolean(window.location.search.match('orderedComputed')));\n\nsuite('single-element binding effects', function() {\n\n  var el;\n\n  setup(function() {\n    el = document.createElement('x-basic');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('undefined input value', function() {\n    assert.equal(el.$.boundInput.value, '', 'undefined input value not blank');\n    el.text = 'this is a test';\n    assert.equal(el.$.boundInput.value, 'this is a test', 'binding to input didn\\'t go');\n    el.text = undefined;\n    assert.equal(el.$.boundInput.value, '', 'undefined input value not blank');\n  });\n\n  test('undefined textarea value', function() {\n    assert.equal(el.$.boundTextArea.value, '', 'undefined textarea value not blank');\n    el.text = 'this is a test';\n    assert.equal(el.$.boundTextArea.value, 'this is a test', 'binding to textarea didn\\'t go');\n    el.text = undefined;\n    assert.equal(el.$.boundTextArea.value, '', 'undefined textarea value not blank');\n  });\n\n  test('id is bindable', function() {\n    assert.equal(el.root.querySelector('span[idtest]').id, 'span', 'id bound to <span> not found');\n  });\n\n  test('textContent binding updates', function() {\n    el.text = 'this is a test';\n    assert.equal(el.$.boundText.textContent, 'this is a test', 'Value not propagated to textContent');\n  });\n\n  test('textContent binding to undefined is empty string', function() {\n    el.text = 'this is a test';\n    el.text = undefined;\n    assert.equal(el.$.boundText.textContent, '', 'undefined bound to textContent should be empty string');\n  });\n\n  test('textContent binding to null is empty string', function() {\n    el.text = null;\n    assert.equal(el.$.boundText.textContent, '', 'null bound to textContent should be empty string');\n  });\n\n  test('textContent binding to zero is empty correct', function() {\n    el.text = 0;\n    assert.equal(el.$.boundText.textContent, '0', 'zero bound to textContent should be empty string');\n  });\n\n  test('camel-case binding updates', function() {\n    el.value = 41;\n    assert.equal(el.$.boundChild.camelCase, 41, 'Value not propagated to camelCase property');\n  });\n\n  test('annotation binding updates', function() {\n    el.value = 42;\n    assert.equal(el.$.boundChild.value, 42, 'Value not propagated to bound child');\n  });\n\n  test('negated annotation binding updates', function() {\n    el.bool = true;\n    assert.equal(el.$.boundChild.negvalue, false, 'Value not negated');\n    el.bool = false;\n    assert.equal(el.$.boundChild.negvalue, true, 'Value not negated');\n  });\n\n  test('observer called', function() {\n    assert.equal(el.observerCounts.valueChanged, 1, 'observer not called once for default value at configure');\n    el.value = 43;\n    assert.equal(el.observerCounts.valueChanged, 2, 'observer not called after property change');\n  });\n\n  test('observer called only once for null', function() {\n    el.clearObserverCounts();\n    assert.equal(el.observerCounts.valueChanged, 0);\n    el.value = {};\n    assert.equal(el.observerCounts.valueChanged, 1);\n    el.value = null;\n    assert.equal(el.observerCounts.valueChanged, 2);\n    el.value = null;\n    assert.equal(el.observerCounts.valueChanged, 2);\n    el.value = {};\n    assert.equal(el.observerCounts.valueChanged, 3);\n    el.value = null;\n    assert.equal(el.observerCounts.valueChanged, 4);\n    el.value = null;\n    assert.equal(el.observerCounts.valueChanged, 4);\n  });\n\n  test('computed value updates', function() {\n    el.value = 44;\n    assert.equal(el.computedvalue, 45, 'Computed value not correct');\n    assert.equal(el.$.boundChild.computedvalue, 45, 'Computed value not propagated to bound child');\n  });\n\n  test('computed value readOnly from imperative set', function() {\n    el.value = 44;\n    // Should have no effect\n    el.computedvalue = 99;\n    assert.equal(el.computedvalue, 45, 'Computed value not correct');\n    assert.equal(el.$.boundChild.computedvalue, 45, 'Computed value not propagated to bound child');\n  });\n\n  test('computed values to same method updates', function() {\n    el.value = 44;\n    el.valuetwo = 144;\n    assert.equal(el.computedvalue, 45, 'Computed value not correct');\n    assert.equal(el.computedvaluetwo, 145, 'Computed value not correct');\n    assert.equal(el.$.boundChild.computedvalue, 45, 'Computed value not propagated to bound child');\n  });\n\n  test('computed value using computing fn from behavior', function() {\n    el.value = 44;\n    assert.equal(el.$.boundChild.computedFromBehavior, 'computed:44');\n    el.computeFromBehavior = function(value) {\n      return 'new:' + value;\n    };\n    assert.equal(el.$.boundChild.computedFromBehavior, 'new:44');\n  });\n\n  test('notification sent', function() {\n    var notified = 0;\n    el.addEventListener('notifyingvalue-changed', function(e) {\n      assert.equal(e.detail.value, 45);\n      notified++;\n    });\n    el.addEventListener('camel-notifying-value-changed', function(e) {\n      assert.equal(e.detail.value, 45);\n      notified++;\n    });\n    el.notifyingvalue = 45;\n    el.camelNotifyingValue = 45;\n    assert.equal(notified, 2, 'Notification events not sent');\n  });\n\n  test('computed observer called', function() {\n    el.clearObserverCounts();\n    el.value = 46;\n    assert.equal(el.observerCounts.computedvalueChanged, 1, 'observer not called');\n  });\n\n  test('NaN does not loop observers', function() {\n    el.clearObserverCounts();\n    el.addEventListener('notifierwithoutcomputing-changed', function() {\n      if (el.observerCounts.notifierWithoutComputingChanged >= 3) {\n        throw new Error('infinite loop!');\n      }\n    });\n    el.notifierWithoutComputing = NaN;\n    assert.equal(el.observerCounts.notifierWithoutComputingChanged, 1,\n                 'NaN was not handled as expected');\n  });\n\n\n  test('computed notification sent', function() {\n    var notified = 0;\n    el.addEventListener('computednotifyingvalue-changed', function(e) {\n      assert.equal(e.detail.value, 49);\n      notified++;\n    });\n    el.notifyingvalue = 47;\n    assert.equal(notified, 1, 'Notification event not sent');\n  });\n\n  test('computed property with multiple dependencies', function() {\n    var notified = 0;\n    el.addEventListener('computed-from-multiple-values-changed', function() {\n      notified++;\n    });\n    el.sum1 = 10;\n    el.sum2 = 20;\n    el.divide = 2;\n    assert.equal(el.computedFromMultipleValues, 15, 'Computed value wrong');\n    assert.equal(notified, 1, 'Notification event not sent');\n    assert.equal(el.observerCounts.computedFromMultipleValuesChanged, 1, 'observer not called');\n  });\n\n  test('computed annotation with literals', function() {\n    el.bool = true;\n    assert.equal(el.$.boundChild.computedFromMixedLiterals, '3foo', 'Wrong result from mixed literal arg computation');\n    assert.equal(el.$.boundChild.computedFromPureLiterals, '3foo', 'Wrong result from pure literal arg computation');\n    assert.equal(el.$.boundChild.computedFromTrickyFunction, '3foo', 'Wrong result from tricky function with pure literal arg computation');\n    assert.equal(el.$.boundChild.computedFromTrickyLiterals, '3tricky,\\'zot\\'', 'Wrong result from tricky literal arg computation');\n    assert.equal(el.$.boundChild.computedFromTrickyLiterals2, '3tricky,\\'zot\\'', 'Wrong result from tricky literal arg computation');\n    assert.equal(el.$.boundChild.computedFromTrickyLiterals3, '3tricky,\\'zot\\'', 'Wrong result from tricky literal arg computation');\n    assert.equal(el.$.computedContent.textContent, '3tricky,\\'zot\\'', 'Wrong textContent from tricky literal arg computation');\n    assert.equal(el.$.computedContent2.textContent, '(3', 'Wrong textContent from tricky literal arg computation');\n  });\n\n  test('computed annotation with no args', function() {\n    assert.equal(el.$.boundChild.computedFromNoArgs, 'no args!', 'Wrong content when computed has no args');\n  });\n\n  test('no read-only observer called with assignment', function() {\n    el.readonlyvalue = 46;\n    assert.equal(el.observerCounts.readonlyvalueChanged, 0, 'observer should not be called for readOnly prop assignment');\n  });\n\n  test('read-only observer called with _setReadonlyvalue', function() {\n    el._setReadonlyvalue(46);\n    assert.equal(el.observerCounts.readonlyvalueChanged, 1, 'observer should be called');\n    assert(el.readonlyvalue == 46, 'value should be changed but was not');\n  });\n\n  test('no read-only notification sent with assignment', function() {\n    var notified = 0;\n    el.addEventListener('readonlyvalue-changed', function() {\n      notified++;\n    });\n    el.readonlyvalue = 47;\n    assert.equal(notified, 0, 'Notification should not be called for readOnly prop assignment');\n  });\n\n  test('read-only notification sent with _setReadonlyvalue', function() {\n    var notified = 0;\n    el.addEventListener('readonlyvalue-changed', function(e) {\n      assert.equal(e.detail.value, 47);\n      notified++;\n    });\n    el._setReadonlyvalue(47);\n    assert.equal(notified, 1, 'Notification event not sent');\n  });\n\n  test('multiple dependency observer called once', function() {\n    el.setProperties({\n      dep1: true,\n      dep2: {},\n      dep3: 42\n    });\n    assert.equal(el.observerCounts.multipleDepChangeHandler, 1, 'observer not called once');\n  });\n\n  test('setProperties does not set readOnly by default', function() {\n    assert.equal(el.observerCounts.valueChanged, 1);\n    assert.equal(el.observerCounts.readonlyvalueChanged, 0);\n    el.setProperties({\n      value: 'shouldChange',\n      nofx: 'shouldChange',\n      readonlyvalue: 'shouldNotChange'\n    });\n    assert.equal(el.value, 'shouldChange');\n    assert.equal(el.nofx, 'shouldChange');\n    assert.equal(el.readonlyvalue, undefined);\n    assert.equal(el.observerCounts.valueChanged, 2);\n    assert.equal(el.observerCounts.readonlyvalueChanged, 0);\n  });\n\n  test('setProperties sets readOnly using `setPrivate` arg', function() {\n    assert.equal(el.observerCounts.valueChanged, 1);\n    assert.equal(el.observerCounts.readonlyvalueChanged, 0);\n    el.setProperties({\n      value: 'shouldChange',\n      nofx: 'shouldChange',\n      readonlyvalue: 'shouldChange'\n    }, true);\n    assert.equal(el.value, 'shouldChange');\n    assert.equal(el.nofx, 'shouldChange');\n    assert.equal(el.readonlyvalue, 'shouldChange');\n    assert.equal(el.observerCounts.valueChanged, 2);\n    assert.equal(el.observerCounts.readonlyvalueChanged, 1);\n  });\n\n  test('annotated computed property', function() {\n    el.value = 20;\n    el.add = 40;\n    el.divide = 3;\n    assert.equal(el.$.boundChild.computedInline, 20, 'computedInline not correct');\n    assert.equal(el.$.boundChild.computedInline2, 20, 'computedInline2 not correct');\n    assert.equal(el.$.boundChild.computedInline3, 20, 'computedInline3 not correct');\n    assert.equal(el.$.boundChild.negComputedInline, false, 'negComputedInline not correct');\n  });\n\n  test('annotated computed attribute', function() {\n    el.value = 20;\n    el.add = 40;\n    el.divide = 3;\n    assert.equal(el.$.boundChild.getAttribute('computedattribute'), 20, 'computed attribute not correct');\n    assert.equal(el.$.boundChild.getAttribute('computedattribute2'), 20, 'computed attribute not correct');\n  });\n\n  test('annotated style attribute binding', function() {\n    el.boundStyle = 'padding: 37px;';\n    assert.equal(getComputedStyle(el.$.boundChild).paddingTop, '37px', 'style attribute binding not correct');\n  });\n\n  test('annotated dataset attribute binding', function() {\n    if (el.$.boundChild.datast) {  // IE10, sigh\n      el.dataSetId = 'yeah';\n      assert.equal(el.$.boundChild.dataset.id, 'yeah', 'dataset.id dataset property not set correctly');\n      assert.equal(el.$.boundChild.getAttribute('data-id'), 'yeah', 'data-id attribute not set correctly');\n    }\n  });\n\n  test('custom notification event to property', function() {\n    el.$.boundChild.customEventValue = 42;\n    el.fire('custom', null, {node: el.$.boundChild});\n    assert.equal(el.customEventValue, 42, 'custom bound property incorrect');\n    assert.equal(el.observerCounts.customEventValueChanged, 1, 'custom bound property observer not called');\n  });\n\n  test('custom notification event to path', function() {\n    el.clearObserverCounts();\n    el.$.boundChild.customEventObjectValue = 84;\n    el.$.boundChild.dispatchEvent(new Event('change'));\n    assert.equal(el.customEventObject.value, 84, 'custom bound path incorrect');\n    assert.equal(el.observerCounts.customEventObjectValueChanged, 1, 'custom bound path observer not called');\n  });\n\n  test('custom notification bubbling event to property', function() {\n    const child = document.createElement('div');\n    el.$.boundChild.appendChild(child);\n\n    el.$.boundChild.customEventValue = 42;\n    child.dispatchEvent(new Event('custom', {bubbles: true}));\n    assert.equal(el.customEventValue, 42, 'custom bound property incorrect');\n    assert.equal(el.observerCounts.customEventValueChanged, 1, 'custom bound property observer not called');\n  });\n\n  test('computed property with negative number', function() {\n    assert.equal(el.$.boundChild.computedNegativeNumber, -1);\n  });\n\n  test('computed property with negative literal', function() {\n    assert.equal(el.$.boundChild.computedNegativeLiteral, undefined);\n  });\n\n  test('computed binding with wildcard', function() {\n    el.a = 5;\n    el.b = {value: 10};\n    assert.equal(el.$.boundChild.computedWildcard, 15);\n  });\n\n  test('binding with dash', function() {\n    el.objectWithDash = {\n      'binding-with-dash': 'yes'\n    };\n    assert.equal(el.$.boundWithDash.textContent, 'yes');\n  });\n\n  test('class attribute without template scope not erased', function() {\n    var el = document.querySelector('.class1');\n    assert.notEqual(el, null, 'class without template scope is undefined');\n    var el2 = document.querySelector('.class2');\n    assert.notEqual(el2, null, 'class without template scope is undefined');\n  });\n\n\n  test('property effect for native property (title)', function() {\n    // NOTE: This will FAIL on browser on which `title` is an own property so\n    // just let this pass.\n    if (document.createElement('div').hasOwnProperty('title')) {\n      this.skip();\n    }\n    assert.isTrue(el.titleChanged.notCalled);\n    el.title = 'a title';\n    assert.isTrue(el.titleChanged.calledOnce);\n    assert.equal(el.titleChanged.firstCall.args[0], 'a title');\n  });\n\n  test('property effect added at instance time', function() {\n    el.earlyBoundObserver = sinon.spy();\n    el.lateBoundObserver = sinon.spy();\n    el.earlyBound = 'early';\n    el._createPropertyObserver('earlyBound', 'earlyBoundObserver');\n    el._createPropertyObserver('lateBound', 'lateBoundObserver');\n    el._flushProperties();\n    el.lateBound = 'late';\n    assert.equal(el.earlyBound, 'early');\n    assert.equal(el.earlyBoundObserver.callCount, 1);\n    assert.equal(el.earlyBoundObserver.firstCall.args[0], 'early');\n    assert.equal(el.lateBound, 'late');\n    assert.equal(el.lateBoundObserver.callCount, 1);\n    assert.equal(el.lateBoundObserver.firstCall.args[0], 'late');\n  });\n\n  test('does not parse bindings inside <script>', function() {\n    assert.include(el.$.scriptWithBinding.textContent, \"{{binding}}\");\n  });\n\n  test('does not parse bindings inside <style>', function() {\n    var style = el.shadowRoot.querySelector('style');\n    // native shadow dom\n    if (style) {\n      assert.include(style.textContent, \"[[binding]]\");\n    // shady dom\n    } else {\n      assert.include(document.querySelector('[scope=\"x-basic\"]').textContent, \"[[binding]]\");\n    }\n  });\n\n  test('only calls dynamic functions once', function() {\n    el.dynamicFn = function() {\n      assert.isFalse(this._dynamicFnCalled);\n      this._dynamicFnCalled = true;\n    };\n  });\n\n  suite('observer inheritance', function() {\n    setup(function() {\n      el = document.createElement('sub-observer-element');\n      document.body.appendChild(el);\n    });\n\n    test('does not invoke observer twice', function() {\n      assert.equal(el.__observerCalled, 1);\n    });\n  });\n\n  suite('automated attribute capitalization detection', function() {\n    let el;\n\n    setup(function() {\n      el = document.createElement('svg-element');\n      document.body.appendChild(el);\n    });\n\n    teardown(function() {\n      document.body.removeChild(el);\n    });\n\n    test('can handle capitalized HTML attribute', function() {\n      assert.equal(el.$.svg.getAttribute('viewBox'), el.value);\n    });\n  });\n\n  suite('can work with strict binding parser', function() {\n    setup(function() {\n      document.body.removeChild(el);\n      el = document.createElement('x-basic-strict-binding-parser');\n      document.body.appendChild(el);\n    });\n\n    test('binding with slash', function() {\n      el.objectWithSlash = {\n        'binding/with/slash': 'yes'\n      };\n      assert.equal(el.$.boundWithSlash.textContent, 'yes');\n    });\n\n    test('json should not be a binding', function() {\n      assert.equal(el.$.jsonContent.textContent, '[[\"Jan\", 31],[\"Feb\", 28],[\"Mar\", 31]]');\n    });\n\n    test('binding with non-English unicode', function() {\n      el.objectWithNonEnglishUnicode = {\n        商品名: 'yes'\n      };\n      assert.equal(el.$.nonEnglishUnicode.textContent, 'yes');\n    });\n\n    test('binding with booleans', function() {\n      el.otherValue = 10;\n      assert.equal(el.$.booleanTrue.textContent, 'foo(field, true): 10');\n      assert.equal(el.$.booleanFalse.textContent, 'foo(field, false): 20');\n    });\n\n    suite('equivalent behavior as regex', function() {\n      // Loop over the suite \"single-element binding effects\" (parent of the parent of this suite)\n      // And make sure that the tests there also pass on the binding-parser\n      //\n      // t.title is the name of the test and t.fn contains the test body\n      this.parent.parent.tests.forEach(t => {\n        test(t.title, t.fn);\n      });\n    });\n  });\n});\n\nsuite('computed bindings with dynamic functions', function() {\n\n  var el;\n\n  setup(function() {\n    sinon.spy(console, 'warn');\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n    console.warn.restore();\n  });\n\n  test('annotated computation with dynamic function', function() {\n    el = document.createElement('x-bind-computed-property');\n    document.body.appendChild(el);\n\n    assert.equal(el.$.check.textContent, 'translated: Hello World.');\n\n    el.translator = function(message) {\n      return 'changed: ' + message;\n    };\n\n    assert.equal(el.$.check.textContent, 'changed: Hello World.');\n    assert.equal(console.warn.callCount, 0);\n  });\n\n  test('annotated computation / late resolved dynamic function', function() {\n    el = document.createElement('x-bind-computed-property-late-translator');\n    document.body.appendChild(el);\n\n    assert.equal(el.$.check.textContent.trim(), '');\n\n    el.translator = function(message) {\n      return 'translated: ' + message;\n    };\n\n    assert.equal(el.$.check.textContent, 'translated: Hello');\n    assert.equal(console.warn.callCount, 0);\n  });\n\n  test('method observer with dynamic function', function() {\n    Polymer({\n      is: 'x-method-observer-with-dynamic-function',\n      properties: {\n        translateMessage: {\n          type: Function\n        },\n        message: {\n          type: String,\n          value: 'Hello'\n        }\n      },\n\n      observers: ['translateMessage(message)']\n\n    });\n\n    el = document.createElement('x-method-observer-with-dynamic-function');\n    document.body.appendChild(el);\n\n    el.translateMessage = sinon.spy();\n    assert.equal(el.translateMessage.callCount, 1);\n    assert.equal(console.warn.callCount, 0);\n  });\n\n  test('observer with dynamic function', function() {\n    Polymer({\n      is: 'x-observer-with-dynamic-function',\n      properties: {\n        messageChanged: {\n          type: Function\n        },\n        message: {\n          type: String,\n          value: 'Hello',\n          observer: 'messageChanged'\n        }\n      }\n\n    });\n\n    el = document.createElement('x-observer-with-dynamic-function');\n    document.body.appendChild(el);\n\n    el.messageChanged = sinon.spy();\n    assert.equal(el.messageChanged.callCount, 1);\n    assert.equal(console.warn.callCount, 0);\n  });\n\n  test('computed property with dynamic function', function() {\n    Polymer({\n      is: 'x-computed-property-with-dynamic-function',\n      properties: {\n        computedValue: {\n          computed: \"translateMessage('Hello')\"\n        },\n        translateMessage: {\n          type: Function\n        }\n      }\n    });\n\n    el = document.createElement('x-computed-property-with-dynamic-function');\n    document.body.appendChild(el);\n\n    assert.equal(el.computedValue, undefined);\n\n    var called = 0;\n    el.translateMessage = function(message) {\n      called += 1;\n      return 'translated: ' + message;\n    };\n\n    assert.equal(called, 1);\n    assert.equal(el.computedValue, 'translated: Hello');\n    assert.equal(console.warn.callCount, 0);\n  });\n\n  test('ensure annotator can pass dynamic fn to parent props', function(done) {\n    el = document.createElement('x-child-template-with-dynamic-fn');\n    document.body.appendChild(el);\n\n    setTimeout(function() {\n      var check = el.root.querySelector('p');\n      assert.equal(check.textContent, 'text');\n      assert.equal(console.warn.callCount, 0);\n      done();\n    });\n\n  });\n\n});\n\nsuite('2-way binding effects between elements', function() {\n\n  var el;\n\n  setup(function() {\n    el = document.createElement('x-compose');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('binding to non-notifying property', function() {\n    el.boundvalue = 42;\n    assert.equal(el.$.basic1.value, 42, 'binding to child not updated');\n    el.$.basic1.value = 43;\n    assert.equal(el.boundvalue, 42, 'binding to non-notifying property updated and should not have been');\n  });\n\n  test('observer for property bound to non-notifying property', function() {\n    el.$.basic1.value = 44;\n    assert.equal(el.observerCounts.boundvalueChanged, 0, 'observer for property bound to non-notifying property called and should not have been');\n  });\n\n  test('binding to non-notifying computed property', function() {\n    el.boundcomputedvalue = 42;\n    el.$.basic1.value = 43;\n    assert.equal(el.boundcomputedvalue, 42, 'binding to non-notifying computed property updated and should not have been');\n  });\n\n  test('observer for property bound to non-notifying computed property', function() {\n    el.$.basic1.value = 44;\n    assert.equal(el.observerCounts.boundcomputedvalueChanged, 0, 'observer for property bound to non-notifying computed property called and should not have been');\n  });\n\n  test('computed value readOnly from downward binding', function() {\n    el.$.basic3.value = 10;\n    assert.equal(el.$.basic3.computedvalue, 11);\n    // should have no effect\n    el.value = 99;\n    assert.equal(el.$.basic3.computedvalue, 11);\n  });\n\n  test('computed value readOnly from upward notification', function() {\n    assert.equal(el.computedValue, 30);\n    // should have no effect\n    el.$.basic3.notifyingvalue = 10;\n    assert.equal(el.computedValue, 30);\n  });\n\n  test('binding to notifying property', function() {\n    el.boundnotifyingvalue = 42;\n    assert.equal(el.$.basic1.notifyingvalue, 42, 'binding to child not updated');\n    assert.equal(el.$.basic1.camelNotifyingValue, 42, 'camel-case binding to child not updated');\n    el.$.basic1.notifyingvalue = 43;\n    assert.equal(el.boundnotifyingvalue, 43, 'binding to notifying property not updated');\n    el.$.basic1.camelNotifyingValue = -43;\n    assert.equal(el.boundnotifyingvalue, -43, 'camel-case binding to notifying property not updated');\n  });\n\n  test('binding to notifying property with default', function() {\n    assert.equal(el.boundnotifyingvalueWithDefault, 99);\n  });\n\n  test('observer for property bound to notifying property', function() {\n    el.$.basic1.notifyingvalue = 45;\n    assert.equal(el.observerCounts.boundnotifyingvalueChanged, 1, 'observer for property bound to notifying property not called');\n  });\n\n  test('binding to notifying computed property', function() {\n    el.$.basic1.notifyingvalue = 43;\n    assert.equal(el.boundcomputednotifyingvalue, 45, 'binding to notifying computed property not updated');\n  });\n\n  test('observer for property bound to notifying computed property', function() {\n    el.$.basic1.notifyingvalue = 45;\n    assert.equal(el.observerCounts.boundcomputednotifyingvalueChanged, 1, 'observer for property bound to non-notifying computed property not called');\n  });\n\n  test('no change for binding into read-only property', function() {\n    el.$.basic1._setReadonlyvalue(45);\n    el.$.basic1.clearObserverCounts();\n    el.boundreadonlyvalue = 46;\n    assert.equal(el.$.basic1.observerCounts.readonlyvalueChanged, 0, 'observer for read-only property should not be called from change to bound value');\n    assert.equal(el.$.basic1.readonlyvalue, 45, 'read-only property should not change from change to bound value');\n  });\n\n  test('change for binding out of read-only property', function() {\n    el.$.basic1._setReadonlyvalue(46);\n    assert.equal(el.observerCounts.boundreadonlyvalueChanged, 1, 'observer for property bound to read-only property should be called from change to bound value');\n    assert.equal(el.boundreadonlyvalue, 46, 'property bound to read-only property should change from change to bound value');\n  });\n\n  test('negated binding update negates value for parent', function() {\n    assert.equal(el.negatedValue, false);\n    assert.equal(el.$.basic4.notifyingvalue, true);\n    el.$.basic4.notifyingvalue = false;\n    assert.equal(el.negatedValue, true);\n  });\n\n  test('custom xxx-changed event notifies correctly', function() {\n    assert.equal(el.boundCustomNotifyingValue, undefined);\n    assert.equal(el.observerCounts.boundCustomNotifyingValueChanged, 0);\n    el.$.basic1.fireCustomNotifyingEvent();\n    assert.equal(el.boundCustomNotifyingValue, 'changed!');\n    assert.equal(el.observerCounts.boundCustomNotifyingValueChanged, 1);\n  });\n\n});\n\nsuite('handling notifying evevnts', function() {\n\n  test('handle notification event and set property with observer when connected', function() {\n    var el = document.createElement('x-handle-notify-event');\n    document.body.appendChild(el);\n    assert.ok(el.shadowRoot.querySelector('#before'), 'element not found before default notifying element');\n    assert.ok(el.shadowRoot.querySelector('#later'), 'element not found after default notifying element');\n    assert.isTrue(el.readySpy.calledOnce, 'ready called more than once');\n    assert.isTrue(el.handleNotify.calledOnce, 'listener called more than once');\n    assert.isTrue(el.propChanged.calledOnce, 'observer called more than once');\n    assert.isTrue(el.handleNotify.calledBefore(el.propChanged), 'observer called before event');\n    assert.isTrue(el.afterSettingProp.calledBefore(el.propChanged), 'accessor side effect processed during notifying event (before clients ready)');\n    assert.isTrue(el.propChanged.calledBefore(el.readySpy), 'observer called before ready');\n    document.body.removeChild(el);\n  });\n\n  test('handle notification event and set property with observer when *not* connected and _enableProperties called', function() {\n    var el = document.createElement('x-handle-notify-event');\n    el._enableProperties();\n    assert.ok(el.shadowRoot.querySelector('#before'), 'element not found before default notifying element');\n    assert.ok(el.shadowRoot.querySelector('#later'), 'element not found after default notifying element');\n    assert.isTrue(el.readySpy.calledOnce, 'ready called more than once');\n    assert.isTrue(el.handleNotify.calledOnce, 'listener called more than once');\n    assert.isTrue(el.propChanged.calledOnce, 'observer called more than once');\n    assert.isTrue(el.handleNotify.calledBefore(el.propChanged), 'observer called before event');\n    assert.isTrue(el.afterSettingProp.calledBefore(el.propChanged), 'accessor side effect processed during notifying event (before clients ready)');\n    assert.isTrue(el.propChanged.calledBefore(el.readySpy), 'observer called before ready');\n  });\n\n});\n\nsuite('1-way binding effects between elements', function() {\n\n  var el;\n\n  setup(function() {\n    el = document.createElement('x-compose');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('one-way binding to non-notifying property', function() {\n    el.boundvalue = 42;\n    assert.equal(el.$.basic1.value, 42, 'binding to child not updated');\n    el.$.basic2.value = 43;\n    assert.equal(el.boundvalue, 42, 'binding to non-notifying property updated and should not have been');\n  });\n\n  test('observer for property one-way-bound to non-notifying property', function() {\n    el.$.basic2.value = 44;\n    assert.equal(el.observerCounts.boundvalueChanged, 0, 'observer for property one-way-bound to non-notifying property called and should not have been');\n  });\n\n  test('one-way binding to non-notifying computed property', function() {\n    el.boundcomputedvalue = 42;\n    el.$.basic2.value = 43;\n    assert.equal(el.boundcomputedvalue, 42, 'binding to non-notifying computed property updated and should not have been');\n  });\n\n  test('observer for property one-way-bound to non-notifying computed property', function() {\n    el.$.basic2.value = 44;\n    assert.equal(el.observerCounts.boundcomputedvalueChanged, 0, 'observer for property bound to non-notifying computed property called and should not have been');\n  });\n\n  test('one-way binding to notifying property', function() {\n    el.boundnotifyingvalue = 42;\n    assert.equal(el.$.basic2.notifyingvalue, 42, 'binding to child not updated');\n    el.$.basic2.notifyingvalue = 43;\n    assert.equal(el.boundnotifyingvalue, 42, 'binding to notifying property updated and should not have been');\n  });\n\n  test('observer for property one-way-bound to notifying property', function() {\n    el.$.basic2.notifyingvalue = 45;\n    assert.equal(el.observerCounts.boundnotifyingvalueChanged, 0, 'observer for property bound to notifying property called and should not have been');\n  });\n\n  test('one-way binding to notifying computed property', function() {\n    el.boundcomputednotifyingvalue = 42;\n    el.$.basic2.notifyingvalue = 43;\n    assert.equal(el.boundcomputednotifyingvalue, 42, 'binding to notifying computed property updated and should not have been');\n  });\n\n  test('observer for property one-way-bound to notifying computed property', function() {\n    el.$.basic2.notifyingvalue = 45;\n    assert.equal(el.observerCounts.boundcomputednotifyingvalueChanged, 0, 'observer for property bound to non-notifying computed property called and should not have been');\n  });\n\n});\n\nsuite('reflection to attribute', function() {\n\n  var el;\n\n  setup(function() {\n    el = document.createElement('x-reflect');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('reflect object', function() {\n    var obj = {foo: 'bar', array: [1, '2', {3:3}]};\n    el.reflectedobject = obj;\n    assert.equal(el.getAttribute('reflectedobject'), '{\"foo\":\"bar\",\"array\":[1,\"2\",{\"3\":3}]}');\n    // Ensure object wasn't re-deserialized\n    assert.equal(el.reflectedobject, obj);\n    el.reflectedobject = null;\n    assert(!el.hasAttribute('reflectedobject'));\n  });\n\n  test('reflect array', function() {\n    var arr = [1, '2', {3:3}, {'four': 'four'}];\n    el.reflectedarray = arr;\n    assert.equal(el.getAttribute('reflectedarray'), '[1,\"2\",{\"3\":3},{\"four\":\"four\"}]');\n    // Ensure array wasn't re-deserialized\n    assert.equal(el.reflectedarray, arr);\n    el.reflectedarray = null;\n    assert(!el.hasAttribute('reflectedarray'));\n  });\n\n  test('reflect string', function() {\n    var str = '\"polymer is grrrrreat, ain\\'t it?\"';\n    el.reflectedstring = str;\n    assert.equal(el.getAttribute('reflectedstring'), str);\n    assert.equal(el.reflectedstring, str);\n    el.reflectedstring = '';\n    assert.equal(el.getAttribute('reflectedstring'), '');\n    assert.equal(el.reflectedstring, '');\n    el.reflectedstring = null;\n    assert(!el.hasAttribute('reflectedstring'));\n    assert.equal(el.reflectedstring, null);\n  });\n\n  test('reflect number', function() {\n    el.reflectedNumber = 765;\n    assert.equal(el.getAttribute('reflected-number'), '765');\n    assert.equal(el.reflectedNumber, 765);\n    el.reflectedNumber = 765.4321;\n    assert.equal(el.getAttribute('reflected-number'), '765.4321');\n    assert.equal(el.reflectedNumber, 765.4321);\n    el.reflectedNumber = null;\n    assert(!el.hasAttribute('reflected-number'));\n    assert.equal(el.reflectedNumber, null);\n  });\n\n  test('reflect boolean', function() {\n    el.reflectedboolean = true;\n    assert(el.hasAttribute('reflectedboolean'));\n    assert.equal(el.getAttribute('reflectedboolean'), '');\n    assert.equal(el.reflectedboolean, true);\n    el.reflectedboolean = false;\n    assert(!el.hasAttribute('reflectedboolean'));\n    assert.equal(el.reflectedboolean, false);\n    el.reflectedboolean = true;\n    el.reflectedboolean = null;\n    assert(!el.hasAttribute('reflectedboolean'));\n    assert.equal(el.reflectedboolean, null);\n  });\n\n  test('reflect date', function() {\n    var date = new Date('Fri Jan 23 2015 17:40:29 GMT-0800 (PST)');\n    el.reflecteddate = date;\n    assert(el.hasAttribute('reflecteddate'));\n    assert.equal(Date.parse(el.getAttribute('reflecteddate')),\n      el.reflecteddate.getTime());\n    assert.equal(el.reflecteddate, date);\n    el.reflecteddate = null;\n    assert(!el.hasAttribute('reflecteddate'));\n    assert.equal(el.reflecteddate, null);\n  });\n\n  test('reflect wrong type', function() {\n    el.reflectedstring = true;\n    assert(el.hasAttribute('reflectedstring'));\n    assert.equal(el.getAttribute('reflectedstring'), '');\n    // Ensure value wasn't re-deserialized\n    assert.strictEqual(el.reflectedstring, true);\n  });\n\n});\n\nsuite('binding to attribute', function() {\n\n  var el;\n\n  setup(function() {\n    el = document.createElement('x-basic');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('bind object to attribute', function() {\n    el.attrvalue = {foo: 'bar', array: [1, '2', {3:3}]};\n    assert.equal(el.$.boundChild.getAttribute('attrvalue'),\n      '{\"foo\":\"bar\",\"array\":[1,\"2\",{\"3\":3}]}');\n    el.attrvalue = null;\n    assert(!el.$.boundChild.hasAttribute('attrvalue'));\n  });\n\n  test('bind array to attribute', function() {\n    el.attrvalue = [1, '2', {3:3}, {'four': 'four'}];\n    assert.equal(el.$.boundChild.getAttribute('attrvalue'),\n      '[1,\"2\",{\"3\":3},{\"four\":\"four\"}]');\n    el.attrvalue = null;\n    assert(!el.$.boundChild.hasAttribute('attrvalue'));\n  });\n\n  test('bind string to attribute', function() {\n    el.attrvalue = '\"polymer is grrrrreat, ain\\'t it?\"';\n    assert.equal(el.$.boundChild.getAttribute('attrvalue'),\n      '\"polymer is grrrrreat, ain\\'t it?\"');\n    el.attrvalue = '';\n    assert.equal(el.$.boundChild.getAttribute('attrvalue'), '');\n    el.attrvalue = null;\n    assert(!el.$.boundChild.hasAttribute('attrvalue'));\n  });\n\n  test('bind number to attribute', function() {\n    el.attrvalue = 765;\n    assert.equal(el.$.boundChild.getAttribute('attrvalue'), '765');\n    el.attrvalue = 765.4321;\n    assert.equal(el.$.boundChild.getAttribute('attrvalue'), '765.4321');\n    el.attrvalue = null;\n    assert(!el.$.boundChild.hasAttribute('attrvalue'));\n  });\n\n  test('bind boolean to attribute', function() {\n    el.attrvalue = true;\n    assert(el.$.boundChild.hasAttribute('attrvalue'));\n    assert.equal(el.$.boundChild.getAttribute('attrvalue'), '');\n    el.attrvalue = false;\n    assert(!el.$.boundChild.hasAttribute('attrvalue'));\n    el.attrvalue = true;\n    el.attrvalue = null;\n    assert(!el.$.boundChild.hasAttribute('attrvalue'));\n  });\n\n  test('bind date to attribute', function() {\n    el.attrvalue = new Date('Fri Jan 23 2015 17:40:29 GMT-0800 (PST)');\n    assert(el.$.boundChild.hasAttribute('attrvalue'));\n    assert.equal(Date.parse(el.$.boundChild.getAttribute('attrvalue')),\n      el.attrvalue.getTime());\n    el.attrvalue = null;\n    assert(!el.$.boundChild.hasAttribute('attrvalue'));\n  });\n\n  test('bind to value attribute on input should not fail', function() {\n    var el = document.createElement('x-input-value');\n    document.body.appendChild(el);\n    el.inputValue = \"the value\";\n    assert.equal(el.$.input.value, \"the value\", \"The value of the input is not propagated\");\n    assert.equal(el.$.input.value$, undefined, \"value$ should be removed from input\");\n    document.body.removeChild(el);\n  });\n\n});\n\nsuite('avoid non-bubbling event gotchas', function() {\n\n  var el;\n  var container;\n\n  setup(function() {\n    container = document.createElement('div');\n    document.body.appendChild(container);\n    container.innerHTML = '<x-notifies3></x-notifies3>';\n    el = container.firstChild;\n  });\n\n  teardown(function() {\n    document.body.removeChild(container);\n  });\n\n  test('avoid non-bubbling event gotchas', function() {\n    el.$.notifies2.$.notifies1.notifies = 'runtimeValue';\n    assert.equal(el.$.notifies2.$.notifies1.notifies, 'runtimeValue');\n    assert.equal(el.$.notifies2.shouldChange, 'runtimeValue');\n    assert.notEqual(el.shouldNotChange, 'runtimeValue');\n  });\n\n  test('avoid non-bubbling event gotchas at ready time', function() {\n    assert.equal(el.$.notifies2.$.notifies1.notifies, 'readyValue');\n    assert.equal(el.$.notifies2.shouldChange, 'readyValue');\n    assert.notEqual(el.shouldNotChange, 'readyValue');\n  });\n\n});\n\nsuite('warnings', function() {\n\n  var el;\n  var warn; //eslint-disable-line no-unused-vars\n\n  setup(function() {\n    sinon.spy(console, 'warn');\n    el = document.createElement('x-basic');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    console.warn.restore();\n    document.body.removeChild(el);\n  });\n\n  test('undefined observer', function() {\n    el.noObserver = 42;\n    assert.isTrue(console.warn.calledOnce, 'no warning for undefined observer');\n  });\n\n  test('undefined complex observer', function() {\n    el.noComplexObserver = {};\n    assert.isTrue(console.warn.calledOnce, 'no warning for undefined complex observer');\n  });\n\n  test('undefined computed function', function() {\n    el.noComputed = 99;\n    assert.isTrue(console.warn.calledOnce, 'no warning for undefined computed function');\n  });\n\n  test('undefined inline computed function', function() {\n    el.noInlineComputed = 99;\n    assert.isTrue(console.warn.calledOnce, 'no warning for undefined computed function');\n  });\n\n  test('binding to a bad attribute warns', function() {\n    document.createElement('x-bind-bad-attribute-name');\n    assert.isTrue(console.warn.calledOnce, 'no warning for setting a bad attribute');\n  });\n\n});\n\nsuite('binding corner cases', function() {\n\n  // IE can create adjacent text nodes that split bindings; this test\n  // ensures the code that addresses this is functional\n  test('text binding after entity', function() {\n    var el = document.createElement('x-entity-and-binding');\n    document.body.appendChild(el);\n    assert.equal(el.$.binding.textContent, 'binding');\n    document.body.removeChild(el);\n  });\n\n  test('bind to isAttached', function() {\n    var el = document.createElement('x-bind-is-attached');\n    sinon.spy(el, '_isAttachedChanged');\n    document.body.appendChild(el);\n    assert.equal(el.$.check.textContent, 'true');\n    assert.isTrue(el._isAttachedChanged.calledOnce);\n    document.body.removeChild(el);\n  });\n\n});\n\nsuite('binding interop', function() {\n\n  test('do not set same value to a non-Polymer element', function() {\n    var el = document.createElement('x-interop');\n    document.body.appendChild(el);\n    assert.equal(el.$.raw.value, 10);\n    assert.equal(el.$.raw.valueChanged.callCount, 1);\n    assert.equal(el.$.raw.valueChanged.firstCall.args[0], 10);\n    // Should set value\n    el.value++;\n    assert.equal(el.$.raw.value, 11);\n    assert.equal(el.$.raw.valueChanged.callCount, 2);\n    assert.equal(el.$.raw.valueChanged.secondCall.args[0], 11);\n    // Notifies up to host, should not be re-set down to element\n    el.$.raw.increment();\n    assert.equal(el.$.raw.value, 12);\n    assert.equal(el.$.raw.valueChanged.callCount, 2);\n    document.body.removeChild(el);\n  });\n\n  test('path notification of object bound to textContent of a Polymer element', function() {\n    var el = document.createElement('x-interop');\n    document.body.appendChild(el);\n    // Initial state\n    assert.equal(el.$.polymer.textContent, '1,2,3');\n    // Push\n    el.push('array', 4);\n    assert.equal(el.$.polymer.textContent, '1,2,3,4');\n    document.body.removeChild(el);\n  });\n\n  test('path notification of array bound to setter of a Polymer element', function() {\n    var el = document.createElement('x-interop');\n    document.body.appendChild(el);\n    // Initial state\n    assert.equal(el.$.polymer.array, el.array);\n    assert.equal(el.$.polymer.arrayChanged.callCount, 1);\n    assert.equal(el.$.polymer.arrayChanged.firstCall.args[0], el.array);\n    // Push\n    el.push('array', 4);\n    assert.equal(el.$.polymer.array, el.array);\n    // Gets called twice, once for splice info, once for length :(\n    assert.equal(el.$.polymer.arrayChanged.callCount, 3);\n    assert.equal(el.$.polymer.arrayChanged.secondCall.args[0], el.array);\n    assert.equal(el.$.polymer.arrayChanged.thirdCall.args[0], el.array);\n    document.body.removeChild(el);\n  });\n\n  test('path notification of array in compound binding to property of Polymer element', function() {\n    var el = document.createElement('x-interop');\n    document.body.appendChild(el);\n    // Initial state\n    assert.equal(el.$.polymer.compound, '**1,2,3**');\n    assert.equal(el.$.polymer.compoundChanged.callCount, 1);\n    assert.equal(el.$.polymer.compoundChanged.firstCall.args[0], '**1,2,3**');\n    // Push\n    el.push('array', 4);\n    assert.equal(el.$.polymer.compound, '**1,2,3,4**');\n    assert.equal(el.$.polymer.compoundChanged.callCount, 2);\n    assert.equal(el.$.polymer.compoundChanged.secondCall.args[0], '**1,2,3,4**');\n    document.body.removeChild(el);\n  });\n\n  test('path notification of array bound to setter of a non-Polymer element', function() {\n    var el = document.createElement('x-interop');\n    document.body.appendChild(el);\n    // Initial state\n    assert.equal(el.$.raw.textContent, '1,2,3');\n    assert.equal(el.$.raw.arrayChanged.callCount, 1);\n    assert.equal(el.$.raw.arrayChanged.firstCall.args[0], el.array);\n    // Push\n    el.push('array', 4);\n    assert.equal(el.$.raw.textContent, '1,2,3,4');\n    // Array change notifies once for splice info, once for length, and\n    // since the property is a Array, it passes the dirty check and will go\n    // through twice; this test also happens to not have a getter, so that\n    // would cause the dirty check to pass even if it wasn't an Object\n    assert.equal(el.$.raw.arrayChanged.callCount, 3);\n    assert.equal(el.$.raw.arrayChanged.secondCall.args[0], el.array);\n    assert.equal(el.$.raw.arrayChanged.thirdCall.args[0], el.array);\n    document.body.removeChild(el);\n  });\n\n  test('path notification of array in compound binding to property of non-Polymer element', function() {\n    var el = document.createElement('x-interop');\n    document.body.appendChild(el);\n    // Initial state\n    assert.equal(el.$.raw.compound, '**1,2,3**');\n    // Raw elements with compound bindings will first see the\n    // literals, then the properties, hence 2 sets initially\n    assert.equal(el.$.raw.compoundChanged.callCount, 2);\n    assert.equal(el.$.raw.compoundChanged.firstCall.args[0], '****');\n    assert.equal(el.$.raw.compoundChanged.secondCall.args[0], '**1,2,3**');\n    // Push\n    el.push('array', 4);\n    assert.equal(el.$.raw.compound, '**1,2,3,4**');\n    assert.equal(el.$.raw.compoundChanged.callCount, 3);\n    assert.equal(el.$.raw.compoundChanged.thirdCall.args[0], '**1,2,3,4**');\n    document.body.removeChild(el);\n  });\n\n});\n\nsuite('compound binding / string interpolation', function() {\n\n  var el;\n\n  setup(function() {\n    el = document.createElement('x-basic');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('compound adjacent property bindings', function() {\n    // Adjacent compound binding with no literal do not override the default\n    assert.equal(el.$.boundProps.prop1, 'default');\n    assert.isTrue(el.$.boundProps.prop1Changed.calledOnce);\n    el.cpnd2 = 'cpnd2';\n    assert.equal(el.$.boundProps.prop1, 'cpnd2');\n    el.cpnd1 = 'cpnd1';\n    el.cpnd3 = {prop: 'cpnd3'};\n    assert.equal(el.$.boundProps.prop1, 'cpnd1cpnd2cpnd3');\n    el.cpnd4 = 'cpnd4';\n    assert.equal(el.$.boundProps.prop1,\n      legacyUndefined ?\n      'cpnd1cpnd2cpnd3' : 'cpnd1cpnd2cpnd3literalComputedcpnd4');\n    el.cpnd5 = 'cpnd5';\n    assert.equal(el.$.boundProps.prop1, 'cpnd1cpnd2cpnd3literalComputedcpnd5cpnd4');\n  });\n\n  test('compound property bindings with literals', function() {\n    assert.equal(el.$.boundProps.prop2, 'literal1  literal2  literal3  literal4');\n    assert.isTrue(el.$.boundProps.prop2Changed.calledOnce);\n    el.cpnd1 = 'cpnd1';\n    el.cpnd2 = 'cpnd2';\n    el.cpnd3 = {prop: 'cpnd3'};\n    el.cpnd4 = 'cpnd4';\n    el.cpnd5 = 'cpnd5';\n    assert.equal(el.$.boundProps.prop2, 'literal1 cpnd1 literal2 cpnd2cpnd3 literal3 literalComputedcpnd5cpnd4 literal4');\n    el.cpnd1 = null;\n    el.cpnd2 = undefined;\n    el.cpnd3 = {};\n    el.cpnd4 = '';\n    el.cpnd5 = '';\n    assert.equal(el.$.boundProps.prop2, 'literal1  literal2  literal3 literalComputed literal4');\n  });\n\n  test('compound adjacent attribute bindings', function() {\n    // Adjacent compound binding with no literal do not override the default\n    assert.equal(el.$.boundChild.getAttribute('compoundAttr1'), null);\n    el.cpnd2 = 'cpnd2';\n    assert.equal(el.$.boundChild.getAttribute('compoundAttr1'), 'cpnd2');\n    el.cpnd1 = 'cpnd1';\n    el.cpnd3 = {prop: 'cpnd3'};\n    assert.equal(el.$.boundChild.getAttribute('compoundAttr1'), 'cpnd1cpnd2cpnd3');\n    el.cpnd4 = 'cpnd4';\n    assert.equal(el.$.boundChild.getAttribute('compoundAttr1'),\n      legacyUndefined ?\n      'cpnd1cpnd2cpnd3' : 'cpnd1cpnd2cpnd3literalComputedcpnd4');\n    el.cpnd5 = 'cpnd5';\n    assert.equal(el.$.boundChild.getAttribute('compoundAttr1'), 'cpnd1cpnd2cpnd3literalComputedcpnd5cpnd4');\n  });\n\n  test('compound property attribute with literals', function() {\n    assert.equal(el.$.boundChild.getAttribute('compoundAttr2'), 'literal1  literal2  literal3  literal4');\n    el.cpnd1 = 'cpnd1';\n    el.cpnd2 = 'cpnd2';\n    el.cpnd3 = {prop: 'cpnd3'};\n    el.cpnd4 = 'cpnd4';\n    el.cpnd5 = 'cpnd5';\n    assert.equal(el.$.boundChild.getAttribute('compoundAttr2'), 'literal1 cpnd1 literal2 cpnd2cpnd3 literal3 literalComputedcpnd5cpnd4 literal4');\n    el.cpnd1 = null;\n    el.cpnd2 = undefined;\n    el.cpnd3 = {};\n    el.cpnd4 = '';\n    el.cpnd5 = '';\n    assert.equal(el.$.boundChild.getAttribute('compoundAttr2'), 'literal1  literal2  literal3 literalComputed literal4');\n  });\n\n  test('compound property attribute with {} and [] in text', function() {\n    el.cpnd1 = 'cpnd1';\n    assert.equal(el.$.boundChild.getAttribute('compoundAttr3'), '[yes/no]: cpnd1, Hello {0} username world');\n  });\n\n  test('compound adjacent textNode bindings', function() {\n    // The single space is due to the gambit to prevent empty text nodes\n    // from being omitted by IE during importNode from the template; it will\n    // only be there when in the virgin state after cloning the template\n    assert.equal(el.$.compound1.textContent, ' ');\n    el.cpnd2 = 'cpnd2';\n    assert.equal(el.$.compound1.textContent, 'cpnd2');\n    el.cpnd1 = 'cpnd1';\n    el.cpnd3 = {prop: 'cpnd3'};\n    assert.equal(el.$.compound1.textContent, 'cpnd1cpnd2cpnd3');\n    el.cpnd4 = 'cpnd4';\n    assert.equal(el.$.compound1.textContent,\n      legacyUndefined ?\n      'cpnd1cpnd2cpnd3' : 'cpnd1cpnd2cpnd3literalComputedcpnd4');\n    el.cpnd5 = 'cpnd5';\n    assert.equal(el.$.compound1.textContent, 'cpnd1cpnd2cpnd3literalComputedcpnd5cpnd4');\n    // Once the binding evaluates back to '', it will in fact be ''\n    el.computeCompound = function() { return ''; };\n    el.cpnd1 = null;\n    el.cpnd2 = '';\n    el.cpnd3 = {prop: null};\n    el.cpnd4 = null;\n    el.cpnd5 = '';\n    assert.equal(el.$.compound1.textContent, '');\n  });\n\n  test('compound textNode bindings with literals', function() {\n    assert.equal(el.$.compound2.textContent.trim(), 'literal1  literal2  literal3  literal4');\n    el.cpnd1 = 'cpnd1';\n    el.cpnd2 = 'cpnd2';\n    el.cpnd3 = {prop: 'cpnd3'};\n    el.cpnd4 = 'cpnd4';\n    el.cpnd5 = 'cpnd5';\n    assert.equal(el.$.compound2.textContent.trim(), 'literal1 cpnd1 literal2 cpnd2cpnd3 literal3 literalComputedcpnd5cpnd4 literal4');\n    el.cpnd1 = null;\n    el.cpnd2 = undefined;\n    el.cpnd3 = {};\n    el.cpnd4 = '';\n    el.cpnd5 = '';\n    assert.equal(el.$.compound2.textContent.trim(), 'literal1  literal2  literal3 literalComputed literal4');\n  });\n\n  test('malformed bindings ignored', function() {\n    el.bool = true;\n    assert.isTrue(el.$.boundChild.textContent.indexOf('really.long.identifier.in.malformed.binding.should.be.ignored') >= 0, true);\n    assert.isTrue(el.$.boundChild.textContent.indexOf('really.long.literal.in.malformed.binding.should.be.ignored') >= 0, true);\n    assert.isTrue(el.$.boundChild.textContent.indexOf('3foo') >= 0, true);\n  });\n\n});\n\nsuite('order of effects', function() {\n\n  var el;\n\n  setup(function() {\n    let gp = document.createElement('x-order-of-effects-grand-parent');\n    document.body.appendChild(gp);\n    el = gp.$.child;\n  });\n\n  test('effects are sorted', function() {\n    assert.equal(el.invocations.length, 0);\n    el.base = 'changed';\n\n    var expected = [\n      'compute',\n      'propagate',  // as observed by child; note: order of binding vs.\n      'propagate',  // computed binding is not guaranteed\n      'reflect',\n      'observe',    // note: order of single-property observer vs.\n      'observe',    // multi-property observer is not guaranteed\n      'notify'      // as observed by grand-parent\n    ];\n\n    assert.deepEqual(el.invocations, expected);\n  });\n});\n\nsuite('misc', function() {\n\n  test('effects forward propagate value', function() {\n    var el = document.createElement('x-propagate');\n    document.body.appendChild(el);\n    assert.equal(el.value, 1, 'observers did not receive latest value for property');\n    document.body.removeChild(el);\n  });\n\n  test('custom _template on prototype', function() {\n    var el = document.createElement('x-template-proto');\n    document.body.appendChild(el);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.equal(el.$.div.textContent, 'yes');\n    assert.equal(el.clicked.callCount, 0);\n    el.$.div.click();\n    assert.equal(el.clicked.callCount, 1);\n    document.body.removeChild(el);\n  });\n\n  test('custom _template on behavior', function() {\n    var el = document.createElement('x-template-behavior');\n    document.body.appendChild(el);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assert.equal(el.$.div.textContent, 'yes');\n    assert.equal(el.clicked.callCount, 0);\n    el.$.div.click();\n    assert.equal(el.clicked.callCount, 1);\n    document.body.removeChild(el);\n  });\n\n});\n\nsuite('DOM sanitization', function() {\n\n  setup(function() {\n    setSanitizeDOMValue(sinon.spy(function(value) {\n      return (value && value.toString().indexOf('javascript') >= 0) ? 'notallowed!' : value;\n    }));\n  });\n\n  teardown(function() {\n    setSanitizeDOMValue(null);\n  });\n\n  test('bound property', function() {\n    var el = document.createElement('x-basic');\n    document.body.appendChild(el);\n    el.sanitizeValue = 'ok';\n    assert.equal(el.$.boundChild.sanitizeValue, 'ok');\n    el.sanitizeValue = 'javascript';\n    assert.equal(el.$.boundChild.sanitizeValue, 'notallowed!');\n    assert.deepEqual(sanitizeDOMValue.lastCall.args,\n      ['javascript', 'sanitizeValue', 'property', el.$.boundChild]);\n  });\n\n  test('bound textContent', function() {\n    var el = document.createElement('x-basic');\n    document.body.appendChild(el);\n    el.sanitizeText = 'ok';\n    assert.equal(el.$.sanitizeText.textContent, 'ok');\n    el.sanitizeText = 'javascript';\n    assert.equal(el.$.sanitizeText.textContent, 'notallowed!');\n    assert.deepEqual(sanitizeDOMValue.lastCall.args,\n      ['javascript', 'textContent', 'text', el.$.sanitizeText.firstChild]);\n  });\n\n  test('bound attribute', function() {\n    var el = document.createElement('x-basic');\n    document.body.appendChild(el);\n    el.attrvalue = 'ok';\n    assert.equal(el.$.boundChild.getAttribute('attrvalue'), 'ok');\n    el.attrvalue = 'javascript';\n    assert.equal(el.$.boundChild.getAttribute('attrvalue'), 'notallowed!');\n    assert.deepEqual(sanitizeDOMValue.lastCall.args,\n      ['javascript', 'attrvalue', 'attribute', el.$.boundChild]);\n  });\n\n  test('reflected attribute', function() {\n    var el = document.createElement('x-reflect');\n    document.body.appendChild(el);\n    el.reflectedstring = 'ok';\n    assert.equal(el.getAttribute('reflectedstring'), 'ok');\n    el.reflectedstring = 'javascript';\n    assert.equal(el.getAttribute('reflectedstring'), 'notallowed!');\n    assert.deepEqual(sanitizeDOMValue.lastCall.args,\n      ['javascript', 'reflectedstring', 'attribute', el]);\n  });\n\n  test('getter returns the current value', function() {\n    assert(sanitizeDOMValue instanceof Function);\n    assert.strictEqual(getSanitizeDOMValue(), sanitizeDOMValue);\n    setSanitizeDOMValue(null);\n    assert.strictEqual(sanitizeDOMValue, null);\n    assert.strictEqual(getSanitizeDOMValue(), null);\n  });\n});\n\nsuite('data (im)mutability', function() {\n\n  test('immutable data propagation', function() {\n    let el = document.createElement('x-immutable-a');\n    document.body.appendChild(el);\n    // Flow initial data\n    el.a = {x: 'xb', b: {x: 'xc', c: 'c'}};\n    assert.equal(el.a, el.a);\n    assert.equal(el.aChanged.callCount, 1);\n    assert.equal(el.$.b.b, el.a.b);\n    assert.equal(el.$.b.x, 'xb');\n    assert.equal(el.$.b.bChanged.callCount, 1);\n    assert.equal(el.$.b.xChanged.callCount, 1);\n    assert.equal(el.$.b.$.c.c, 'c');\n    assert.equal(el.$.b.$.c.x, 'xc');\n    assert.equal(el.$.b.$.c.cChanged.callCount, 1);\n    assert.equal(el.$.b.$.c.xChanged.callCount, 1);\n    // Mutate in place with reset (error, does nothing)\n    el.a.b.c = 'wontchange';\n    el.a = el.a;\n    assert.equal(el.a, el.a);\n    assert.equal(el.aChanged.callCount, 1);\n    assert.equal(el.$.b.b, el.a.b);\n    assert.equal(el.$.b.x, 'xb');\n    assert.equal(el.$.b.bChanged.callCount, 1);\n    assert.equal(el.$.b.xChanged.callCount, 1);\n    assert.equal(el.$.b.$.c.c, 'c');\n    assert.equal(el.$.b.$.c.x, 'xc');\n    assert.equal(el.$.b.$.c.cChanged.callCount, 1);\n    assert.equal(el.$.b.$.c.xChanged.callCount, 1);\n    // Mutate via immutable pattern:\n    el.a = Object.assign({}, el.a, {b:\n      Object.assign({}, el.a.b, {\n        c: 'willchange1'\n      })\n    });\n    assert.equal(el.a, el.a);\n    assert.equal(el.aChanged.callCount, 2);\n    assert.equal(el.$.b.b, el.a.b);\n    assert.equal(el.$.b.x, 'xb');\n    assert.equal(el.$.b.bChanged.callCount, 2);\n    assert.equal(el.$.b.xChanged.callCount, 1);\n    assert.equal(el.$.b.$.c.c, 'willchange1');\n    assert.equal(el.$.b.$.c.x, 'xc');\n    assert.equal(el.$.b.$.c.cChanged.callCount, 2);\n    assert.equal(el.$.b.$.c.xChanged.callCount, 1);\n    // Mutate via path API\n    el.set('a.b.c', 'willchange2');\n    assert.equal(el.a, el.a);\n    assert.equal(el.aChanged.callCount, 2);\n    assert.equal(el.$.b.b, el.a.b);\n    assert.equal(el.$.b.x, 'xb');\n    assert.equal(el.$.b.bChanged.callCount, 2);\n    assert.equal(el.$.b.xChanged.callCount, 1);\n    assert.equal(el.$.b.$.c.c, 'willchange2');\n    assert.equal(el.$.b.$.c.x, 'xc');\n    assert.equal(el.$.b.$.c.cChanged.callCount, 3);\n    assert.equal(el.$.b.$.c.xChanged.callCount, 1);\n  });\n\n  test('mutable data propagation', function() {\n    let el = document.createElement('x-mutable-a');\n    document.body.appendChild(el);\n    // Flow initial data\n    el.a = {x: 'xb', b: {x: 'xc', c: 'c'}};\n    assert.equal(el.a, el.a);\n    assert.equal(el.aChanged.callCount, 1);\n    assert.equal(el.$.b.b, el.a.b);\n    assert.equal(el.$.b.x, 'xb');\n    assert.equal(el.$.b.bChanged.callCount, 1);\n    assert.equal(el.$.b.xChanged.callCount, 1);\n    assert.equal(el.$.b.$.c.c, 'c');\n    assert.equal(el.$.b.$.c.x, 'xc');\n    assert.equal(el.$.b.$.c.cChanged.callCount, 1);\n    assert.equal(el.$.b.$.c.xChanged.callCount, 1);\n    // Mutate in place with reset\n    el.a.b.c = 'willchange1';\n    el.a = el.a;\n    assert.equal(el.a, el.a);\n    assert.equal(el.aChanged.callCount, 2);\n    assert.equal(el.$.b.b, el.a.b);\n    assert.equal(el.$.b.x, 'xb');\n    assert.equal(el.$.b.bChanged.callCount, 2);\n    assert.equal(el.$.b.xChanged.callCount, 1);\n    assert.equal(el.$.b.$.c.c, 'willchange1');\n    assert.equal(el.$.b.$.c.x, 'xc');\n    assert.equal(el.$.b.$.c.cChanged.callCount, 2);\n    assert.equal(el.$.b.$.c.xChanged.callCount, 1);\n    // Mutate via immutable pattern:\n    el.a = Object.assign({}, el.a, {b:\n      Object.assign({}, el.a.b, {\n        c: 'willchange2'\n      })\n    });\n    assert.equal(el.a, el.a);\n    assert.equal(el.aChanged.callCount, 3);\n    assert.equal(el.$.b.b, el.a.b);\n    assert.equal(el.$.b.x, 'xb');\n    assert.equal(el.$.b.bChanged.callCount, 3);\n    assert.equal(el.$.b.xChanged.callCount, 1);\n    assert.equal(el.$.b.$.c.c, 'willchange2');\n    assert.equal(el.$.b.$.c.x, 'xc');\n    assert.equal(el.$.b.$.c.cChanged.callCount, 3);\n    assert.equal(el.$.b.$.c.xChanged.callCount, 1);\n    // Mutate via path API\n    el.set('a.b.c', 'willchange3');\n    assert.equal(el.a, el.a);\n    assert.equal(el.aChanged.callCount, 3);\n    assert.equal(el.$.b.b, el.a.b);\n    assert.equal(el.$.b.x, 'xb');\n    assert.equal(el.$.b.bChanged.callCount, 3);\n    assert.equal(el.$.b.xChanged.callCount, 1);\n    assert.equal(el.$.b.$.c.c, 'willchange3');\n    assert.equal(el.$.b.$.c.x, 'xc');\n    assert.equal(el.$.b.$.c.cChanged.callCount, 4);\n    assert.equal(el.$.b.$.c.xChanged.callCount, 1);\n  });\n\n});\n\nsuite('runtime effects', function() {\n\n  var el, el2;\n\n  setup(function() {\n    el = document.createElement('x-basic');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n    document.body.removeChild(el2);\n  });\n\n  test('add/remove runtime property effect', function() {\n    assert.equal(el.observerCounts.valueChanged, 1);\n    let info = {};\n    let fn = sinon.spy();\n    let effect = { info, fn };\n    el._addPropertyEffect('value', el.PROPERTY_EFFECT_TYPES.OBSERVE, effect);\n    el.value = 'value++';\n    assert.equal(el.observerCounts.valueChanged, 2);\n    assert.equal(fn.callCount, 1);\n    assert.equal(fn.firstCall.args[0], el);\n    assert.equal(fn.firstCall.args[1], 'value');\n    assert.equal(fn.firstCall.args[2].value, 'value++');\n    assert.equal(fn.firstCall.args[4], info);\n    el._removePropertyEffect('value', el.PROPERTY_EFFECT_TYPES.OBSERVE, effect);\n    el.value = 'value+++';\n    assert.equal(fn.callCount, 1);\n    // Ensure prototype wasn't affected\n    el2 = document.createElement('x-basic');\n    document.body.appendChild(el2);\n    assert.equal(fn.callCount, 1);\n  });\n\n  test('add/remove runtime path effect', function() {\n    assert.equal(el.observerCounts.valueChanged, 1);\n    let info = {};\n    let fn = sinon.spy();\n    let trigger = {name: 'value.path', structured: true};\n    let effect = { info, fn, trigger };\n    el._addPropertyEffect('value', el.PROPERTY_EFFECT_TYPES.OBSERVE, effect);\n    el.value = {path: 'value.path'};\n    assert.equal(el.observerCounts.valueChanged, 2);\n    assert.equal(fn.callCount, 1);\n    assert.equal(fn.getCall(0).args[0], el);\n    assert.equal(fn.getCall(0).args[1], 'value');\n    assert.equal(fn.getCall(0).args[2].value, el.value);\n    assert.equal(fn.getCall(0).args[4], info);\n    el.set('value.path', 'value.path++');\n    assert.equal(el.observerCounts.valueChanged, 2);\n    assert.equal(fn.callCount, 2);\n    assert.equal(fn.getCall(1).args[0], el);\n    assert.equal(fn.getCall(1).args[1], 'value.path');\n    assert.equal(fn.getCall(1).args[2]['value.path'], 'value.path++');\n    assert.equal(fn.getCall(1).args[4], info);\n    el._removePropertyEffect('value', el.PROPERTY_EFFECT_TYPES.OBSERVE, effect);\n    el.set('value.path', 'value.path+++');\n    assert.equal(fn.callCount, 2);\n    // Ensure prototype wasn't affected\n    el2 = document.createElement('x-basic');\n    document.body.appendChild(el2);\n    assert.equal(fn.callCount, 2);\n  });\n\n});\n\nsuite('a la carte usage of API', function() {\n\n  let BaseClass;\n\n  suiteSetup(function() {\n    BaseClass = class extends PropertyEffects(HTMLElement) {\n      connectedCallback() {\n        this.pcSpy = sinon.spy();\n        this._enableProperties();\n      }\n      _propertiesChanged(props, changedProps, oldProps) {\n        this.pcSpy(props, changedProps, oldProps);\n        super._propertiesChanged(props, changedProps, oldProps);\n      }\n    };\n  });\n\n  test('generic property effect', function() {\n    class TestClass extends BaseClass {\n      constructor() {\n        super();\n        this.observer = sinon.spy();\n      }\n    }\n    let observer = sinon.spy();\n    TestClass.addPropertyEffect('prop', TestClass.prototype.PROPERTY_EFFECT_TYPES.OBSERVE, {\n      fn: observer\n    });\n    customElements.define('pe-pe', TestClass);\n    let el = document.createElement('pe-pe');\n    document.body.appendChild(el);\n    assert.equal(observer.callCount, 0);\n    assert.equal(el.pcSpy.callCount, 0);\n    el.prop = true;\n    assert.equal(observer.callCount, 1);\n    assert.equal(el.pcSpy.callCount, 1);\n    el.prop = 'hithere';\n    assert.equal(observer.callCount, 2);\n    assert.equal(el.pcSpy.callCount, 2);\n    el.prop = false;\n    assert.equal(observer.callCount, 3);\n    assert.equal(el.pcSpy.callCount, 3);\n    document.body.removeChild(el);\n  });\n\n  test('read only property', function() {\n    class TestClass extends BaseClass {}\n    TestClass.createReadOnlyProperty('prop', true);\n    customElements.define('pe-read-only', TestClass);\n    let el = document.createElement('pe-read-only');\n    document.body.appendChild(el);\n    el.prop = true;\n    assert.equal(el.prop, undefined);\n    assert.equal(el.pcSpy.callCount, 0);\n    el._setProp(true);\n    assert.equal(el.prop, true);\n    assert.equal(el.pcSpy.callCount, 1);\n    el.prop = false;\n    assert.equal(el.prop, true);\n    assert.equal(el.pcSpy.callCount, 1);\n    document.body.removeChild(el);\n  });\n\n  test('reflected property', function() {\n    class TestClass extends BaseClass {}\n    TestClass.createReflectedProperty('prop', true);\n    customElements.define('pe-reflected', TestClass);\n    let el = document.createElement('pe-reflected');\n    document.body.appendChild(el);\n    assert.equal(el.hasAttribute('prop'), false);\n    assert.equal(el.pcSpy.callCount, 0);\n    el.prop = true;\n    assert.equal(el.getAttribute('prop'), '');\n    assert.equal(el.pcSpy.callCount, 1);\n    el.prop = 'hithere';\n    assert.equal(el.getAttribute('prop'), 'hithere');\n    assert.equal(el.pcSpy.callCount, 2);\n    el.prop = false;\n    assert.equal(el.hasAttribute('prop'), false);\n    assert.equal(el.pcSpy.callCount, 3);\n    document.body.removeChild(el);\n  });\n\n  test('property observer', function() {\n    class TestClass extends BaseClass {\n      constructor() {\n        super();\n        this.observer = sinon.spy();\n      }\n    }\n    TestClass.createPropertyObserver('prop', 'observer');\n    customElements.define('pe-observer', TestClass);\n    let el = document.createElement('pe-observer');\n    document.body.appendChild(el);\n    assert.equal(el.observer.callCount, 0);\n    assert.equal(el.pcSpy.callCount, 0);\n    el.prop = true;\n    assert.equal(el.observer.callCount, 1);\n    assert.equal(el.pcSpy.callCount, 1);\n    el.prop = 'hithere';\n    assert.equal(el.observer.callCount, 2);\n    assert.equal(el.pcSpy.callCount, 2);\n    el.prop = false;\n    assert.equal(el.observer.callCount, 3);\n    assert.equal(el.pcSpy.callCount, 3);\n    document.body.removeChild(el);\n  });\n\n  test('method observer', function() {\n    class TestClass extends BaseClass {\n      constructor() {\n        super();\n        this.observer = sinon.spy();\n      }\n    }\n    TestClass.createMethodObserver('observer(a, b.c)', true);\n    customElements.define('pe-method-observer', TestClass);\n    let el = document.createElement('pe-method-observer');\n    document.body.appendChild(el);\n    if (legacyUndefined) {\n      assert.equal(el.observer.callCount, 0);\n    } else {\n      assert.equal(el.observer.callCount, 1);\n      assert.deepEqual(el.observer.getCall(0).args, [undefined, undefined]);\n    }\n    assert.equal(el.pcSpy.callCount, 1);\n    el.a = 'a';\n    if (legacyUndefined) {\n      assert.equal(el.observer.callCount, 0);\n    } else {\n      assert.equal(el.observer.callCount, 2);\n      assert.deepEqual(el.observer.getCall(1).args, ['a', undefined]);\n    }\n    assert.equal(el.pcSpy.callCount, 2);\n    el.b = {c: 'c'};\n    if (legacyUndefined) {\n      assert.equal(el.observer.callCount, 1);\n      assert.deepEqual(el.observer.getCall(0).args, ['a', 'c']);\n    } else {\n      assert.equal(el.observer.callCount, 3);\n      assert.deepEqual(el.observer.getCall(2).args, ['a', 'c']);\n    }\n    assert.equal(el.pcSpy.callCount, 3);\n    el.setProperties({\n      a: 'A',\n      b: {c: 'C'}\n    });\n    if (legacyUndefined) {\n      assert.equal(el.observer.callCount, 2);\n      assert.deepEqual(el.observer.getCall(1).args, ['A', 'C']);\n      assert.equal(el.pcSpy.callCount, 4);\n    } else {\n      assert.equal(el.observer.callCount, 4);\n      assert.deepEqual(el.observer.getCall(3).args, ['A', 'C']);\n      assert.equal(el.pcSpy.callCount, 4);\n    }\n\n    el.observer = sinon.spy();\n    assert.equal(el.observer.callCount, 1);\n    assert.deepEqual(el.observer.getCall(0).args, ['A', 'C']);\n    assert.equal(el.pcSpy.callCount, 5);\n    document.body.removeChild(el);\n  });\n\n  test('computed property', function() {\n    class TestClass extends BaseClass {\n      constructor() {\n        super();\n        this.compute = sinon.spy(function(a, c) { return a + c; });\n      }\n    }\n    TestClass.createComputedProperty('prop', 'compute(a, b.c)');\n    customElements.define('pe-computed', TestClass);\n    let el = document.createElement('pe-computed');\n    document.body.appendChild(el);\n    assert.equal(el.compute.callCount, 0);\n    assert.equal(el.pcSpy.callCount, 0);\n    el.a = 'a';\n    if (legacyUndefined) {\n      assert.equal(el.compute.callCount, 0);\n    } else {\n      assert.equal(el.compute.callCount, 1);\n      assert.deepEqual(el.compute.getCall(0).args, ['a', undefined]);\n      assert.equal(el.prop, 'aundefined');\n    }\n    assert.equal(el.pcSpy.callCount, 1);\n    el.b = {c: 'c'};\n    if (legacyUndefined) {\n      assert.equal(el.compute.callCount, 1);\n      assert.deepEqual(el.compute.getCall(0).args, ['a', 'c']);\n    } else {\n      assert.equal(el.compute.callCount, 2);\n      assert.deepEqual(el.compute.getCall(1).args, ['a', 'c']);\n    }\n    assert.equal(el.prop, 'ac');\n    assert.equal(el.pcSpy.callCount, 2);\n    el.setProperties({\n      a: 'A',\n      b: {c: 'C'}\n    });\n    if (legacyUndefined) {\n      assert.equal(el.compute.callCount, 2);\n      assert.deepEqual(el.compute.getCall(1).args, ['A', 'C']);\n      assert.equal(el.pcSpy.callCount, 3);\n    } else {\n      assert.equal(el.compute.callCount, 3);\n      assert.deepEqual(el.compute.getCall(2).args, ['A', 'C']);\n      assert.equal(el.pcSpy.callCount, 3);\n    }\n    assert.equal(el.prop, 'AC');\n    document.body.removeChild(el);\n  });\n\n  test('notifying property', function() {\n    class TestClass extends BaseClass { }\n    TestClass.createNotifyingProperty('prop');\n    customElements.define('pe-notify', TestClass);\n    let el = document.createElement('pe-notify');\n    let handler = sinon.spy();\n    el.addEventListener('prop-changed', handler);\n    document.body.appendChild(el);\n    assert.equal(handler.callCount, 0);\n    assert.equal(el.pcSpy.callCount, 0);\n    el.prop = 'prop';\n    assert.equal(handler.callCount, 1);\n    assert.equal(handler.getCall(0).args[0].detail.value, 'prop');\n    assert.equal(el.pcSpy.callCount, 1);\n    el.prop += '+';\n    assert.equal(handler.callCount, 2);\n    assert.equal(handler.getCall(1).args[0].detail.value, 'prop+');\n    document.body.removeChild(el);\n  });\n\n  test('bound template', function() {\n    let template = document.createElement('template');\n    template.innerHTML = '<div>[[prop]]</div><button on-click=\"handler\"></button>';\n    class TestClass extends BaseClass {\n      connectedCallback() {\n        this.handler = sinon.spy();\n        this.attachShadow({mode:'open'}).appendChild(this._stampTemplate(template));\n        super.connectedCallback();\n      }\n    }\n    TestClass.bindTemplate(template);\n    customElements.define('pe-template', TestClass);\n    let el = document.createElement('pe-template');\n    document.body.appendChild(el);\n    assert.equal(el.handler.callCount, 0);\n    el.prop = 'prop';\n    assert.equal(el.shadowRoot.querySelector('div').textContent, 'prop');\n    el.shadowRoot.querySelector('button').click();\n    assert.equal(el.handler.callCount, 1);\n    document.body.removeChild(el);\n  });\n\n});\n\nsuite('warn on legacy differences', () => {\n\n  setup(function() {\n    sinon.spy(console, 'warn');\n  });\n\n  teardown(function() {\n    setLegacyWarnings(false);\n    console.warn.restore();\n  });\n\n  test('warn if non-declared property used in binding', () => {\n    setLegacyWarnings(true);\n    Polymer({\n      is: 'x-warn-undeclared-binding',\n      _template: html`\n        <div attr$=\"[[undeclaredToAttr]]\"\n             prop=\"[[undeclaredToProp]]\">\n             [[undeclaredToText]]\n             [[compute(undeclaredDep1, undeclaredDep2)]]\n             </div>\n        <template is=\"dom-repeat\" items=\"[0]\">\n          <div attr$=\"[[nestedUndeclaredToAttr]]\"\n             prop=\"[[nestedUndeclaredToProp]]\">\n             [[nestedUndeclaredToText]]\n             [[compute(nestedUndeclaredDep1, nestedUndeclaredDep2)]]\n             </div>\n        </template>\n        `,\n      compute(dep) { return dep; }\n    });\n    const el = document.createElement('x-warn-undeclared-binding');\n    document.body.appendChild(el);\n    flush();\n    document.body.removeChild(el);\n    assert.equal(console.warn.callCount, 10);\n  });\n\n  test('do not warn on valid non-property bindings', () => {\n    setLegacyWarnings(true);\n    Polymer({\n      is: 'x-nowarn-undeclared-binding',\n      properties: {\n        hostProp: String,\n        dynamicFn: Function\n      },\n      _template: html`\n        <div>[[hostProp]]</div>    <!-- host prop -->\n        <div>[[noDeps()]]</div>    <!-- method with no deps -->\n        <div>[[literalDeps('hi')]]</div>  <!-- method with literal deps -->\n        <div>[[dynamicFn()]]</div> <!-- dynamic function with no deps -->\n        <div>[[dynamicFnWithDep(hostProp)]]</div>  <!-- dynamic function with deps -->\n        <template is=\"dom-repeat\" items=\"[0]\" as=\"instProp\">\n          <div>[[instProp]]</div>  <!-- instance prop -->\n          <div>[[hostProp]]</div>  <!-- nested host prop -->\n          <div>[[noDeps()]]</div>  <!-- nested method with no deps -->\n          <div>[[literalDeps('hi')]]</div>  <!-- method with literal deps -->\n          <div>[[dynamicFn()]]</div> <!-- dynamic function with no deps -->\n          <div>[[dynamicFnWithDep(hostProp)]]</div>  <!-- dynamic function with deps -->\n        </template>\n      `,\n      noDeps() { return 'static'; },\n      dynamicFn(dep) { return dep; },\n      dynamicFnWithDep(dep) { return dep; }\n    });\n    const el = document.createElement('x-nowarn-undeclared-binding');\n    document.body.appendChild(el);\n    flush();\n    document.body.removeChild(el);\n    assert.equal(console.warn.callCount, 0);\n  });\n\n  test('warn when re-declaring a computed property', () => {\n    Polymer({\n      is: 'x-warn-redeclared-computed',\n      behaviors: [{\n        properties: {\n          a: { computed: 'compute(x)' }\n        }\n      }, {\n        properties: {\n          a: { computed: 'compute(y)' }\n        }\n      }]\n    });\n    const el = document.createElement('x-warn-redeclared-computed');\n    document.body.appendChild(el);\n    document.body.removeChild(el);\n    assert.equal(console.warn.callCount, 1);\n  });\n\n  test('warn when disabling readOnly on a readOnly property', () => {\n    Polymer({\n      is: 'x-warn-disable-readonly',\n      behaviors: [{\n        properties: {\n          a: { readOnly: true }\n        }\n      }, {\n        properties: {\n          a: { readOnly: false }\n        }\n      }]\n    });\n    const el = document.createElement('x-warn-disable-readonly');\n    document.body.appendChild(el);\n    document.body.removeChild(el);\n    assert.equal(console.warn.callCount, 1);\n  });\n\n  test('warn when disabling reflect on a reflect property', () => {\n    Polymer({\n      is: 'x-warn-disable-reflect',\n      behaviors: [{\n        properties: {\n          a: { reflectToAttribute: true }\n        }\n      }, {\n        properties: {\n          a: { reflectToAttribute: false }\n        }\n      }]\n    });\n    const el = document.createElement('x-warn-disable-reflect');\n    document.body.appendChild(el);\n    document.body.removeChild(el);\n    assert.equal(console.warn.callCount, 1);\n  });\n\n  test('warn when disabling notify on a notify property', () => {\n    Polymer({\n      is: 'x-warn-disable-notify',\n      behaviors: [{\n        properties: {\n          a: { notify: true }\n        }\n      }, {\n        properties: {\n          a: { notify: false }\n        }\n      }]\n    });\n    const el = document.createElement('x-warn-disable-notify');\n    document.body.appendChild(el);\n    document.body.removeChild(el);\n    assert.equal(console.warn.callCount, 1);\n  });\n\n});\n\nif (orderedComputed) {\n\n  suite('computed property ordering', function() {\n    var el;\n\n    setup(function() {\n      el = document.createElement('x-computed-ordering');\n      document.body.appendChild(el);\n    });\n\n    teardown(function() {\n      document.body.removeChild(el);\n    });\n\n    test('computed property ordering', function() {\n\n      assert.equal(el.bc, 110);\n      assert.equal(el.bcd, 111);\n      assert.equal(el.abbcd, 1211);\n      assert.equal(el.computeBC.callCount, 1);\n      assert.equal(el.computeBCD.callCount, 1);\n      assert.equal(el.computeABBCD.callCount, 1);\n\n      el.setProperties({\n        b: 200,\n        c: 20\n      });\n      assert.equal(el.bc, 220);\n      assert.equal(el.bcd, 221);\n      assert.equal(el.abbcd, 1421);\n      assert.equal(el.computeBC.callCount, 2);\n      assert.equal(el.computeBCD.callCount, 2);\n      assert.equal(el.computeABBCD.callCount, 2);\n\n      el.a = 2000;\n      assert.equal(el.bc, 220);\n      assert.equal(el.bcd, 221);\n      assert.equal(el.abbcd, 2421);\n      assert.equal(el.computeBC.callCount, 2);\n      assert.equal(el.computeBCD.callCount, 2);\n      assert.equal(el.computeABBCD.callCount, 3);\n\n      el.c = 30;\n      assert.equal(el.bc, 230);\n      assert.equal(el.bcd, 231);\n      assert.equal(el.abbcd, 2431);\n      assert.equal(el.computeBC.callCount, 3);\n      assert.equal(el.computeBCD.callCount, 3);\n      assert.equal(el.computeABBCD.callCount, 4);\n\n      el.d = 2;\n      assert.equal(el.bc, 230);\n      assert.equal(el.bcd, 232);\n      assert.equal(el.abbcd, 2432);\n      assert.equal(el.computeBC.callCount, 3);\n      assert.equal(el.computeBCD.callCount, 4);\n      assert.equal(el.computeABBCD.callCount, 5);\n\n      el.setProperties({\n        a: 1000,\n        b: 100,\n        c: 10,\n        d: 1\n      });\n      assert.equal(el.bc, 110);\n      assert.equal(el.bcd, 111);\n      assert.equal(el.abbcd, 1211);\n      assert.equal(el.computeBC.callCount, 4);\n      assert.equal(el.computeBCD.callCount, 5);\n      assert.equal(el.computeABBCD.callCount, 6);\n\n    });\n\n    test('computing functions as dependencies', function() {\n      assert.equal(el.xy, '222');\n      assert.equal(el.computeXYSpy.callCount, 1);\n      assert.equal(el.xyChanged.callCount, 1);\n\n      el.setProperties({\n        x: 3,\n        z: 300\n      });\n      assert.equal(el.xy, '323');\n      assert.equal(el.computeXYSpy.callCount, 2);\n      assert.equal(el.xyChanged.callCount, 2);\n    });\n\n    test('ensure circular dependencies do not iloop', function() {\n      el.circIn = 1;\n      // The answers here don't _really_ matter; it just shouldn't iloop\n      // circA will go first (defined first), which will pull circB, which\n      // has no circA yet, and thus returns 1 for this turn\n      assert.ok(el.circA); // should be equal to 2, based on impl\n      assert.ok(el.circB); // should be equal to 1, based on impl\n    });\n\n  });\n\n}\n\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/ready-attached-order-class.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n</head>\n<body>\n\n<script type=\"module\">\nwindow.clearTestLists = function() {\n  window.actualAttachedList = [];\n  window.actualReadyList = [];\n  window.actualReadyBeforeAttachedList = [];\n};\n\nwindow.clearTestLists();\n\nwindow.readyMixin = function(base) {\n  return class readyMixin extends base {\n    static get properties() {\n      return {\n        prop: {\n          value: true,\n          observer: '_propChanged'\n        }\n      };\n    }\n\n    _propChanged() {\n      this.observerShadowRoot = Boolean(this.shadowRoot);\n    }\n    ready() {\n      super.ready();\n      this._readied = true;\n      this.readyList = window.actualReadyList.slice();\n      this.readyShadowRoot = Boolean(this.shadowRoot);\n      window.actualReadyList.push(this);\n    }\n\n    connectedCallback() {\n      this._eventList = [];\n      this.addEventListener('e', (e) => {\n        this._eventList.push(e.composedPath()[0]);\n      });\n      super.connectedCallback();\n      this.dispatchEvent(new Event('e', {composed: true, bubbles: true}));\n      this.attachedShadowRoot = Boolean(this.shadowRoot);\n      this.attachedTime$Keys = Object.keys(this.$);\n      this.attachedList = window.actualAttachedList.slice();\n      window.actualAttachedList.push(this);\n      if (!this._readied) {\n        window.actualReadyBeforeAttachedList.push(this);\n      }\n    }\n  };\n};\n</script>\n\n<dom-module id=\"x-zot\">\n  <template>\n    x-zot<slot></slot>\n  </template>\n  <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nclass El extends window.readyMixin(PolymerElement) {\n  static get is() { return 'x-zot'; }\n}\ncustomElements.define(El.is, El);\n</script>\n</dom-module>\n\n<dom-module id=\"x-bar\">\n  <template>\n    <x-zot id=\"zot\"></x-zot>\n  </template>\n  <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nclass El extends window.readyMixin(PolymerElement) {\n  static get is() { return 'x-bar'; }\n}\ncustomElements.define(El.is, El);\n</script>\n</dom-module>\n\n<dom-module id=\"x-foo\">\n  <template>\n    <x-bar id=\"bar1\"></x-bar>\n    <x-bar id=\"bar2\"></x-bar>\n  </template>\n  <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nclass El extends window.readyMixin(PolymerElement) {\n  static get is() { return 'x-foo'; }\n}\ncustomElements.define(El.is, El);\n</script>\n</dom-module>\n\n<dom-module id=\"x-ready\">\n  <template>\n    <x-zot id=\"a\">\n      <x-zot id=\"b\"></x-zot>\n      <x-zot id=\"c\">\n        <x-zot id=\"d\"></x-zot>\n      </x-zot>\n    </x-zot>\n    <x-foo id=\"foo\"></x-foo>\n  </template>\n  <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nclass El extends window.readyMixin(PolymerElement) {\n  static get is() { return 'x-ready'; }\n  static get properties() {\n    return {\n      foo: {\n        observer: '_fooChanged'\n      }\n    };\n  }\n  _fooChanged() {}\n}\ncustomElements.define(El.is, El);\n</script>\n</dom-module>\n\n<dom-module id=\"x-templatized\">\n  <template>\n    <template is=\"dom-if\" if>\n      <x-ready foo=\"[[foo]]\"></x-ready>\n    </template>\n  </template>\n  <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nclass El extends PolymerElement {\n  static get is() { return 'x-templatized'; }\n  static get properties() {\n    return {\n      foo: {\n        value: 'foo'\n      }\n    };\n  }\n}\ncustomElements.define(El.is, El);\n</script>\n</dom-module>\n\n<script type=\"module\">\nimport { flush } from '../../lib/utils/flush.js';\n\nsuite('ready and attached ordering', function() {\n\n  let el;\n\n  setup(function() {\n    window.clearTestLists();\n    el = document.createElement('x-ready');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('element dom ready before element', function() {\n    assert.includeMembers(el.readyList, [el.$.a, el.$.b, el.$.c, el.$.d, el.$.foo]);\n    var foo = el.$.foo;\n    assert.includeMembers(foo.readyList, [foo.$.bar1, foo.$.bar1.$.zot, foo.$.bar2, foo.$.bar2.$.zot]);\n    var b1 = foo.$.bar1, b2 = foo.$.bar2;\n    assert.includeMembers(b1.readyList, [b1.$.zot]);\n    assert.includeMembers(b2.readyList, [b2.$.zot]);\n  });\n\n  test('can listen to events fired by element dom in connected', function() {\n    assert.includeMembers(el._eventList, [el.$.a, el.$.b, el.$.c, el.$.d, el.$.foo]);\n    var foo = el.$.foo;\n    assert.includeMembers(foo._eventList, [foo.$.bar1, foo.$.bar2]);\n    var b1 = foo.$.bar1, b2 = foo.$.bar2;\n    assert.includeMembers(b1._eventList, [b1.$.zot]);\n    assert.includeMembers(b2._eventList, [b2.$.zot]);\n  });\n\n  test('shadowRoot available in ready, connected, observer', function() {\n    [el, el.$.a, el.$.b, el.$.c, el.$.d, el.$.foo,\n      el.$.foo.$.bar1, el.$.foo.$.bar1.$.zot,\n      el.$.foo.$.bar2, el.$.foo.$.bar2.$.zot].forEach((e) => {\n      assert.isTrue(e.observerShadowRoot);\n      assert.isTrue(e.readyShadowRoot);\n      assert.isTrue(e.attachedShadowRoot);\n    });\n  });\n\n  test('element attached called after ready', function() {\n    assert.equal(window.actualReadyBeforeAttachedList.length, 0);\n  });\n\n  test('element has $ references at attached time', function() {\n    assert.sameMembers(el.attachedTime$Keys, ['a', 'b', 'c', 'd', 'foo']);\n    assert.sameMembers(el.$.foo.attachedTime$Keys, ['bar1', 'bar2']);\n  });\n\n});\n\nsuite('templatized: ready and attached ordering', function() {\n\n  let container, el;\n\n  setup(function() {\n    window.clearTestLists();\n    container = document.createElement('x-templatized');\n    document.body.appendChild(container);\n    flush();\n    el = container.shadowRoot.querySelector('x-ready');\n  });\n\n  teardown(function() {\n    document.body.removeChild(container);\n  });\n\n  test('element dom ready before element', function() {\n    assert.includeMembers(el.readyList, [el.$.a, el.$.b, el.$.c, el.$.d, el.$.foo]);\n    var foo = el.$.foo;\n    assert.includeMembers(foo.readyList, [foo.$.bar1, foo.$.bar1.$.zot, foo.$.bar2, foo.$.bar2.$.zot]);\n    var b1 = foo.$.bar1, b2 = foo.$.bar2;\n    assert.includeMembers(b1.readyList, [b1.$.zot]);\n    assert.includeMembers(b2.readyList, [b2.$.zot]);\n  });\n\n  test('can listen to events fired by element dom in connected', function() {\n    assert.includeMembers(el._eventList, [el.$.a, el.$.b, el.$.c, el.$.d, el.$.foo]);\n    var foo = el.$.foo;\n    assert.includeMembers(foo._eventList, [foo.$.bar1, foo.$.bar2]);\n    var b1 = foo.$.bar1, b2 = foo.$.bar2;\n    assert.includeMembers(b1._eventList, [b1.$.zot]);\n    assert.includeMembers(b2._eventList, [b2.$.zot]);\n  });\n\n  test('shadowRoot available in ready, connected, observer', function() {\n    [el, el.$.a, el.$.b, el.$.c, el.$.d, el.$.foo,\n      el.$.foo.$.bar1, el.$.foo.$.bar1.$.zot,\n      el.$.foo.$.bar2, el.$.foo.$.bar2.$.zot].forEach((e) => {\n      assert.isTrue(e.observerShadowRoot);\n      assert.isTrue(e.readyShadowRoot);\n      assert.isTrue(e.attachedShadowRoot);\n    });\n  });\n\n  test('element attached called after ready', function() {\n    assert.equal(window.actualReadyBeforeAttachedList.length, 0);\n  });\n\n  test('element has $ references at attached time', function() {\n    assert.sameMembers(el.attachedTime$Keys, ['a', 'b', 'c', 'd', 'foo']);\n    assert.sameMembers(el.$.foo.attachedTime$Keys, ['bar1', 'bar2']);\n  });\n\n});\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/ready-attached-order.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n</head>\n<body>\n\n<script type=\"module\">\nwindow.clearTestLists = function() {\n  window.actualAttachedList = [];\n  window.actualReadyList = [];\n  window.actualReadyBeforeAttachedList = [];\n};\n\nwindow.clearTestLists();\n\nwindow.readyBehavior = {\n  properties: {\n    prop: {\n      value: true,\n      observer: '_propChanged'\n    },\n  },\n  _propChanged: function() {\n    this.observerShadowRoot = Boolean(this.shadowRoot);\n  },\n  ready: function() {\n    this._readied = true;\n    this.readyList = window.actualReadyList.slice();\n    this.readyShadowRoot = Boolean(this.shadowRoot);\n    window.actualReadyList.push(this);\n  },\n\n  attached: function() {\n    this.attachedShadowRoot = Boolean(this.shadowRoot);\n    this.attachedTime$Keys = Object.keys(this.$);\n    this.attachedList = window.actualAttachedList.slice();\n    window.actualAttachedList.push(this);\n    if (!this._readied) {\n      window.actualReadyBeforeAttachedList.push(this);\n    }\n  }\n};\n</script>\n\n<dom-module id=\"x-zot\">\n  <template>\n    x-zot<slot></slot>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-zot',\n  behaviors: [window.readyBehavior]\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-bar\">\n  <template>\n    <x-zot id=\"zot\"></x-zot>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-bar',\n  behaviors: [window.readyBehavior]\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-foo\">\n  <template>\n    <x-bar id=\"bar1\"></x-bar>\n    <x-bar id=\"bar2\"></x-bar>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-foo',\n  behaviors: [window.readyBehavior]\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-ready\">\n  <template>\n    <x-zot id=\"a\">\n      <x-zot id=\"b\"></x-zot>\n      <x-zot id=\"c\">\n        <x-zot id=\"d\"></x-zot>\n      </x-zot>\n    </x-zot>\n    <x-foo id=\"foo\"></x-foo>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-ready',\n  properties: {\n    foo: {\n      observer: '_fooChanged'\n    }\n  },\n  behaviors: [window.readyBehavior],\n  _fooChanged: function() {}\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-templatized\">\n  <template>\n    <template is=\"dom-if\" if>\n      <x-ready foo=\"[[foo]]\"></x-ready>\n    </template>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-templatized',\n  properties: {\n    foo: {\n      value: 'foo'\n    }\n  }\n});\n</script>\n</dom-module>\n\n<script type=\"module\">\nimport { flush } from '../../lib/utils/flush.js';\n\nsuite('ready and attached ordering', function() {\n\n  let el;\n\n  setup(function() {\n    window.clearTestLists();\n    el = document.createElement('x-ready');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('element dom ready before element', function() {\n    assert.includeMembers(el.readyList, [el.$.a, el.$.b, el.$.c, el.$.d, el.$.foo]);\n    var foo = el.$.foo;\n    assert.includeMembers(foo.readyList, [foo.$.bar1, foo.$.bar1.$.zot, foo.$.bar2, foo.$.bar2.$.zot]);\n    var b1 = foo.$.bar1, b2 = foo.$.bar2;\n    assert.includeMembers(b1.readyList, [b1.$.zot]);\n    assert.includeMembers(b2.readyList, [b2.$.zot]);\n  });\n\n  // test('element dom connected before element', function() {\n  //   assert.includeMembers(el.attachedList, [el.$.a, el.$.b, el.$.c, el.$.d, el.$.foo]);\n  //   var foo = el.$.foo;\n  //   assert.includeMembers(foo.attachedList, [foo.$.bar1, foo.$.bar2]);\n  //   var b1 = foo.$.bar1, b2 = foo.$.bar2;\n  //   assert.includeMembers(b1.attachedList, [b1.$.zot]);\n  //   assert.includeMembers(b2.attachedList, [b2.$.zot]);\n  // });\n\n  test('shadowRoot available in ready, connected, observer', function() {\n    [el, el.$.a, el.$.b, el.$.c, el.$.d, el.$.foo,\n      el.$.foo.$.bar1, el.$.foo.$.bar1.$.zot,\n      el.$.foo.$.bar2, el.$.foo.$.bar2.$.zot].forEach((e) => {\n      assert.isTrue(e.observerShadowRoot);\n      assert.isTrue(e.readyShadowRoot);\n      assert.isTrue(e.attachedShadowRoot);\n    });\n  });\n\n  test('element attached called after ready', function() {\n    assert.equal(window.actualReadyBeforeAttachedList.length, 0);\n  });\n\n  test('element has $ references at attached time', function() {\n    assert.sameMembers(el.attachedTime$Keys, ['a', 'b', 'c', 'd', 'foo']);\n    assert.sameMembers(el.$.foo.attachedTime$Keys, ['bar1', 'bar2']);\n  });\n\n});\n\nsuite('templatized: ready and attached ordering', function() {\n\n  let container, el;\n\n  setup(function() {\n    window.clearTestLists();\n    container = document.createElement('x-templatized');\n    document.body.appendChild(container);\n    flush();\n    el = container.shadowRoot.querySelector('x-ready');\n  });\n\n  teardown(function() {\n    document.body.removeChild(container);\n  });\n\n  test('element dom ready before element', function() {\n    assert.includeMembers(el.readyList, [el.$.a, el.$.b, el.$.c, el.$.d, el.$.foo]);\n    var foo = el.$.foo;\n    assert.includeMembers(foo.readyList, [foo.$.bar1, foo.$.bar1.$.zot, foo.$.bar2, foo.$.bar2.$.zot]);\n    var b1 = foo.$.bar1, b2 = foo.$.bar2;\n    assert.includeMembers(b1.readyList, [b1.$.zot]);\n    assert.includeMembers(b2.readyList, [b2.$.zot]);\n  });\n\n  test('shadowRoot available in ready, connected, observer', function() {\n    [el, el.$.a, el.$.b, el.$.c, el.$.d, el.$.foo,\n      el.$.foo.$.bar1, el.$.foo.$.bar1.$.zot,\n      el.$.foo.$.bar2, el.$.foo.$.bar2.$.zot].forEach((e) => {\n      assert.isTrue(e.observerShadowRoot);\n      assert.isTrue(e.readyShadowRoot);\n      assert.isTrue(e.attachedShadowRoot);\n    });\n  });\n\n  test('element attached called after ready', function() {\n    assert.equal(window.actualReadyBeforeAttachedList.length, 0);\n  });\n\n  test('element has $ references at attached time', function() {\n    assert.sameMembers(el.attachedTime$Keys, ['a', 'b', 'c', 'd', 'foo']);\n    assert.sameMembers(el.$.foo.attachedTime$Keys, ['bar1', 'bar2']);\n  });\n\n});\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/render-status.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n<body>\n\n<script type=\"module\">\nimport { beforeNextRender, afterNextRender } from '../../lib/utils/render-status.js';\nimport { LegacyElementMixin } from '../../lib/legacy/legacy-element-mixin.js';\nclass XFoo extends LegacyElementMixin(HTMLElement) {\n  ready() {\n    super.ready();\n    sinon.spy(this, 'beforeNextRender');\n    sinon.spy(this, 'stillBeforeNextRender');\n    beforeNextRender(this, this.beforeNextRender,\n      ['before']);\n  }\n\n  beforeNextRender() {\n    beforeNextRender(this, this.stillBeforeNextRender,\n      ['still-before']);\n  }\n  stillBeforeNextRender() {\n    if (this.beforeDone) {\n      this.beforeDone();\n    }\n  }\n}\ncustomElements.define('x-foo', XFoo);\n\nclass XBar extends LegacyElementMixin(HTMLElement) {\n  ready() {\n    super.ready();\n    sinon.spy(this, 'afterNextRender');\n    sinon.spy(this, 'afterAfterNextRender');\n    afterNextRender(this, (a) => {\n      this.afterNextRender(a);\n    }, ['after']);\n  }\n\n  afterNextRender() {\n    afterNextRender(this, (a) => {\n      this.afterAfterNextRender(a);\n    }, ['after-after']);\n  }\n  afterAfterNextRender() {\n    if (this.afterDone) {\n      this.afterDone();\n    }\n  }\n\n}\ncustomElements.define('x-bar', XBar);\n</script>\n\n<script type=\"module\">\nimport { flush } from '../../lib/utils/render-status.js';\n\nsuite('render-status', function() {\n\n  test('beforeNextRender', function(done) {\n    let el = document.createElement('x-foo');\n    document.body.appendChild(el);\n    el.beforeDone = function() {\n      assert.ok(el.beforeNextRender.withArgs('before').calledOnce);\n      assert.ok(el.stillBeforeNextRender.withArgs('still-before').calledOnce);\n      // break out of this raf so next test is not tainted.\n      requestAnimationFrame(() => { done(); });\n    };\n  });\n\n  test('afterNextRender', function(done) {\n    let el = document.createElement('x-bar');\n    let raf1 = sinon.spy();\n    let raf2 = sinon.spy();\n    requestAnimationFrame(() => {\n      raf1();\n      requestAnimationFrame(() => {\n        raf2();\n      });\n    });\n    el.afterDone = function() {\n      assert.ok(el.afterNextRender.withArgs('after').calledOnce);\n      assert.ok(el.afterNextRender.calledAfter(raf1));\n      assert.ok(el.afterAfterNextRender.withArgs('after-after').calledOnce);\n      assert.ok(el.afterAfterNextRender.calledAfter(raf2));\n      // break out of this raf so next test is not tainted.\n      requestAnimationFrame(() => { done(); });\n    };\n    document.body.appendChild(el);\n  });\n\n  test('flush', function() {\n    let el1 = document.createElement('x-foo');\n    let el2 = document.createElement('x-bar');\n    document.body.appendChild(el1);\n    document.body.appendChild(el2);\n    flush();\n    assert.ok(el1.beforeNextRender.withArgs('before').calledOnce);\n    assert.ok(el1.stillBeforeNextRender.withArgs('still-before').calledOnce);\n    assert.ok(el2.afterNextRender.withArgs('after').calledOnce);\n    assert.ok(el2.afterAfterNextRender.withArgs('after-after').calledOnce);\n  });\n\n});\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/resolveurl.html",
    "content": "<!DOCTYPE html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"UTF-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\">\n    import { setRootPath } from '../../lib/utils/settings.js';\n    setRootPath('earlyRootPath/');\n  </script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n  <script type=\"module\" src=\"./sub/resolveurl-elements.js\"></script>\n</head>\n<body>\n  <x-resolve></x-resolve>\n\n  <dom-module id=\"x-late\">\n    <template>\n      <style>\n        :host {\n          background: url('foo.png');\n        }\n      </style>\n      <img id=\"root\" src$=\"[[rootPath]]foo.png\">\n      <img id=\"import\" src$=\"[[importPath]]foo.png\">\n    </template>\n  </dom-module>\n\n  <dom-module id=\"x-resolve\">\n  </dom-module>\n\n  <script type=\"module\">\nimport './sub/resolveurl-elements.js';\nimport { PolymerElement } from '../../polymer-element.js';\nclass XResolve extends PolymerElement {\n  static get is() { return 'x-resolve'; }\n}\ncustomElements.define(XResolve.is, XResolve);\n</script>\n\n\n  <script type=\"module\">\nimport './sub/resolveurl-elements.js';\nimport { PolymerElement } from '../../polymer-element.js';\nimport { setRootPath } from '../../lib/utils/settings.js';\nsuite('ResolveUrl', function() {\n\n  const testStylesAndAttributes = (elementName) => () => {\n    var el = document.createElement(elementName);\n    document.body.appendChild(el);\n    var resolvedUrl = /sub\\/foo\\.z/;\n    var styleHashUrl = /url\\('#bar'\\)/;\n    var styleAbsUrl = /url\\('\\/zot'\\)/;\n    var style = el.shadowRoot.querySelector('style') || document.querySelector(`style[scope=${elementName}]`);\n    assert.match(style.textContent, resolvedUrl, 'url not relative to main document');\n    assert.match(style.textContent, styleHashUrl, 'hash url incorrectly resolved');\n    assert.match(style.textContent, styleAbsUrl, 'absolute url incorrectly resolved');\n    assert.match(el.$.div.getAttribute('style'), resolvedUrl, 'style url not relative to main document');\n    assert.match(el.$.img.src, resolvedUrl, 'src url not relative to main document');\n    assert.match(el.$.a.href, resolvedUrl, 'href url not relative to main document');\n    assert.match(el.$.import.getAttribute('url'), resolvedUrl, 'url url not relative to main document');\n    assert.match(el.$.resolveUrl.getAttribute('url'), resolvedUrl, 'url url not relative to main document');\n    assert.equal(el.$.resolveUrlHash.getAttribute('url'), '#foo', 'url url not relative to main document');\n    assert.equal(el.$.resolveUrlAbs.getAttribute('url'), '/foo', 'url url not relative to main document');\n    assert.notMatch(el.$.root.getAttribute('url'), resolvedUrl, 'url url not relative to main document');\n    assert.notMatch(el.$.rel.href, resolvedUrl, 'relative href url not relative to main document');\n    assert.match(el.$.rel.href, /\\?123$/, 'relative href does not preserve query string');\n    assert.equal(el.$.action.getAttribute('action'), 'foo.z', 'action attribute relativized for incorrect element type');\n    assert.match(el.$.formAction.action, resolvedUrl, 'action attribute relativized for incorrect element type');\n    assert.equal(el.$.hash.getAttribute('href'), '#foo.z', 'hash-only url should not be resolved');\n    assert.equal(el.$.absolute.getAttribute('href'), '/foo.z', 'absolute urls should not be resolved');\n    assert.equal(el.$.protocol.getAttribute('href'), 'data:foo.z', 'urls with other protocols should not be resolved');\n    document.body.removeChild(el);\n  };\n\n  test('Urls in styles and attributes', testStylesAndAttributes('p-r'));\n\n  test('Urls in styles and attributes (hybrid)', testStylesAndAttributes('p-r-hybrid'));\n\n  test('url changes via setting importPath/rootPath on element instance', function() {\n    var el = document.createElement('p-r');\n    document.body.appendChild(el);\n    el.rootPath = 'instanceRoot/';\n    el.importPath = 'instanceImport/';\n    var matchRoot = /instanceRoot\\//;\n    var matchImport = /instanceImport\\//;\n    assert.match(el.$.div.getAttribute('style'), matchImport);\n    assert.match(el.$.import.getAttribute('url'), matchImport);\n    assert.match(el.$.root.getAttribute('url'), matchRoot);\n    document.body.removeChild(el);\n  });\n\n  test('rootPath set early', function() {\n    class XEarly extends PolymerElement {\n      static get is() { return 'x-late';}\n    }\n    customElements.define('x-early', XEarly);\n    var el = document.createElement('x-early');\n    document.body.appendChild(el);\n    var matchRoot = /earlyRootPath\\//i;\n    assert.match(el.$.root.getAttribute('src'), matchRoot);\n    document.body.removeChild(el);\n  });\n\n  test('url changes via setting importPath/rootPath when defining element', function() {\n    setRootPath('defineRoot/');\n    class XLate extends PolymerElement {\n      static get is() { return 'x-late';}\n      static get importPath() { return 'defineImport/';}\n    }\n    customElements.define(XLate.is, XLate);\n    var el = document.createElement('x-late');\n    document.body.appendChild(el);\n    var matchRoot = /defineRoot\\//i;\n    var matchImport = /defineImport\\//i;\n    var style = el.shadowRoot.querySelector('style') || document.querySelector('style[scope=x-late]');\n    assert.match(style.textContent, matchImport);\n    assert.match(el.$.import.getAttribute('src'), matchImport);\n    assert.match(el.$.root.getAttribute('src'), matchRoot);\n    document.body.removeChild(el);\n  });\n\n  test('resolveUrl api', function() {\n    var el = document.createElement('p-r');\n    var expected = document.location.href.replace(/[?#].*$/, '');\n    var actual = el.resolveUrl('../resolveurl.html');\n    assert.equal(actual, expected);\n  });\n\n  test('resolveUrl api with base', function() {\n    var el = document.createElement('p-r');\n    var expected = 'http://example.com/resolveurl.html';\n    var actual = el.resolveUrl('resolveurl.html', 'http://example.com/');\n    assert.equal(actual, expected);\n  });\n\n  test('resolveUrl api, when defined in main doc', function() {\n    var el = document.querySelector('x-resolve');\n    var expected = document.location.href.replace(/[?#].*$/, '');\n    expected = expected.split('/');\n    expected.pop();\n    expected = expected.join('/') + '/foo/bar.png';\n    var actual = el.resolveUrl('foo/../foo/bar.png');\n    assert.equal(actual, expected);\n  });\n\n  test('resolveUrl when called with a protocol-relative url', function () {\n    const el = document.querySelector('x-resolve');\n    const expected = `https://example.com/foo`;\n    const actual =\n        el.resolveUrl('//example.com/foo', 'https://example.org/bar');\n    assert.equal(actual, expected);\n  });\n\n  test('resolveUrl when called with //', function () {\n    const el = document.querySelector('x-resolve');\n    const expected = '//';\n    const actual =\n        el.resolveUrl('//', 'https://example.org/bar');\n    assert.equal(actual, expected);\n  });\n\n  test('resolveUrl when called with relative url and a bad baseURI', function () {\n    const el = document.querySelector('x-resolve');\n    const expected = 'relative/path.png';\n    const actual =\n        el.resolveUrl('relative/path.png', '/not/a/full/uri');\n    assert.equal(actual, expected);\n  });\n\n  test('resolveUrl when called with a full url and a bad baseURI', function () {\n    const el = document.querySelector('x-resolve');\n    const expected = 'https://example.com/foo.png';\n    const actual =\n        el.resolveUrl('https://example.com/foo.png', '/not/a/full/uri');\n    assert.equal(actual, expected);\n  });\n\n  test('resolveUrl when called with a protocol-relative url and a bad baseURI', function () {\n    const el = document.querySelector('x-resolve');\n    const expected = '//example.com/foo.png';\n    const actual =\n        el.resolveUrl('//example.com/foo.png', '/not/a/full/uri');\n    assert.equal(actual, expected);\n  });\n\n  test('resolveUrl api with assetpath', function() {\n    var el = document.createElement('p-r-ap');\n    // Manually calculate expected URL, to avoid dependence on\n    // URL object for this test for IE! Otherwise, would do this:\n    // var importPath = document.querySelector('#elements').href;\n    // var expected = new URL('../../assets/Beaker2.jpg', importPath);\n    var expected = document.location.href.replace(/[?#].*$/, '');\n    expected = expected.split('/');\n    expected.pop();\n    expected.pop();\n    expected = expected.join('/');\n    expected = expected + '/assets/Beaker2.jpg';\n    var actual = el.resolveUrl('Beaker2.jpg');\n    assert.equal(actual, expected);\n  });\n});\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/shady-content.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script>\n    if (window.customElements) {\n      customElements.forcePolyfill = true;\n    }\n    window.ShadyDOM = {\n      force: true\n    };\n  </script>\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n</head>\n<body>\n\n<dom-module id=\"x-dist\">\n  <template>\n    x-dist\n    <div id=\"distWrapper\"><slot id=\"content\"></slot></div>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-dist'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-dist-simple\">\n  <template>\n    <slot id=\"content\"></slot>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-dist-simple'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-dist-star\">\n  <template><slot></slot></template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-dist-star'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-dist-inside-deep-tree\">\n  <template>\n    x-dist-inside-deep-tree\n    <div></div>\n    <div>\n      <div>\n        <div>\n          <div id=\"distWrapper\"><slot id=\"content\"></slot></div>\n        </div>\n      </div>\n    </div>\n    <div></div>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-dist-inside-deep-tree'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-no-dist\">\n  <template><span id=\"static\">x-no-dist</span></template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-no-dist'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-compose-dist\">\n  <template>\n    <x-dist id=\"dist\"></x-dist>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-compose-dist'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-compose-no-dist\">\n  <template>\n    <x-no-dist id=\"noDist\"></x-no-dist>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-compose-no-dist'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-dynamic-content\">\n  <template>\n    <div>\n      <div>\n        <div>\n          <div id=\"container\">\n            <template is=\"dom-if\" id=\"domif\">\n              <slot name=\"insert\" id=\"dynamicContent\"></slot>\n            </template>\n          </div>\n        </div>\n      </div>\n    </div>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-dynamic-content'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-dynamic-content-wrapped\">\n  <template>\n    <div>\n      <template is=\"dom-if\" id=\"domif\">\n        <div id=\"container\">\n          <slot name=\"insert\"></slot>\n        </div>\n      </template>\n    </div>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-dynamic-content-wrapped'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-dynamic-content-redist\">\n  <template>\n    <x-dynamic-content id=\"redistContainer\">\n      <template is=\"dom-if\" id=\"redistDomif\">\n        <slot name=\"insert\" id=\"redistContent\"></slot>\n      </template>\n    </x-dynamic-content>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-dynamic-content-redist'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-dynamic-content-redist-element\">\n  <template>\n    <template is=\"dom-if\" id=\"redistDomif\">\n      <x-dist id=\"redistContainer\">\n        <slot name=\"insert\" id=\"redistContent\"></slot>\n      </x-dist>\n    </template>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-dynamic-content-redist-element'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-dynamic-content-and-dynamic-no-content\">\n  <template>\n    <div id=\"container\">\n      <template is=\"dom-if\" id=\"staticIf\" restamp>\n        <div id=\"static\">static</div>\n      </template>\n      <template is=\"dom-if\" id=\"contentIf\" restamp>\n        <slot name=\"one\"></slot>\n      </template>\n    </div>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-dynamic-content-and-dynamic-no-content'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-multi-dist\">\n  <template>\n    <x-dist id=\"dist1\"><slot id=\"content1\"></slot></x-dist>\n    <x-dist id=\"dist2\"><slot id=\"content2\"></slot></x-dist>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-multi-dist'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-lazy-no-dist\">\n  <template>\n    Lazy no dist!\n  </template>\n</dom-module>\n\n<dom-module id=\"x-compose-lazy-no-dist\">\n  <template>\n    <x-lazy-no-dist id=\"lazy\">\n      <slot></slot>\n    </x-lazy-no-dist>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-compose-lazy-no-dist'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-toggle-if\">\n  <template>\n    <div id=\"container1\">\n      <template id=\"foo\" is=\"dom-if\" if=\"{{foo}}\" restamp>\n        <span>foo</span>\n        <slot id=\"1.1\" name=\"one\"></slot>\n        <slot id=\"1.2\" name=\"two\"></slot>\n      </template>\n    </div>\n    <div id=\"container2\">\n      <template id=\"notFoo\" is=\"dom-if\" if=\"{{!foo}}\" restamp>\n        <span>Not foo</span>\n        <slot id=\"2.1\" name=\"one\"></slot>\n        <slot id=\"2.2\" name=\"two\"></slot>\n      </template>\n    </div>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-toggle-if',\n  properties: {\n    foo: {\n      type: Boolean,\n      value: true\n    }\n  }\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-repeat\">\n  <template>\n    <x-dist-inside-deep-tree id=\"dist\">\n      <template is=\"dom-repeat\" items=\"{{items}}\"><div>{{item}}</div></template>\n    </x-dist-inside-deep-tree>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-repeat',\n  properties: {\n    items: {\n      type: Array,\n      value: [\"ITEM1\", \"ITEM2\", \"ITEM3\"]\n    }\n  }\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-repeat2\">\n  <template>\n    <x-dist-star id=\"dist\">\n      <template is=\"dom-repeat\" items=\"{{items}}\">\n        <div>{{item}}</div>\n      </template>\n    </x-dist-star>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-repeat2',\n  properties: {\n    items: {\n      type: Array,\n      value: [\"ITEM1\", \"ITEM2\", \"ITEM3\"]\n    }\n  }\n});\n</script>\n</dom-module>\n\n<x-repeat2 id=\"repeat2\"></x-repeat2>\n\n<x-compose-lazy-no-dist><span>Child</span></x-compose-lazy-no-dist>\n\n<script>\n  if (!window.ShadyDOM) {\n    ShadyDOM = {\n      patch: function() {},\n      flush: function() {}\n    };\n  }\n</script>\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nimport { flush } from '../../lib/utils/flush.js';\nfunction createPatchedDocumentFragment() {\n  var frag = document.createDocumentFragment();\n  return frag;\n}\n\nsuite('appendChild & removeChild of <slot>', function() {\n\n  test('append div to distributing element', function() {\n    var dist = document.createElement('x-dist');\n    document.body.appendChild(dist);\n    // Distribute div\n    var div = document.createElement('div');\n    dist.appendChild(div);\n    ShadyDOM.flush();\n    // Append to distributed div\n    var div2 = document.createElement('div');\n    div.appendChild(div2);\n    ShadyDOM.flush();\n    // Remove\n    dist.removeChild(div);\n    ShadyDOM.flush();\n    document.body.removeChild(dist);\n  });\n\n  test('append div to non-distributing element', function() {\n    var noDist = document.createElement('x-no-dist');\n    document.body.appendChild(noDist);\n    // Distribute div\n    var div = document.createElement('div');\n    noDist.appendChild(div);\n    ShadyDOM.flush();\n    // Append to distributed div\n    var div2 = document.createElement('div');\n    div.appendChild(div2);\n    ShadyDOM.flush();\n    // Remove\n    noDist.removeChild(div);\n    ShadyDOM.flush();\n    document.body.removeChild(noDist);\n  });\n\n  test('append div to shady root of distributing element', function() {\n    var dist = document.createElement('x-dist');\n    document.body.appendChild(dist);\n    // Append div to root\n    var div = document.createElement('div');\n    dist.root.appendChild(div);\n    ShadyDOM.flush();\n    // Append to div in root\n    var div2 = document.createElement('div');\n    div.appendChild(div2);\n    ShadyDOM.flush();\n    // Remove\n    dist.root.removeChild(div);\n    ShadyDOM.flush();\n    document.body.removeChild(dist);\n  });\n\n  test('append div to shady root of non-distributing element', function() {\n    var noDist = document.createElement('x-no-dist');\n    document.body.appendChild(noDist);\n    // Append div to root\n    var div = document.createElement('div');\n    noDist.root.appendChild(div);\n    ShadyDOM.flush();\n    // Append to div in root\n    var div2 = document.createElement('div');\n    div.appendChild(div2);\n    ShadyDOM.flush();\n    // Remove\n    noDist.root.removeChild(div);\n    ShadyDOM.flush();\n    document.body.removeChild(noDist);\n  });\n\n  test('append div to distributing element in root', function() {\n    var compose = document.createElement('x-compose-dist');\n    document.body.appendChild(compose);\n    // Distribute div\n    var div = document.createElement('div');\n    compose.$.dist.appendChild(div);\n    ShadyDOM.flush();\n    // Append to distributed div\n    var div2 = document.createElement('div');\n    div.appendChild(div2);\n    ShadyDOM.flush();\n    // Remove\n    compose.$.dist.removeChild(div);\n    ShadyDOM.flush();\n    document.body.removeChild(compose);\n  });\n\n  test('append div to non-distributing element in root', function() {\n    var compose = document.createElement('x-compose-no-dist');\n    document.body.appendChild(compose);\n    // Append div to root\n    var div = document.createElement('div');\n    compose.$.noDist.appendChild(div);\n    ShadyDOM.flush();\n    // Append to div in root\n    var div2 = document.createElement('div');\n    div.appendChild(div2);\n    ShadyDOM.flush();\n    // Remove\n    compose.$.noDist.removeChild(div);\n    ShadyDOM.flush();\n    document.body.removeChild(compose);\n  });\n\n  test('append slot to shady root of element (div first)', function() {\n    var noDist = document.createElement('x-no-dist');\n    document.body.appendChild(noDist);\n    // Append div to light dom\n    var div = document.createElement('div');\n    div.name = 'insert';\n    noDist.appendChild(div);\n    ShadyDOM.flush();\n    // Append slot to shady root\n    var slot = document.createElement('slot');\n    slot.setAttribute('name', 'insert');\n    noDist.root.appendChild(slot);\n    ShadyDOM.flush();\n    // Remove\n    noDist.root.removeChild(slot);\n    ShadyDOM.flush();\n    document.body.removeChild(noDist);\n  });\n\n  test('append slot to shady root of element (slot first)', function() {\n    var noDist = document.createElement('x-no-dist');\n    document.body.appendChild(noDist);\n    // Append slot to shady root\n    var slot = document.createElement('slot');\n    slot.setAttribute('name', 'insert');\n    noDist.root.appendChild(slot);\n    // Append div to light dom\n    var div = document.createElement('div');\n    div.name = 'insert';\n    noDist.appendChild(div);\n    ShadyDOM.flush();\n    // Remove\n    noDist.root.removeChild(slot);\n    ShadyDOM.flush();\n    document.body.removeChild(noDist);\n  });\n\n  test('append slot to div in shady root of element (div first)', function() {\n    var noDist = document.createElement('x-no-dist');\n    document.body.appendChild(noDist);\n    // Append div to light dom\n    var div = document.createElement('div');\n    div.name = 'insert';\n    noDist.appendChild(div);\n    ShadyDOM.flush();\n    // Append slot to shady root\n    var slot = document.createElement('slot');\n    slot.setAttribute('name', 'insert');\n    noDist.$.static.appendChild(slot);\n    ShadyDOM.flush();\n    // Remove\n    noDist.$.static.removeChild(slot);\n    ShadyDOM.flush();\n    document.body.removeChild(noDist);\n  });\n\n  test('append slot to div in shady root of element (slot first)', function() {\n    var noDist = document.createElement('x-no-dist');\n    document.body.appendChild(noDist);\n    // Append slot to shady root\n    var slot = document.createElement('slot');\n    slot.setAttribute('name', 'insert');\n    noDist.$.static.appendChild(slot);\n    // Append div to light dom\n    var div = document.createElement('div');\n    div.name = 'insert';\n    noDist.appendChild(div);\n    ShadyDOM.flush();\n    // Remove\n    noDist.$.static.removeChild(slot);\n    ShadyDOM.flush();\n    document.body.removeChild(noDist);\n  });\n\n  test('append slot in fragment to shady root of element (div first)', function() {\n    var noDist = document.createElement('x-no-dist');\n    document.body.appendChild(noDist);\n    // Append div to light dom\n    var div = document.createElement('div');\n    div.name = 'insert';\n    noDist.appendChild(div);\n    ShadyDOM.flush();\n    // Append slot to shady root\n    var frag = document.createDocumentFragment();\n    var slot = document.createElement('slot');\n    slot.setAttribute('name', 'insert');\n    frag.appendChild(slot);\n    noDist.root.appendChild(frag);\n    ShadyDOM.flush();\n    // Remove\n    noDist.root.removeChild(slot);\n    ShadyDOM.flush();\n    document.body.removeChild(noDist);\n  });\n\n  test('append slot in fragment to shady root of element (slot first)', function() {\n    var noDist = document.createElement('x-no-dist');\n    document.body.appendChild(noDist);\n    // Append slot to shady root\n    var frag = document.createDocumentFragment();\n    var slot = document.createElement('slot');\n    slot.setAttribute('name', 'insert');\n    frag.appendChild(slot);\n    noDist.root.appendChild(frag);\n    // Append div to light dom\n    var div = document.createElement('div');\n    div.name = 'insert';\n    noDist.appendChild(div);\n    ShadyDOM.flush();\n\n    // Remove\n    noDist.root.removeChild(slot);\n    ShadyDOM.flush();\n\n    document.body.removeChild(noDist);\n  });\n\n  test('append wrapped slot to shady root of element (div first)', function() {\n    var noDist = document.createElement('x-no-dist');\n    document.body.appendChild(noDist);\n    // Append div to light dom\n    var div = document.createElement('div');\n    div.name = 'insert';\n    noDist.appendChild(div);\n    ShadyDOM.flush();\n    // Append slot to shady root\n    var frag = document.createDocumentFragment();\n    var wrapper = document.createElement('div');\n    var slot = document.createElement('slot');\n    slot.setAttribute('name', 'insert');\n    wrapper.appendChild(slot);\n    frag.appendChild(wrapper);\n    noDist.root.appendChild(frag);\n    ShadyDOM.flush();\n\n    // Remove\n    noDist.root.removeChild(wrapper);\n    ShadyDOM.flush();\n\n    document.body.removeChild(noDist);\n  });\n\n  test('append wrapped slot to shady root of element (slot first)', function() {\n    var noDist = document.createElement('x-no-dist');\n    document.body.appendChild(noDist);\n    // Append slot to shady root\n    var frag = document.createDocumentFragment();\n    var wrapper = document.createElement('div');\n    var slot = document.createElement('slot');\n    slot.setAttribute('name', 'insert');\n    wrapper.appendChild(slot);\n    frag.appendChild(wrapper);\n    noDist.root.appendChild(frag);\n    // Append div to light dom\n    var div = document.createElement('div');\n    div.name = 'insert';\n    noDist.appendChild(div);\n    ShadyDOM.flush();\n\n    // Remove\n    noDist.root.removeChild(wrapper);\n    ShadyDOM.flush();\n\n    document.body.removeChild(noDist);\n  });\n\n  test('append wrapped slot to div in shady root of element (div first)', function() {\n    var noDist = document.createElement('x-no-dist');\n    document.body.appendChild(noDist);\n    // Append div to light dom\n    var div = document.createElement('div');\n    div.name = 'insert';\n    noDist.appendChild(div);\n    ShadyDOM.flush();\n    // Append slot to shady root\n    var frag = document.createDocumentFragment();\n    var wrapper = document.createElement('div');\n    var slot = document.createElement('slot');\n    slot.setAttribute('name', 'insert');\n    wrapper.appendChild(slot);\n    frag.appendChild(wrapper);\n    noDist.$.static.appendChild(frag);\n    ShadyDOM.flush();\n\n    // Remove\n    noDist.$.static.removeChild(wrapper);\n    ShadyDOM.flush();\n\n    document.body.removeChild(noDist);\n  });\n\n  test('append wrapped slot to div in shady root of element (slot first)', function() {\n    var noDist = document.createElement('x-no-dist');\n    document.body.appendChild(noDist);\n    // Append slot to shady root\n    var frag = document.createDocumentFragment();\n    var wrapper = document.createElement('div');\n    var slot = document.createElement('slot');\n    slot.setAttribute('name', 'insert');\n    wrapper.appendChild(slot);\n    frag.appendChild(wrapper);\n    noDist.$.static.appendChild(frag);\n    // Append div to light dom\n    var div = document.createElement('div');\n    div.name = 'insert';\n    noDist.appendChild(div);\n    ShadyDOM.flush();\n\n    // Remove\n    noDist.$.static.removeChild(wrapper);\n    ShadyDOM.flush();\n\n    document.body.removeChild(noDist);\n  });\n\n  test('append slot to non-distributing element in shady root of composed element (div first)', function() {\n    var compose = document.createElement('x-compose-no-dist');\n    document.body.appendChild(compose);\n    // Append slot to light DOM of non-distributing element\n    var div = document.createElement('div');\n    div.name = 'insert';\n    compose.appendChild(div);\n    ShadyDOM.flush();\n    // Append slot to non-distributing element\n    var slot = document.createElement('slot');\n    slot.setAttribute('name', 'insert');\n    compose.$.noDist.appendChild(slot);\n    ShadyDOM.flush();\n\n    // Remove\n    compose.$.noDist.removeChild(slot);\n    ShadyDOM.flush();\n\n    document.body.removeChild(compose);\n  });\n\n  test('append slot to non-distributing element in shady root of composed element (slot first)', function() {\n    var compose = document.createElement('x-compose-no-dist');\n    document.body.appendChild(compose);\n    // Append slot to light DOM of non-distributing element\n    var slot = document.createElement('slot');\n    slot.setAttribute('name', 'insert');\n    compose.$.noDist.appendChild(slot);\n    // Append div to light dom\n    var div = document.createElement('div');\n    div.name = 'insert';\n    compose.appendChild(div);\n    ShadyDOM.flush();\n\n    // Remove\n    compose.$.noDist.removeChild(slot);\n    ShadyDOM.flush();\n\n    document.body.removeChild(compose);\n  });\n\n  test('append wrapped slot to non-distributing element in shady root of composed element (div first)', function() {\n    var compose = document.createElement('x-compose-no-dist');\n    document.body.appendChild(compose);\n    // Append div to light dom\n    var div = document.createElement('div');\n    div.name = 'insert';\n    compose.appendChild(div);\n    ShadyDOM.flush();\n    // Append slot to shady root\n    var frag = document.createDocumentFragment();\n    var wrapper = document.createElement('div');\n    var slot = document.createElement('slot');\n    slot.setAttribute('name', 'insert');\n    wrapper.appendChild(slot);\n    frag.appendChild(wrapper);\n    compose.$.noDist.appendChild(frag);\n    ShadyDOM.flush();\n\n    // Remove\n    compose.$.noDist.removeChild(wrapper);\n    ShadyDOM.flush();\n\n    document.body.removeChild(compose);\n  });\n\n  test('append wrapped slot to non-distributing element in shady root of composed element (slot first)', function() {\n    var compose = document.createElement('x-compose-no-dist');\n    document.body.appendChild(compose);\n    // Append slot to shady root\n    var frag = document.createDocumentFragment();\n    var wrapper = document.createElement('div');\n    var slot = document.createElement('slot');\n    slot.setAttribute('name', 'insert');\n    wrapper.appendChild(slot);\n    frag.appendChild(wrapper);\n    compose.$.noDist.appendChild(frag);\n    // Append div to light dom\n    var div = document.createElement('div');\n    div.name = 'insert';\n    compose.appendChild(div);\n    ShadyDOM.flush();\n\n    // Remove\n    compose.$.noDist.removeChild(wrapper);\n    ShadyDOM.flush();\n\n    document.body.removeChild(compose);\n  });\n\n  test('append slot to distributing element in shady root of composed element (div first)', function() {\n    var compose = document.createElement('x-compose-dist');\n    document.body.appendChild(compose);\n    // Append slot to light DOM of non-distributing element\n    var div = document.createElement('div');\n    div.name = 'insert';\n    compose.appendChild(div);\n    ShadyDOM.flush();\n    // Append slot to non-distributing element\n    var slot = document.createElement('slot');\n    slot.setAttribute('name', 'insert');\n    compose.$.dist.appendChild(slot);\n    ShadyDOM.flush();\n\n    // Remove\n    compose.$.dist.removeChild(slot);\n    ShadyDOM.flush();\n\n    document.body.removeChild(compose);\n  });\n\n  test('append slot to distributing element in shady root of composed element (slot first)', function() {\n    var compose = document.createElement('x-compose-dist');\n    document.body.appendChild(compose);\n    // Append slot to non-distributing element\n    var slot = document.createElement('slot');\n    slot.setAttribute('name', 'insert');\n    compose.$.dist.appendChild(slot);\n    // Append slot to light DOM of non-distributing element\n    var div = document.createElement('div');\n    div.name = 'insert';\n    compose.appendChild(div);\n    ShadyDOM.flush();\n\n    // Remove\n    compose.$.dist.removeChild(slot);\n    ShadyDOM.flush();\n\n    document.body.removeChild(compose);\n  });\n\n  test('append wrapped slot to distributing element in shady root of composed element (div first)', function() {\n    var compose = document.createElement('x-compose-dist');\n    document.body.appendChild(compose);\n    // Append div to light dom\n    var div = document.createElement('div');\n    div.name = 'insert';\n    compose.appendChild(div);\n    ShadyDOM.flush();\n    // Append slot to shady root\n    var frag = document.createDocumentFragment();\n    var wrapper = document.createElement('div');\n    var slot = document.createElement('slot');\n    slot.setAttribute('name', 'insert');\n    wrapper.appendChild(slot);\n    frag.appendChild(wrapper);\n    compose.$.dist.appendChild(frag);\n    ShadyDOM.flush();\n\n    // Remove\n    compose.$.dist.removeChild(wrapper);\n    ShadyDOM.flush();\n\n    document.body.removeChild(compose);\n  });\n\n  test('append wrapped slot to distributing element in shady root of composed element (slot first)', function() {\n    var compose = document.createElement('x-compose-dist');\n    document.body.appendChild(compose);\n    // Append slot to shady root\n    var frag = document.createDocumentFragment();\n    var wrapper = document.createElement('div');\n    var slot = document.createElement('slot');\n    slot.setAttribute('name', 'insert');\n    wrapper.appendChild(slot);\n    frag.appendChild(wrapper);\n    compose.$.dist.appendChild(frag);\n    // Append div to light dom\n    var div = document.createElement('div');\n    div.name = 'insert';\n    compose.appendChild(div);\n    ShadyDOM.flush();\n\n    // Remove\n    compose.$.dist.removeChild(wrapper);\n    ShadyDOM.flush();\n\n    document.body.removeChild(compose);\n  });\n\n  test('append slot to initially un-upgraded element', function() {\n    var lazyContainer = document.querySelector('x-compose-lazy-no-dist');\n    var child = lazyContainer.firstElementChild;\n    Polymer({is: 'x-lazy-no-dist'});\n    var slot = document.createElement('slot');\n    lazyContainer.$.lazy.root.appendChild(slot);\n    ShadyDOM.flush();\n    assert.equal(slot.assignedNodes({flatten: true})[1], child);\n\n  });\n\n  test('composed children distributed', function() {\n    var host = document.createElement('x-dist');\n    document.body.appendChild(host);\n    var s0 = document.createElement('span');\n    var frag = document.createDocumentFragment();\n    var s1 = document.createElement('span');\n    var s2 = document.createElement('span');\n    var s3 = document.createElement('span');\n    frag.appendChild(s1);\n    frag.appendChild(s2);\n    frag.appendChild(s3);\n    host.appendChild(s0);\n    host.insertBefore(frag, s0);\n    ShadyDOM.flush();\n\n    host.removeChild(s1);\n    host.removeChild(s2);\n    host.removeChild(s3);\n    ShadyDOM.flush();\n\n  });\n\n  test('composed children added but not distributed', function() {\n    var host = document.createElement('x-dist');\n    document.body.appendChild(host);\n    var s0 = document.createElement('span');\n    var frag = document.createDocumentFragment();\n    var s1 = document.createElement('span');\n    var s2 = document.createElement('span');\n    var s3 = document.createElement('span');\n    frag.appendChild(s1);\n    frag.appendChild(s2);\n    frag.appendChild(s3);\n    host.$.distWrapper.appendChild(s0);\n    host.$.distWrapper.insertBefore(frag, s0);\n    ShadyDOM.flush();\n\n    host.$.distWrapper.removeChild(s1);\n    host.$.distWrapper.removeChild(s2);\n    host.$.distWrapper.removeChild(s3);\n    ShadyDOM.flush();\n\n  });\n\n  test('moving children between distributing hosts', function() {\n    var h1 = document.createElement('x-dist');\n    var h2 = document.createElement('x-dist');\n    document.body.appendChild(h1);\n    document.body.appendChild(h2);\n    ShadyDOM.flush();\n    var d = document.createElement('div');\n    h1.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h1.childNodes.length, 1);\n    assert.equal(h1.firstElementChild, d);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h2.childNodes.length, 0);\n    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}).length, 0);\n    h2.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h2.childNodes.length, 1);\n    assert.equal(h2.firstElementChild, d);\n    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h1.childNodes.length, 0);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);\n    h1.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h1.childNodes.length, 1);\n    assert.equal(h1.firstElementChild, d);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h2.childNodes.length, 0);\n    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}).length, 0);\n    h2.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h2.childNodes.length, 1);\n    assert.equal(h2.firstElementChild, d);\n    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h1.childNodes.length, 0);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);\n    document.body.removeChild(h1);\n    document.body.removeChild(h2);\n  });\n\n  test('moving children between distributing hosts (parsed child)', function() {\n    var div = document.createElement('div');\n    div.innerHTML = '<x-dist><div></div></x-dist>';\n    var h1 = div.firstChild;\n    var h2 = document.createElement('x-dist');\n    document.body.appendChild(div);\n    document.body.appendChild(h2);\n    ShadyDOM.flush();\n    var d = h1.firstElementChild;\n    assert.equal(d.localName, 'div');\n    assert.equal(h1.childNodes.length, 1);\n    assert.equal(h1.firstElementChild, d);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h2.childNodes.length, 0);\n    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}).length, 0);\n    h2.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h2.childNodes.length, 1);\n    assert.equal(h2.firstElementChild, d);\n    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h1.childNodes.length, 0);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);\n    h1.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h1.childNodes.length, 1);\n    assert.equal(h1.firstElementChild, d);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h2.childNodes.length, 0);\n    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}).length, 0);\n    h2.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h2.childNodes.length, 1);\n    assert.equal(h2.firstElementChild, d);\n    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h1.childNodes.length, 0);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);\n    document.body.removeChild(div);\n    document.body.removeChild(h2);\n  });\n\n  test('moving children between distributing host and fragment', function() {\n    var h1 = document.createElement('x-dist');\n    var h2 = createPatchedDocumentFragment();\n    document.body.appendChild(h1);\n    ShadyDOM.flush();\n    var d = document.createElement('div');\n    h1.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h1.childNodes.length, 1);\n    assert.equal(h1.firstElementChild, d);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h2.childNodes.length, 0);\n    h2.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h2.childNodes.length, 1);\n    assert.equal(h2.firstChild, d);\n    assert.equal(h1.childNodes.length, 0);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);\n    h1.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h1.childNodes.length, 1);\n    assert.equal(h1.firstElementChild, d);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h2.childNodes.length, 0);\n    h2.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h2.childNodes.length, 1);\n    assert.equal(h2.firstChild, d);\n    assert.equal(h1.childNodes.length, 0);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);\n    document.body.removeChild(h1);\n  });\n\n  test('moving children between distributing host and fragment (parsed child)', function() {\n    var div = document.createElement('div');\n    div.innerHTML = '<x-dist><div></div></x-dist>';\n    var h1 = div.firstChild;\n    var h2 = createPatchedDocumentFragment();\n    document.body.appendChild(h1);\n    ShadyDOM.flush();\n    var d = h1.firstElementChild;\n    assert.equal(d.localName, 'div');\n    assert.equal(h1.childNodes.length, 1);\n    assert.equal(h1.firstElementChild, d);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h2.childNodes.length, 0);\n    h2.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h2.childNodes.length, 1);\n    assert.equal(h2.firstChild, d);\n    assert.equal(h1.childNodes.length, 0);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);\n    h1.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h1.childNodes.length, 1);\n    assert.equal(h1.firstElementChild, d);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h2.childNodes.length, 0);\n    h2.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h2.childNodes.length, 1);\n    assert.equal(h2.firstChild, d);\n    assert.equal(h1.childNodes.length, 0);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);\n    document.body.removeChild(h1);\n  });\n\n  test('moving children between distributing hosts with deep insertion points', function() {\n    var h1 = document.createElement('x-dist-inside-deep-tree');\n    var h2 = document.createElement('x-dist-inside-deep-tree');\n    document.body.appendChild(h1);\n    document.body.appendChild(h2);\n    ShadyDOM.flush();\n    var d = document.createElement('div');\n    h1.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h1.childNodes.length, 1);\n    assert.equal(h1.firstElementChild, d);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h2.childNodes.length, 0);\n    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}).length, 0);\n    h2.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h2.childNodes.length, 1);\n    assert.equal(h2.firstElementChild, d);\n    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h1.childNodes.length, 0);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);\n    h1.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h1.childNodes.length, 1);\n    assert.equal(h1.firstElementChild, d);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h2.childNodes.length, 0);\n    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}).length, 0);\n    h2.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h2.childNodes.length, 1);\n    assert.equal(h2.firstElementChild, d);\n    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h1.childNodes.length, 0);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);\n    document.body.removeChild(h1);\n    document.body.removeChild(h2);\n  });\n\n  test('moving children between distributing hosts with deep insertion points (parsed child)', function() {\n    var div = document.createElement('div');\n    div.innerHTML = '<x-dist-inside-deep-tree><div></div></x-dist-inside-deep-tree>';\n    var h1 = div.firstChild;\n    var h2 = document.createElement('x-dist-inside-deep-tree');\n    document.body.appendChild(div);\n    document.body.appendChild(h2);\n    ShadyDOM.flush();\n    var d = h1.firstElementChild;\n    assert.equal(d.localName, 'div');\n    assert.equal(h1.childNodes.length, 1);\n    assert.equal(h1.firstElementChild, d);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h2.childNodes.length, 0);\n    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}).length, 0);\n    h2.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h2.childNodes.length, 1);\n    assert.equal(h2.firstElementChild, d);\n    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h1.childNodes.length, 0);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);\n    h1.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h1.childNodes.length, 1);\n    assert.equal(h1.firstElementChild, d);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h2.childNodes.length, 0);\n    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}).length, 0);\n    h2.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h2.childNodes.length, 1);\n    assert.equal(h2.firstElementChild, d);\n    assert.deepEqual(h2.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h1.childNodes.length, 0);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);\n    document.body.removeChild(div);\n    document.body.removeChild(h2);\n  });\n\n  test('moving children between distributing host with deep insertion and fragment', function() {\n    var h1 = document.createElement('x-dist-inside-deep-tree');\n    var h2 = createPatchedDocumentFragment();\n    document.body.appendChild(h1);\n    ShadyDOM.flush();\n    var d = document.createElement('div');\n    h1.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h1.childNodes.length, 1);\n    assert.equal(h1.firstElementChild, d);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h2.childNodes.length, 0);\n    h2.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h2.childNodes.length, 1);\n    assert.equal(h2.firstChild, d);\n    assert.equal(h1.childNodes.length, 0);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);\n    h1.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h1.childNodes.length, 1);\n    assert.equal(h1.firstElementChild, d);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h2.childNodes.length, 0);\n    h2.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h2.childNodes.length, 1);\n    assert.equal(h2.firstChild, d);\n    assert.equal(h1.childNodes.length, 0);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);\n    document.body.removeChild(h1);\n  });\n\n  test('moving children between distributing host with deep insertion and fragment (parsed child)', function() {\n    var div = document.createElement('div');\n    div.innerHTML = '<x-dist-inside-deep-tree><div></div></x-dist-inside-deep-tree>';\n    var h1 = div.firstChild;\n    var h2 = createPatchedDocumentFragment();\n    document.body.appendChild(h1);\n    ShadyDOM.flush();\n    var d = h1.firstElementChild;\n    assert.equal(d.localName, 'div');\n    assert.equal(h1.childNodes.length, 1);\n    assert.equal(h1.firstElementChild, d);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h2.childNodes.length, 0);\n    h2.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h2.childNodes.length, 1);\n    assert.equal(h2.firstChild, d);\n    assert.equal(h1.childNodes.length, 0);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);\n    h1.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h1.childNodes.length, 1);\n    assert.equal(h1.firstElementChild, d);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h2.childNodes.length, 0);\n    h2.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h2.childNodes.length, 1);\n    assert.equal(h2.firstChild, d);\n    assert.equal(h1.childNodes.length, 0);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);\n    document.body.removeChild(h1);\n  });\n\n  test('moving children between distributing host with shallow insertion and fragment', function() {\n    var h1 = document.createElement('x-dist-simple');\n    var h2 = createPatchedDocumentFragment();\n    document.body.appendChild(h1);\n    ShadyDOM.flush();\n    var d = document.createElement('div');\n    h1.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h1.childNodes.length, 1);\n    assert.equal(h1.firstElementChild, d);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h2.childNodes.length, 0);\n    h2.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h2.childNodes.length, 1);\n    assert.equal(h2.firstChild, d);\n    assert.equal(h1.childNodes.length, 0);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);\n    h1.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h1.childNodes.length, 1);\n    assert.equal(h1.firstElementChild, d);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h2.childNodes.length, 0);\n    h2.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h2.childNodes.length, 1);\n    assert.equal(h2.firstChild, d);\n    assert.equal(h1.childNodes.length, 0);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);\n    document.body.removeChild(h1);\n  });\n\n  test('moving children between distributing host with shallow insertion and fragment (parsed child)', function() {\n    var div = document.createElement('div');\n    div.innerHTML = '<x-dist-simple><div></div></x-dist-simple>';\n    var h1 = div.firstChild;\n    var h2 = createPatchedDocumentFragment();\n    document.body.appendChild(h1);\n    ShadyDOM.flush();\n    var d = h1.firstElementChild;\n    assert.equal(d.localName, 'div');\n    assert.equal(h1.childNodes.length, 1);\n    assert.equal(h1.firstElementChild, d);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h2.childNodes.length, 0);\n    h2.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h2.childNodes.length, 1);\n    assert.equal(h2.firstChild, d);\n    assert.equal(h1.childNodes.length, 0);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);\n    h1.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h1.childNodes.length, 1);\n    assert.equal(h1.firstElementChild, d);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}), [d]);\n    assert.equal(h2.childNodes.length, 0);\n    h2.appendChild(d);\n    ShadyDOM.flush();\n    assert.equal(h2.childNodes.length, 1);\n    assert.equal(h2.firstChild, d);\n    assert.equal(h1.childNodes.length, 0);\n    assert.deepEqual(h1.$.content.assignedNodes({flatten: true}).length, 0);\n    document.body.removeChild(h1);\n  });\n\n  test('moving an element containing a dom-repeat that distributes items', function() {\n    var x1 = document.createElement('x-repeat');\n    var div = document.createElement('div');\n    document.body.appendChild(x1);\n    document.body.appendChild(div);\n    flush();\n    assert.equal(x1.$.dist.children.length, 4);\n\n    div.appendChild(x1);\n    ShadyDOM.flush();\n    assert.equal(x1.$.dist.children.length, 4);\n\n    document.body.appendChild(x1);\n    ShadyDOM.flush();\n    assert.equal(x1.$.dist.children.length, 4);\n\n    div.appendChild(x1);\n    ShadyDOM.flush();\n    assert.equal(x1.$.dist.children.length, 4);\n\n    document.body.removeChild(div);\n  });\n\n  test('dom-repeat that distributes inside a slot container', function(done) {\n    var x1 = document.querySelector('#repeat2');\n    ShadyDOM.flush();\n    // async due to attachment.\n    setTimeout(function() {\n      assert.equal(x1.$.dist.children.length, 4);\n\n      done();\n    });\n  });\n\n  test('adding a document fragment clears nodes in the fragment', function() {\n    var x = document.createElement('x-dist-star');\n    document.body.appendChild(x);\n    var frag = document.createDocumentFragment();\n    var t = document.createTextNode('hi');\n    var d = document.createElement('div');\n    frag.appendChild(t);\n    frag.appendChild(d);\n    x.appendChild(frag);\n    ShadyDOM.flush();\n    assert.equal(t.parentNode, x, 'logical parent wrong');\n    assert.equal(d.parentNode, x, 'logical parent wrong');\n    assert.equal(frag.childNodes.length, 0, 'fragment not empty');\n    document.body.removeChild(x);\n  });\n\n  test('adding a non-distributing node removes the node from its current location', function() {\n    var x = document.createElement('x-dist-star');\n    var t = document.createTextNode('hi');\n    document.body.appendChild(t);\n    x.appendChild(t);\n    ShadyDOM.flush();\n    assert.equal(t.parentNode, x);\n\n  });\n\n});\n\nsuite('multi-content mutations', function() {\n\n  test('remove, append first content', function() {\n    var el = document.createElement('x-multi-dist');\n    document.body.appendChild(el);\n    // Append div\n    var div = document.createElement('div');\n    el.appendChild(div);\n    ShadyDOM.flush();\n\n    // Remove first content\n    el.$.dist1.removeChild(el.$.content1);\n    ShadyDOM.flush();\n\n    // Re-add a new first content\n    el.$.dist1.appendChild(document.createElement('slot'));\n    ShadyDOM.flush();\n\n  });\n\n  test('remove, append first distributing element', function() {\n    var el = document.createElement('x-multi-dist');\n    document.body.appendChild(el);\n    // Append div\n    var div = document.createElement('div');\n    el.appendChild(div);\n    ShadyDOM.flush();\n\n    // Remove first element with nested content\n    el.root.removeChild(el.$.dist1);\n    ShadyDOM.flush();\n\n    // Re-add a new first content\n    var frag = document.createDocumentFragment();\n    var dist = document.createElement('x-dist');\n    dist.appendChild(document.createElement('slot'));\n    frag.appendChild(dist);\n    el.root.insertBefore(frag, el.$.dist2);\n    // Note, special call required here\n    ShadyDOM.flush();\n\n  });\n\n  test('move first distributing element', function() {\n    var el = document.createElement('x-multi-dist');\n    document.body.appendChild(el);\n    // Append div\n    var div = document.createElement('div');\n    el.appendChild(div);\n    ShadyDOM.flush();\n\n    // Remove first element with nested content to the end\n    el.root.appendChild(el.$.dist1);\n    // Note, special call required here\n    ShadyDOM.flush();\n\n  });\n\n});\n\nsuite('dom-if append <slot>', function() {\n\n  test('x-dynamic-content', function() {\n    var el = document.createElement('x-dynamic-content');\n    document.body.appendChild(el);\n    var div = document.createElement('div');\n    div.name = 'insert';\n    el.appendChild(div);\n\n    el.$.domif.if = true;\n    el.$.domif.render();\n    ShadyDOM.flush();\n\n    document.body.removeChild(el);\n  });\n\n  test('x-dynamic-content-wrapped', function() {\n    var el = document.createElement('x-dynamic-content-wrapped');\n    document.body.appendChild(el);\n    var div = document.createElement('div');\n    div.name = 'insert';\n    el.appendChild(div);\n\n    el.$.domif.if = true;\n    el.$.domif.render();\n    ShadyDOM.flush();\n\n    document.body.removeChild(el);\n  });\n\n  test('x-dynamic-content-redist', function() {\n    var el = document.createElement('x-dynamic-content-redist');\n    document.body.appendChild(el);\n    var div = document.createElement('div');\n    div.name = 'insert';\n    el.appendChild(div);\n\n    el.$.redistDomif.if = true;\n    el.$.redistContainer.$.domif.if = true;\n    el.$.redistDomif.render();\n    ShadyDOM.flush();\n\n    document.body.removeChild(el);\n  });\n\n  test('x-dynamic-content-redist-element', function() {\n    var el = document.createElement('x-dynamic-content-redist-element');\n    document.body.appendChild(el);\n    var div = document.createElement('div');\n    div.name = 'insert';\n    el.appendChild(div);\n\n    el.$.redistDomif.if = true;\n    el.$.redistDomif.render();\n    ShadyDOM.flush();\n\n    document.body.removeChild(el);\n  });\n\n  test('x-toggle-if', function() {\n    var el = document.createElement('x-toggle-if');\n    document.body.appendChild(el);\n    var c1 = document.createElement('div');\n    c1.id = 'one';\n    el.appendChild(c1);\n    var c2 = document.createElement('div');\n    c2.id = 'two';\n    el.appendChild(c2);\n    el.$.foo.render();\n    el.$.notFoo.render();\n    ShadyDOM.flush();\n\n    el.foo = false;\n    el.$.foo.render();\n    el.$.notFoo.render();\n    ShadyDOM.flush();\n\n    el.foo = true;\n    el.$.foo.render();\n    el.$.notFoo.render();\n    ShadyDOM.flush();\n\n    el.foo = false;\n    el.$.foo.render();\n    el.$.notFoo.render();\n    ShadyDOM.flush();\n\n    el.foo = true;\n    el.$.foo.render();\n    el.$.notFoo.render();\n    ShadyDOM.flush();\n\n    document.body.removeChild(el);\n  });\n\n  test('x-dynamic-content-and-dynamic-no-content', function() {\n    var el = document.createElement('x-dynamic-content-and-dynamic-no-content');\n    document.body.appendChild(el);\n    var c1 = document.createElement('div');\n    c1.slot = 'one';\n    el.appendChild(c1);\n    flush();\n    assert.equal(el.querySelector('[slot=\"one\"]'), c1);\n    assert.notOk(el.root.querySelector('#static'));\n    assert.notOk(el.root.querySelector('slot'));\n    el.$.contentIf.if = true;\n    el.$.staticIf.if = true;\n    flush();\n    assert.ok(el.root.querySelector('#static'));\n    var ip = el.root.querySelector('slot');\n    assert.ok(ip);\n    assert.equal(ip.assignedNodes({flatten: true})[0], c1);\n    el.$.contentIf.if = false;\n    el.$.staticIf.if = false;\n    flush();\n    assert.equal(el.querySelector('[slot=\"one\"]'), c1);\n    assert.notOk(el.root.querySelector('#static'));\n    assert.notOk(el.root.querySelector('slot'));\n    el.$.contentIf.if = true;\n    el.$.staticIf.if = true;\n    flush();\n    assert.ok(el.root.querySelector('#static'));\n    ip = el.root.querySelector('slot');\n    assert.ok(ip);\n    assert.equal(ip.assignedNodes({flatten: true})[0], c1);\n    document.body.removeChild(el);\n  });\n\n});\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/shady-dynamic.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script>\n    if (window.customElements) {\n      customElements.forcePolyfill = true;\n    }\n    window.ShadyDOM = {\n      force: true\n    };\n  </script>\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\">\n    import {setSyncInitialRender} from '../../lib/utils/settings.js';\n    window.syncInitialRender = Boolean(window.location.search.match('syncInitialRender'));\n    setSyncInitialRender(window.syncInitialRender);\n  </script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n</head>\n<body>\n\n<dom-module id=\"x-project\">\n  <template strip-whitespace>x-project: [<slot></slot>]</template>\n</dom-module>\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-project'\n});\n</script>\n\n<dom-module id=\"x-reproject\">\n  <template strip-whitespace>\n    <x-project>x-reproject: [<slot></slot>]</x-project>\n  </template>\n</dom-module>\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-reproject'\n});\n</script>\n\n<dom-module id='x-rereproject'>\n  <template strip-whitespace>\n    <x-reproject>x-rereproject: [<slot></slot>]</x-reproject>\n  </template>\n</dom-module>\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-rereproject',\n  attachedCount: 0,\n  attached: function() {\n    this.attachedCount++;\n  }\n});\n</script>\n\n<dom-module id=\"x-test\">\n  <template strip-whitespace>\n    <x-rereproject><span id=\"projected\">projected</span></x-rereproject>\n  </template>\n</dom-module>\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-test'\n});\n</script>\n\n<dom-module id=\"x-test-no-distribute\">\n  <template>\n    <span>Local dom without insertion point.</span>\n  </template>\n</dom-module>\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-test-no-distribute'\n});\n</script>\n\n<dom-module id=\"x-distribute\">\n  <template>\n    <div>\n      <span>Elements without test attribute</span>\n      <div id=\"notTestContainer\" style=\"color: white; background-color: green; min-height: 1em;\">\n        <slot id=\"notTestContent\"></slot>\n      </div>\n      <span>Elements with test attribute</span>\n      <div style=\"color: white; background-color: red; min-height: 1em;\">\n        <div id=\"testContainer\">\n          <slot id=\"testContent\" name=\"test\"></slot>\n        </div>\n      </div>\n    </div>\n  </template>\n</dom-module>\n\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: \"x-distribute\"\n});\n</script>\n\n<dom-module id=\"x-compose\">\n  <template><x-project id=\"project\"></x-project></template>\n</dom-module>\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-compose'\n});\n</script>\n\n\n<dom-module id=\"x-select3\">\n  <template><slot id=\"x-select3-slot\" name=\"s3\"></slot></template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-select3'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-select2\">\n  <template><x-select3 id=\"select\"><slot id=\"x-select2-slot\" name=\"s2\"></slot></x-select3></template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-select2'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-select1\">\n  <template><x-select2 id=\"select\"><slot id=\"x-select1-slot\" name=\"s1\"></slot></x-select2></template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-select1'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-echo\">\n  <template><slot></slot></template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-echo'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-simple\">\n  <template><div>simple</div></template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-simple'});\n</script>\n</dom-module>\n\n\n<dom-module id=\"x-redistribute-a-b\">\n  <template>\n    <x-echo id=\"echo1\"><slot name=\"a\"></slot></x-echo>\n    <x-echo id=\"echo2\"><slot name=\"b\"></slot></x-echo>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-redistribute-a-b'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-attr\">\n  <template>Attr1</template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-attr',\n  hostAttributes: {\n    slot: 'bar'\n  }\n\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-attr2\">\n  <template>Attr2</template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-attr2',\n  // TODO(sorvell): cannot put `slot` into properties because it is patched.\n  ready: function() {\n    this.slot = 'foo';\n  }\n\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-select-attr\">\n  <template>\n    Foo: [<slot name=\"foo\"></slot>]\n    Bar: [<slot name=\"bar\"></slot>]\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-select-attr'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-compose-select-attr\">\n  <template>\n    <x-select-attr id=\"select\">\n      <x-attr id=\"attr1\"></x-attr>\n      <x-attr2 id=\"attr2\"></x-attr2>\n    </x-select-attr>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-compose-select-attr'});\n</script>\n</dom-module>\n\n\n<dom-module id=\"x-clonate\">\n  <template><span>[</span><slot></slot><span>]</span></template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-clonate'\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-attach3\">\n  <template>\n    <style>\n      :host {\n        display: block;\n        border: 1px dashed orange;\n        padding: 4px;\n        box-sizing: border-box;\n      }\n\n      :host > ::slotted(.add3) {\n        box-sizing: border-box;\n        height: 20px;\n        background: #333;\n        border: 2px solid yellow;\n      }\n    </style>\n    <slot></slot>\n    <template is=\"dom-if\" if=\"{{shouldIf(done.count)}}\">\n      <x-attach2></x-attach2>\n    </template>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-attach3',\n  properties: {\n    done: {value: {count: 0}}\n  },\n  ready: function() {\n    this.done.count++;\n  },\n  attached: function() {\n    var d = document.createElement('div');\n    d.className = 'add3';\n    this.appendChild(d);\n  },\n  shouldIf: function(x) {\n    return x < 3;\n  }\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-attach2\">\n  <template>\n    <style>\n      :host {\n        display: block;\n        border: 1px dashed tomato;\n        padding: 4px;\n      }\n\n      x-attach3 > ::slotted(.add2) {\n        box-sizing: border-box;\n        height: 20px;\n        background: gray;\n        border: 2px solid yellow;\n      }\n    </style>\n    <x-attach3><slot></slot></x-attach3>\n    <template is=\"dom-if\" if=\"{{shouldIf(done.count)}}\">\n      <x-attach1></x-attach1>\n    </template>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-attach2',\n  properties: {\n    done: {value: {count: 0}}\n  },\n  ready: function() {\n    this.done.count++;\n  },\n  attached: function() {\n    var d = document.createElement('div');\n    d.className = 'add2';\n    this.appendChild(d);\n  },\n  shouldIf: function(x) {\n    return x < 3;\n  }\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-attach1\">\n  <template>\n    <style>\n      :host {\n        display: block;\n        border: 1px dashed seagreen;\n        padding: 4px;\n      }\n\n      .slotContainer ::slotted(.add1) {\n        box-sizing: border-box;\n        height: 20px;\n        background: lightgray;\n        border: 2px solid yellow;\n      }\n    </style>\n    <x-attach2><div class=\"slotContainer\"><slot></slot><div></x-attach2>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-attach1',\n  attached: function() {\n    var d = document.createElement('div');\n    d.className = 'add1';\n    this.appendChild(d);\n  }\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-commented\">\n  <template><span>[</span><!--comment--><slot></slot></span><span>]</span></slot></template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-commented'});\n</script>\n</dom-module>\n\n\n<dom-module id=\"polymer-dom-repeat\">\n  <template>\n    <div>\n      <div>\n        <div>\n          <div id=\"container\">\n            <template id=\"repeater\" is=\"dom-repeat\" items=\"{{items}}\">\n              <div>stuff</div>\n            </template>\n          </div>\n        </div>\n      </div>\n    </div>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'polymer-dom-repeat',\n  properties: {\n    items: {\n      value: function() {\n        return ['a', 'b', 'c', 'd', 'e'];\n      }\n    }\n  }\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-deep-contains\">\n  <template>\n    <div id=\"shadowed\"></div>\n    <slot name=\"light\"></slot>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-deep-contains',\n  created: function() {\n    var e = document.createElement('div');\n    e.setAttribute('slot', 'light');\n    this.appendChild(e);\n    e = document.createElement('div');\n    e.setAttribute('slot', 'notdistributed');\n    this.appendChild(e);\n  }\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-wrapped\">\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-wrapped'\n});\n</script>\n</dom-module>\n\n\n<dom-module id=\"x-shadow-host-root-0-0\">\n  <template>\n    <slot></slot>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-shadow-host-root-0-0',\n  hostAttributes: {\n    tabindex: '-1'\n  }\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-shadow-host-root-0-0-light-0\">\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-shadow-host-root-0-0-light-0',\n  hostAttributes: {\n    tabindex: '-1'\n  }\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-shadow-host-root-0-0-light\">\n  <template>\n    <div>\n      <div>\n        <x-shadow-host-root-0-0-light-0></x-shadow-host-root-0-0-light-0>\n      </div>\n    </div>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-shadow-host-root-0-0-light',\n  hostAttributes: {\n    tabindex: '-1'\n  }\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-shadow-host-root-0-1\">\n  <template>\n    <slot></slot>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-shadow-host-root-0-1',\n  hostAttributes: {\n    tabindex: '-1'\n  }\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-shadow-host-root-0-1-light\">\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-shadow-host-root-0-1-light',\n  hostAttributes: {\n    tabindex: '-1'\n  }\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-shadow-host-root-0\">\n  <template>\n    <slot></slot>\n    <div>\n      <x-shadow-host-root-0-0>\n        <x-shadow-host-root-0-0-light></x-shadow-host-root-0-0-light>\n      </x-shadow-host-root-0-0>\n    </div>\n    <x-shadow-host-root-0-1>\n      <x-shadow-host-root-0-1-light></x-shadow-host-root-0-1-light>\n    </x-shadow-host-root-0-1>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-shadow-host-root-0',\n  hostAttributes: {\n    tabindex: '-1'\n  }\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-shadow-host-root-0-light\">\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-shadow-host-root-0-light',\n  hostAttributes: {\n    tabindex: '-1'\n  }\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-shadow-host-root-1-0\">\n  <template>\n    <slot></slot>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-shadow-host-root-1-0',\n  hostAttributes: {\n    tabindex: '-1'\n  }\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-shadow-host-root-1-0-light\">\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-shadow-host-root-1-0-light',\n  hostAttributes: {\n    tabindex: '-1'\n  }\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-shadow-host-root-1-1\">\n  <template>\n    <slot></slot>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-shadow-host-root-1-1',\n  hostAttributes: {\n    tabindex: '-1'\n  }\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-shadow-host-root-1-1-light\">\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-shadow-host-root-1-1-light',\n  hostAttributes: {\n    tabindex: '-1'\n  }\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-shadow-host-root-1\">\n  <template>\n    <slot></slot>\n    <div>\n      <x-shadow-host-root-1-0>\n        <x-shadow-host-root-1-0-light></x-shadow-host-root-1-0-light>\n      </x-shadow-host-root-1-0>\n    </div>\n    <div>\n      <div>\n        <div>\n          <x-shadow-host-root-1-1>\n            <x-shadow-host-root-1-1-light></x-shadow-host-root-1-1-light>\n          </x-shadow-host-root-1-1>\n        </div>\n      </div>\n    </div>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-shadow-host-root-1',\n  hostAttributes: {\n    tabindex: '-1'\n  }\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-shadow-host-root-1-light-0\">\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-shadow-host-root-1-light-0',\n  hostAttributes: {\n    tabindex: '-1'\n  }\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-shadow-host-root-1-light\">\n  <template>\n    <x-shadow-host-root-1-light-0></x-shadow-host-root-1-light-0>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-shadow-host-root-1-light',\n  hostAttributes: {\n    tabindex: '-1'\n  }\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-shadow-host-root\">\n  <template>\n    <slot></slot>\n    <div>\n      <div>\n        <x-shadow-host-root-0>\n          <x-shadow-host-root-0-light></x-shadow-host-root-0-light>\n        </x-shadow-host-root-0>\n      </div>\n    </div>\n    <div>\n      <x-shadow-host-root-1>\n        <x-shadow-host-root-1-light></x-shadow-host-root-1-light>\n      </x-shadow-host-root-1>\n    </div>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-shadow-host-root',\n  hostAttributes: {\n    tabindex: '-1'\n  }\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-shadow-host-root-light\">\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-shadow-host-root-light',\n  hostAttributes: {\n    tabindex: '-1'\n  }\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-outer\">\n  <template>\n    <x-inner id=\"inner\">\n      <slot></slot>\n    </x-inner>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-outer'\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-inner\">\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-inner',\n  attached: function(){\n    this.listen(this, 'click', '_onClick');\n  },\n  _onClick: function(event){\n    this._eventTarget = event.target;\n  }\n});\n</script>\n</dom-module>\n\n\n<x-test></x-test>\n\n<div class=\"accessors\">\n  <x-test-no-distribute><div class=\"child\"></div></x-test-no-distribute>\n  <x-project><div class=\"child\"></div></x-project>\n</div>\n\n<x-test-no-distribute id=\"noDistribute\">\n  <div class=\"bar\">Bar</div>\n  <div class=\"foo\">Foo</div>\n</x-test-no-distribute>\n\n<x-select1>\n  <div class=\"select-child\"></div>\n</x-select1>\n\n<x-select-class1>\n  <div></div>\n</x-select-class1>\n\n<x-select-attr>\n  <x-attr></x-attr>\n</x-select-attr>\n\n<x-compose-select-attr></x-compose-select-attr>\n\n<x-redistribute-a-b></x-redistribute-a-b>\n\n<div id=\"container\">\n  <x-echo></x-echo>\n  <span>1</span>\n  <span>2</span>\n</div>\n\n<x-deep-contains></x-deep-contains>\n\n<x-wrapped></x-wrapped>\n\n<x-shadow-host-root>\n  <x-shadow-host-root-light></x-shadow-host-root-light>\n</x-shadow-host-root>\n\n<x-outer>\n  <button>click me</button>\n</x-outer>\n<script>\n  if (!window.ShadyDOM) {\n    ShadyDOM = {\n      patch: function() {},\n      flush: function() {}\n    };\n  }\n</script>\n<script type=\"module\">\nimport { flush } from '../../lib/utils/flush.js';\nimport { dom } from '../../lib/legacy/polymer.dom.js';\n\nfunction createEnabledElement(tag) {\n  var e = document.createElement(tag);\n  document.body.appendChild(e);\n  document.body.removeChild(e);\n  return e;\n}\n\nfunction allInsertionPoints(e) {\n  var r = [];\n  while (e) {\n    e = e.assignedSlot;\n    if (e) {\n      r.push(e);\n    }\n  }\n  return r;\n}\n\nvar checkUnpatchedDom = false;\n\nsuite('ShadyDOM', function() {\n\nvar testElement;\n\nsuiteSetup(function() {\n  testElement = document.querySelector('x-test');\n});\n\ntest('querySelector (local)', function() {\n  var projected = testElement.root.querySelector('#projected');\n  assert.equal(projected.textContent, 'projected');\n  var p2 = testElement.querySelector('#projected');\n  assert.isNull(p2);\n  var rere = testElement.root.querySelector('x-rereproject');\n  assert.equal(rere.is, 'x-rereproject');\n  var re = rere.root.querySelector('x-reproject');\n  assert.equal(re.is, 'x-reproject');\n  var p = re.root.querySelector('x-project');\n  assert.equal(p.is, 'x-project');\n});\n\ntest('querySelectorAll (local)', function() {\n  var rere = testElement.root.querySelector('x-rereproject');\n  var re = rere.root.querySelector('x-reproject');\n  var p = re.root.querySelector('x-project');\n  var rereList = rere.root.querySelectorAll('*');\n  assert.include(rereList, re);\n  assert.equal(rereList.length, 2);\n  var reList = re.root.querySelectorAll('*');\n  assert.include(reList, p);\n  assert.equal(reList.length, 2);\n  var pList = p.root.querySelectorAll('*');\n  assert.equal(pList.length, 1);\n});\n\ntest('querySelector (light)', function() {\n  var projected = testElement.root.querySelector('#projected');\n  var rere = testElement.root.querySelector('x-rereproject');\n  var re = rere.root.querySelector('x-reproject');\n  var p = re.root.querySelector('x-project');\n  assert.equal(rere.querySelector('#projected'), projected);\n  assert(re.querySelector('slot'));\n  assert(p.querySelector('slot'));\n});\n\ntest('querySelectorAll (light)', function() {\n  var projected = testElement.root.querySelector('#projected');\n  var rere = testElement.root.querySelector('x-rereproject');\n  var re = rere.root.querySelector('x-reproject');\n  var p = re.root.querySelector('x-project');\n  assert.equal(rere.querySelectorAll('#projected')[0], projected);\n  assert(re.querySelectorAll('slot').length, 1);\n  assert(p.querySelectorAll('slot').length, 1);\n});\n\ntest('querySelectorAll with dom-repeat', function() {\n  var el = document.createElement('polymer-dom-repeat');\n  document.body.appendChild(el);\n  el.$.repeater.render();\n  flush();\n  assert.equal(el.$.container.querySelectorAll('*').length, 7, 'querySelectorAll finds repeated elements');\n  document.body.removeChild(el);\n});\n\ntest('querySelector document', function() {\n  assert.ok(document.querySelector('body'));\n});\n\ntest('projection', function() {\n  var projected = testElement.root.querySelector('#projected');\n  assert.equal(projected.textContent, 'projected');\n  var rere = testElement.root.querySelector('x-rereproject');\n  assert.equal(rere.is, 'x-rereproject');\n  var re = rere.root.querySelector('x-reproject');\n  assert.equal(re.is, 'x-reproject');\n  var p = re.root.querySelector('x-project');\n  assert.equal(p.is, 'x-project');\n  var c1 = rere.root.querySelector('slot');\n  assert.include(c1.assignedNodes({flatten: true}), projected);\n  var c2 = re.root.querySelector('slot');\n  assert.include(c2.assignedNodes({flatten: true}), projected);\n  var c3 = p.root.querySelector('slot');\n  assert.include(c3.assignedNodes({flatten: true}), projected);\n  var ip$ = [c1, c2, c3];\n  var as$ = allInsertionPoints(projected);\n  assert.deepEqual(as$, ip$);\n});\n\ntest('shadyRoot (reproject)', function() {\n  var select = document.querySelector('x-select1');\n  var child = select.firstElementChild;\n  var c1 = select.root.querySelector('slot');\n  var c2 = select.$.select.root.querySelector('slot');\n  var c3 = select.$.select.$.select.root.querySelector('slot');\n  assert.equal(c1.getAttribute('name'), 's1');\n  assert.equal(c2.getAttribute('name'), 's2');\n  assert.equal(c3.getAttribute('name'), 's3');\n  // var ip$ = [c1, c2, c3];\n  assert.equal(child.className, 'select-child');\n  assert.equal(allInsertionPoints(child).length, 0);\n  child.slot = 's1';\n  flush();\n  assert.deepEqual(allInsertionPoints(child), [c1]);\n  child.slot = 's2';\n  c1.setAttribute('name', 's2');\n  c1.slot = 's2';\n  flush();\n  assert.deepEqual(allInsertionPoints(child), [c1, c2]);\n  child.slot = 's3';\n  c1.setAttribute('name', 's3');\n  c1.slot = 's3';\n  c2.setAttribute('name', 's3');\n  c2.slot = 's3';\n  flush();\n  assert.deepEqual(allInsertionPoints(child), [c1, c2, c3]);\n  child.slot = '';\n  flush();\n  assert.deepEqual(allInsertionPoints(child), []);\n  child.slot = 's3';\n  flush();\n  assert.deepEqual(allInsertionPoints(child), [c1, c2, c3]);\n  child.slot = '';\n  flush();\n  assert.deepEqual(allInsertionPoints(child), []);\n  child.slot = 's2';\n  c1.setAttribute('name', 's2');\n  c1.slot = 's2';\n  c2.setAttribute('name', 's2');\n  c2.slot = 's2';\n  flush();\n  assert.deepEqual(allInsertionPoints(child), [c1, c2]);\n  child.slot = 's1';\n  c1.setAttribute('name', 's1');\n  c1.slot = 's1';\n  flush();\n  assert.deepEqual(allInsertionPoints(child), [c1]);\n  child.slot = '';\n  flush();\n  assert.deepEqual(allInsertionPoints(child), []);\n});\n\ntest('without a host setting hostAttributes/reflecting properties provokes distribution', function() {\n  var e = document.querySelector('x-select-attr');\n  var ip$ = e.root.querySelectorAll('slot');\n  var c = e.firstElementChild;\n  flush();\n  assert.equal(allInsertionPoints(c)[0], ip$[1], 'child not distributed based on host attribute');\n  c.slot = 'foo';\n  flush();\n  assert.equal(allInsertionPoints(c)[0], ip$[0], 'child not distributed based on reflecting attribute');\n  c.slot = '';\n  flush();\n  assert.equal(allInsertionPoints(c).length, 0, 'child not distributed based on reflecting attribute');\n});\n\ntest('within a host setting hostAttributes/reflecting properties provokes distribution', function() {\n  var e = document.querySelector('x-compose-select-attr');\n  var ip$ = e.$.select.root.querySelectorAll('slot');\n  var c1 = e.$.attr1;\n  flush();\n  assert.equal(allInsertionPoints(c1)[0], ip$[1], 'child not distributed based on host attribute');\n  c1.slot = 'foo';\n  flush();\n  assert.equal(allInsertionPoints(c1)[0], ip$[0], 'child not distributed based on reflecting attribute');\n  c1.slot = 'bar';\n  flush();\n  assert.equal(allInsertionPoints(c1)[0], ip$[1], 'child not distributed based on reflecting attribute');\n  var c2 = e.$.attr2;\n  flush();\n  assert.equal(allInsertionPoints(c2)[0], ip$[0], 'child not distributed based on default value');\n});\n\ntest('appendChild (light)', function() {\n  var rere = testElement.root.querySelector('x-rereproject');\n  var s = document.createElement('span');\n  s.id = 'added';\n  s.textContent = 'Added';\n  rere.appendChild(s);\n  assert.equal(testElement.root.querySelector('#added'), s);\n});\n\ntest('insertBefore (light)', function() {\n  var rere = testElement.root.querySelector('x-rereproject');\n  var ref = testElement.root.querySelector('#added');\n  var s = document.createElement('span');\n  s.id = 'added2';\n  s.textContent = 'Added2';\n  rere.insertBefore(s, ref);\n  assert.equal(testElement.root.querySelector('#added2'), s);\n});\n\ntest('removeChild (light)', function() {\n  var added = testElement.root.querySelector('#added');\n  var added2 = testElement.root.querySelector('#added2');\n  var rere = testElement.root.querySelector('x-rereproject');\n  assert.equal(testElement.root.querySelectorAll('*').length, 4);\n  rere.removeChild(added);\n  rere.removeChild(added2);\n  assert.equal(testElement.root.querySelectorAll('*').length, 2);\n});\n\ntest('appendChild (local)', function() {\n  var rere = testElement.root.querySelector('x-rereproject');\n  var s = document.createElement('span');\n  s.id = 'local';\n  s.textContent = 'Local';\n  rere.root.appendChild(s);\n  assert.equal(rere.root.querySelector('#local'), s);\n});\n\ntest('insertBefore (local)', function() {\n  var rere = testElement.root.querySelector('x-rereproject');\n  var ref = testElement.root.querySelector('#local');\n  var s = document.createElement('span');\n  s.id = 'local2';\n  s.textContent = 'Local2';\n  rere.root.insertBefore(s, ref);\n  assert.equal(rere.root.querySelector('#local2'), s);\n});\n\ntest('removeChild (local)', function() {\n  var rere = testElement.root.querySelector('x-rereproject');\n  var local = rere.root.querySelector('#local');\n  var local2 = rere.root.querySelector('#local2');\n  rere.root.removeChild(local);\n  rere.root.removeChild(local2);\n  assert.equal(rere.root.querySelectorAll('#local').length, 0);\n});\n\ntest('localDom.insertBefore first element results in minimal change', function() {\n  var children = testElement.root.childNodes;\n  var rere = testElement.root.querySelector('x-rereproject');\n  assert.equal(rere.attachedCount, 1);\n  var s = document.createElement('span');\n  s.id = 'local-first';\n  s.textContent = 'Local First';\n  testElement.root.insertBefore(s, children[0]);\n  assert.equal(testElement.root.querySelector('#local-first'), s);\n  assert.equal(rere.attachedCount, 1);\n  testElement.root.removeChild(s);\n  assert.equal(rere.attachedCount, 1);\n});\n\ntest('appendChild (fragment, local)', function() {\n  var rere = testElement.root.querySelector('x-rereproject');\n  var fragment = document.createDocumentFragment();\n  var childCount = 5;\n  for (var i=0; i < childCount; i++) {\n    var s = document.createElement('span');\n    s.textContent = i;\n    fragment.appendChild(s);\n  }\n  rere.root.appendChild(fragment);\n  var added = rere.root.querySelectorAll('span');\n  assert.equal(added.length, childCount);\n  for (i=0; i < added.length; i++) {\n    rere.root.removeChild(added[i]);\n  }\n  assert.equal(rere.root.querySelectorAll('span').length, 0);\n});\n\ntest('insertBefore (fragment, local)', function() {\n  var rere = testElement.root.querySelector('x-rereproject');\n  var fragment = document.createDocumentFragment();\n  var childCount = 5;\n  for (var i=0; i < childCount; i++) {\n    var s = document.createElement('span');\n    s.textContent = i;\n    fragment.appendChild(s);\n  }\n  var l = document.createElement('span');\n  l.textContent = 'last';\n  rere.root.appendChild(l);\n  rere.root.insertBefore(fragment, l);\n  var added = rere.root.querySelectorAll('span');\n  assert.equal(added.length, childCount+1);\n  assert.equal(added[added.length-1], l);\n  for (i=0; i < added.length; i++) {\n    rere.root.removeChild(added[i]);\n  }\n  assert.equal(rere.root.querySelectorAll('span').length, 0);\n});\n\ntest('mutations using fragments without logical dom', function() {\n  var d = document.createElement('div');\n  document.body.appendChild(d);\n  assert.equal(d.childNodes.length, 0);\n  var frag = document.createDocumentFragment();\n  var c = document.createElement('div');\n  frag.appendChild(c);\n  d.appendChild(frag);\n  assert.equal(d.childNodes.length, 1);\n  assert.equal(d.firstChild, c);\n  var c1 = document.createElement('div');\n  frag.appendChild(c1);\n  d.appendChild(frag);\n  assert.equal(d.childNodes.length, 2);\n  assert.equal(d.firstChild, c);\n  assert.equal(d.lastChild, c1);\n});\n\ntest('appendChild interacts with unmanaged parent tree', function() {\n  var container = document.querySelector('#container');\n  var echo = container.firstElementChild;\n  assert.equal(echo.localName, 'x-echo');\n  var s1 = echo.nextElementSibling;\n  assert.equal(s1.textContent, '1');\n  var s2 = s1.nextElementSibling;\n  assert.equal(s2.textContent, '2');\n  assert.equal(container.children.length, 3);\n  echo.appendChild(s1);\n  flush();\n  assert.equal(container.children.length, 2);\n  assert.equal(echo.nextElementSibling, s2);\n  echo.appendChild(s2);\n  flush();\n  assert.equal(container.children.length, 1);\n  assert.equal(echo.nextElementSibling, null);\n  container.appendChild(s1);\n  flush();\n  assert.equal(container.children.length, 2);\n  assert.equal(echo.nextElementSibling, s1);\n  container.appendChild(s2);\n  flush();\n  assert.equal(container.children.length, 3);\n  assert.equal(echo.nextElementSibling, s1);\n  assert.equal(s1.nextElementSibling, s2);\n});\n\ntest('distribute (forced)', function() {\n  var rere = testElement.root.querySelector('x-rereproject');\n  var re = rere.root.querySelector('x-reproject');\n  var p = re.root.querySelector('x-project');\n  var s = document.createElement('span');\n  s.id = 'light';\n  s.textContent = 'Light';\n  rere.appendChild(s);\n  assert.equal(rere.querySelector('#light'), s);\n  assert.equal(s.parentNode, rere);\n  if (checkUnpatchedDom) {\n    assert.notEqual(Polymer.TreeApi.Composed.getParentNode(s), rere);\n  }\n  if (checkUnpatchedDom) {\n    assert.equal(Polymer.TreeApi.Composed.getParentNode(s), p);\n  }\n  rere.removeChild(s);\n  if (checkUnpatchedDom) {\n    assert.equal(Polymer.TreeApi.Composed.getParentNode(s), p);\n  }\n  if (checkUnpatchedDom) {\n    assert.equal(Polymer.TreeApi.Composed.getParentNode(s), null);\n  }\n});\n\ntest('queryDistributedElements', function() {\n  var rere = testElement.root.querySelector('x-rereproject');\n  var re = rere.root.querySelector('x-reproject');\n  var p = re.root.querySelector('x-project');\n  var projected = testElement.root.querySelector('#projected');\n  var d$ = p.queryDistributedElements('*');\n  assert.equal(d$.length, 1);\n  assert.equal(d$[0], projected);\n\n});\n\ntest('getEffectiveChildNodes', function() {\n  var rere = testElement.root.querySelector('x-rereproject');\n  var re = rere.root.querySelector('x-reproject');\n  var projected = testElement.root.querySelector('#projected');\n  var c$ = re.getEffectiveChildNodes();\n  assert.equal(c$.length, 3);\n  assert.equal(c$[1], projected);\n});\n\ntest('querySelector', function() {\n  var test = document.querySelector('x-test');\n  var rere = document.querySelector('x-rereproject');\n  var projected = document.querySelector('#projected');\n  assert.ok(test);\n  assert.notOk(rere);\n  assert.notOk(projected);\n});\n\ntest('event', function() {\n  var rere = testElement.root.querySelector('x-rereproject');\n  var re = rere.root.querySelector('x-reproject');\n  var p = re.root.querySelector('x-project');\n  var eventHandled = 0;\n  testElement.addEventListener('test-event', function(e) {\n    eventHandled++;\n    assert.equal(e.composedPath()[0], p);\n    assert.equal(e.target, testElement);\n    var path = e.composedPath();\n    // path includes window only on more recent Shadow DOM implementations\n    // account for that here.\n    assert.ok(path.length >= 10);\n    assert.equal(path[0], p);\n    assert.equal(path[2], re);\n    assert.equal(path[4], rere);\n    assert.equal(path[6], testElement);\n    // event.path *should* be an array\n    assert.isArray(path);\n    assert.isFunction(path.indexOf);\n    assert(path.indexOf(testElement) > -1);\n  });\n\n  rere.addEventListener('test-event', function(e) {\n    eventHandled++;\n    assert.equal(e.target, rere);\n  });\n\n  p.fire('test-event');\n  assert.equal(eventHandled, 2);\n});\n\ntest('event.target', function() {\n  var e = document.querySelector('x-outer');\n  var b = document.querySelector('x-outer button');\n  b.dispatchEvent(new Event('click', {bubbles: true}));\n  assert.equal(e.$.inner._eventTarget.localName, 'button', 'event restarted incorrectly');\n});\n\ntest('parentNode', function() {\n  var rere = testElement.root.querySelector('x-rereproject');\n  var projected = testElement.root.querySelector('#projected');\n  assert.equal(testElement.parentNode, document.body);\n  assert.equal(projected.parentNode, rere);\n});\n\ntest('childNodes is an array', function() {\n  var test = document.querySelector('x-test');\n  assert.isTrue(Array.isArray(test.childNodes));\n});\n\ntest('cloneNode shallow', function() {\n  var a = document.createElement('div');\n  a.innerHTML = '<x-clonate><span>1</span><span>2</span></x-clonate>';\n  var b = a.firstElementChild.cloneNode();\n  document.body.appendChild(b);\n  assert.equal(b.childNodes.length, 0, 'shallow copy has incorrect children');\n  if (checkUnpatchedDom) {\n    assert.equal(b.children.length, 2, 'shallow copy has incorrect composed children');\n  }\n});\n\ntest('cloneNode deep', function() {\n  var a = document.createElement('div');\n  a.innerHTML = '<x-clonate><span>1</span><span>2</span></x-clonate>';\n  var b = a.cloneNode(true);\n  document.body.appendChild(b);\n  assert.equal(b.firstElementChild.childNodes.length, 2, 'deep copy has incorrect children');\n  if (checkUnpatchedDom) {\n    assert.equal(b.children.length, 4, 'deep copy has incorrect composed children');\n  }\n});\n\ntest('importNode shallow', function() {\n  var a = document.createElement('div');\n  a.innerHTML = '<x-clonate><span>1</span><span>2</span></x-clonate>';\n  // NOTE: Safari defaults do `deep` true for importNode so be explicit here.\n  var b = document.importNode(a.firstElementChild, false);\n  document.body.appendChild(b);\n  assert.equal(b.childNodes.length, 0, 'shallow import has incorrect children');\n  if (checkUnpatchedDom) {\n    assert.equal(b.children.length, 2, 'shallow import has incorrect composed children');\n  }\n});\n\ntest('importNode deep', function() {\n  var a = document.createElement('div');\n  a.innerHTML = '<x-clonate><span>1</span><span>2</span></x-clonate>';\n  var b = document.importNode(a, true);\n  document.body.appendChild(b);\n  assert.equal(b.firstElementChild.childNodes.length, 2, 'deep copy has incorrect children');\n  if (checkUnpatchedDom) {\n    assert.equal(b.children.length, 4, 'deep copy has incorrect composed children');\n  }\n});\n\ntest('styling: flush causes attached and re-flushes if necessary', function(done) {\n  var a = document.createElement('x-attach1');\n  document.body.appendChild(a);\n  flush();\n  assert.equal(a.offsetHeight, 540);\n  done();\n});\n\ntest('flush reentrancy', function() {\n  // Setup callbacks\n  var order = [];\n  var cb1 = sinon.spy(function() { order.push(cb1); });\n  var cb2 = sinon.spy(function() { order.push(cb2); });\n  var cb3 = sinon.spy(function() { order.push(cb3); });\n  var cb4 = sinon.spy(function() { order.push(cb4); });\n  var cbReentrant = sinon.spy(function() {\n    order.push(cbReentrant);\n    ShadyDOM.enqueue(cb3);\n    flush();\n    ShadyDOM.enqueue(cb4);\n  });\n  // Enqueue\n  ShadyDOM.enqueue(cb1);\n  ShadyDOM.enqueue(cbReentrant);\n  ShadyDOM.enqueue(cb2);\n  // Flush\n  flush();\n  // Check callbacks called and in correct order\n  assert.isTrue(cb1.calledOnce);\n  assert.isTrue(cb2.calledOnce);\n  assert.isTrue(cb3.calledOnce);\n  assert.isTrue(cb4.calledOnce);\n  assert.isTrue(cbReentrant.calledOnce);\n  assert.sameMembers(order, [cb1, cbReentrant, cb2, cb3, cb4]);\n});\n\ntest('event.composedPath correctly calculated for elements with destination insertion points', function(done) {\n  var re = document.createElement('x-reproject');\n  document.body.appendChild(re);\n  flush();\n  var p = re.root.querySelector('x-project');\n  var child = document.createElement('p');\n  child.innerHTML = \"hello\";\n  // child will be inserted into p after distributeContent is performed.\n  re.appendChild(child);\n  flush();\n  child.addEventListener('child-event', function(e){\n    var path = e.composedPath();\n    assert.isTrue(path.indexOf(p) !== -1, 'path contains p');\n    assert.isTrue(path.indexOf(re) !== -1, 'path contains re');\n    done();\n  });\n  var evt = new CustomEvent('child-event');\n  child.dispatchEvent(evt);\n  document.body.removeChild(re);\n});\n\ntest('initial distribution is synchronous when `syncInitialRender` is true', function() {\n  if (!window.syncInitialRender) {\n    this.skip();\n  }\n  const el = document.createElement('x-test');\n  document.body.appendChild(el);\n  let child = ShadyDOM.nativeTree.firstElementChild(el);\n  assert.equal(child.localName, 'x-rereproject');\n  child = ShadyDOM.nativeTree.firstElementChild(child);\n  assert.equal(child.localName, 'x-reproject');\n  child = ShadyDOM.nativeTree.firstElementChild(child);\n  assert.equal(child.localName, 'x-project');\n  assert.equal(ShadyDOM.nativeTree.textContent(child), 'x-project: [x-reproject: [x-rereproject: [projected]]]');\n  document.body.removeChild(el);\n});\n\n});\n\nsuite('Accessors', function() {\n  var noDistribute, distribute;\n\n  suiteSetup(function() {\n    noDistribute = document.querySelector('.accessors x-test-no-distribute');\n    distribute = document.querySelector('.accessors x-project');\n  });\n\n  test('node accessors (no distribute)', function() {\n    var child = noDistribute.children[0];\n    assert.isTrue(child.classList.contains('child'), 'test node could not be found');\n    var before = document.createElement('div');\n    var after = document.createElement('div');\n    noDistribute.insertBefore(before, child);\n    noDistribute.appendChild(after);\n    flush();\n    assert.equal(noDistribute.firstChild, before, 'firstChild incorrect');\n    assert.equal(noDistribute.lastChild, after, 'lastChild incorrect');\n    assert.equal(before.nextSibling, child, 'nextSibling incorrect');\n    assert.equal(child.nextSibling, after, 'nextSibling incorrect');\n    assert.equal(after.previousSibling, child, 'previousSibling incorrect');\n    assert.equal(after.nextSibling, null, 'nextSibling incorrect');\n    assert.equal(child.previousSibling, before, 'previousSibling incorrect');\n  });\n\n  test('node accessors (distribute)', function() {\n    var child = distribute.children[0];\n    assert.isTrue(child.classList.contains('child'), 'test node could not be found');\n    var before = document.createElement('div');\n    var after = document.createElement('div');\n    distribute.insertBefore(before, child);\n    distribute.appendChild(after);\n    flush();\n    assert.equal(distribute.firstChild, before, 'firstChild incorrect');\n    assert.equal(distribute.lastChild, after, 'lastChild incorrect');\n    assert.equal(before.nextSibling, child, 'nextSibling incorrect');\n    assert.equal(child.nextSibling, after, 'nextSibling incorrect');\n    assert.equal(after.previousSibling, child, 'previousSibling incorrect');\n    assert.equal(after.nextSibling, null, 'nextSibling incorrect');\n    assert.equal(child.previousSibling, before, 'previousSibling incorrect');\n  });\n\n  test('element accessors (no distribute)', function() {\n    var parent = document.createElement('x-test-no-distribute');\n    var child = document.createElement('div');\n    parent.appendChild(child);\n    var before = document.createElement('div');\n    var after = document.createElement('div');\n    parent.insertBefore(before, child);\n    parent.appendChild(after);\n    assert.equal(parent.firstElementChild, before, 'firstElementChild incorrect');\n    assert.equal(parent.lastElementChild, after, 'lastElementChild incorrect');\n    assert.equal(before.nextElementSibling, child, 'nextElementSibling incorrect');\n    assert.equal(child.nextElementSibling, after, 'nextElementSibling incorrect');\n    assert.equal(after.previousElementSibling, child, 'previousElementSibling incorrect');\n    assert.equal(child.previousElementSibling, before, 'previousElementSibling incorrect');\n  });\n\n  test('element accessors (distribute)', function() {\n    var parent = document.createElement('x-project');\n    var child = document.createElement('div');\n    parent.appendChild(child);\n    var before = document.createElement('div');\n    var after = document.createElement('div');\n    parent.insertBefore(before, child);\n    parent.appendChild(after);\n    assert.equal(parent.firstElementChild, before, 'firstElementChild incorrect');\n    assert.equal(parent.lastElementChild, after, 'lastElementChild incorrect');\n    assert.equal(before.nextElementSibling, child, 'nextElementSibling incorrect');\n    assert.equal(child.nextElementSibling, after, 'nextElementSibling incorrect');\n    assert.equal(after.previousElementSibling, child, 'previousElementSibling incorrect');\n    assert.equal(child.previousElementSibling, before, 'previousElementSibling incorrect');\n  });\n\n  test('node accessors (empty logical tree)', function() {\n    var element = document.createElement('x-simple');\n    assert.equal(element.parentNode, null, 'parentNode incorrect');\n    assert.equal(element.firstChild, null, 'firstChild incorrect');\n    assert.equal(element.lastChild, null, 'lastChild incorrect');\n    assert.equal(element.nextSibling, null, 'nextSibling incorrect');\n    assert.equal(element.previousSibling, null, 'previousSibling incorrect');\n    assert.equal(element.firstElementChild, null, 'firstElementChild incorrect');\n    assert.equal(element.lastElementChild, null, 'lastElementChild incorrect');\n    assert.equal(element.nextElementSibling, null, 'nextElementSibling incorrect');\n    assert.equal(element.previousElementSibling, null, 'previousElementSibling incorrect');\n  });\n\n  test('node accessors (unmanaged logical tree)', function() {\n    var element = document.createElement('div');\n    var child1 = document.createElement('div');\n    var child2 = document.createElement('div');\n    element.appendChild(child1);\n    element.appendChild(child2);\n    assert.equal(element.parentNode, null, 'parentNode incorrect');\n    assert.equal(element.firstChild, child1, 'firstChild incorrect');\n    assert.equal(element.lastChild, child2, 'lastChild incorrect');\n    assert.equal(element.nextSibling, null, 'nextSibling incorrect');\n    assert.equal(element.previousSibling, null, 'previousSibling incorrect');\n    assert.equal(element.firstElementChild, child1, 'firstElementChild incorrect');\n    assert.equal(element.lastElementChild, child2, 'lastElementChild incorrect');\n    assert.equal(element.nextElementSibling, null, 'nextElementSibling incorrect');\n    assert.equal(element.previousElementSibling, null, 'previousElementSibling incorrect');\n  });\n\n  test('textContent', function() {\n    var testElement = document.createElement('x-project');\n    testElement.textContent = 'Hello World';\n    assert.equal(testElement.textContent, 'Hello World', 'textContent getter incorrect');\n    if (checkUnpatchedDom) {\n      flush();\n      assert.equal(Polymer.TreeApi.Composed.getChildNodes(testElement)[1].textContent, 'Hello World', 'text content setter incorrect');\n    }\n    testElement = createEnabledElement('x-commented');\n    assert.equal(testElement.root.textContent, '[]', 'text content getter with comment incorrect');\n\n    var textNode = document.createTextNode('foo');\n    assert.equal(textNode.textContent, 'foo', 'text content getter on textnode incorrect');\n    textNode.textContent = 'bar';\n    assert.equal(textNode.textContent, 'bar', 'text content setter on textnode incorrect');\n\n    var commentNode = document.createComment('foo');\n    assert.equal(commentNode.textContent, 'foo', 'text content getter on commentnode incorrect');\n    commentNode.textContent = 'bar';\n    assert.equal(commentNode.textContent, 'bar', 'text content setter on commentnode incorrect');\n  });\n\n  test('innerHTML', function() {\n    var testElement = document.createElement('x-project');\n    testElement.innerHTML = '<div>Hello World</div><div>2</div><div>3</div>';\n    var added = testElement.firstChild;\n    assert.equal(added.textContent , 'Hello World', 'innerHTML setter incorrect');\n    assert.equal(testElement.innerHTML , '<div>Hello World</div><div>2</div><div>3</div>', 'innerHTML getter incorrect');\n    if (checkUnpatchedDom) {\n      flush();\n      var children = Polymer.TreeApi.Composed.getChildNodes(testElement);\n      assert.equal(children[1], added, 'innerHTML setter composed incorrectly');\n      assert.equal(children[2].textContent, '2', 'innerHTML setter composed incorrectly');\n      assert.equal(children[3].textContent, '3', 'innerHTML setter composed incorrectly');\n    }\n  });\n\n  test('innerHTML (non-composed)', function() {\n    var testElement = document.createElement('div');\n    document.body.appendChild(testElement);\n    testElement.innerHTML = '<div>Hello World</div><div>2</div><div>3</div>';\n    var added = testElement.firstChild;\n    assert.equal(added.textContent , 'Hello World', 'innerHTML setter incorrect');\n    assert.equal(testElement.innerHTML , '<div>Hello World</div><div>2</div><div>3</div>', 'innerHTML getter incorrect');\n    assert.equal(testElement.children.length, 3);\n  });\n\n});\n\nsuite('activeElement', function() {\n  var r;\n    // light\n      var r_l;\n    // shadow\n      var r_0;\n        // light\n          var r_0_l;\n        // shadow\n          var r_0_0;\n            // light\n              var r_0_0_l;\n                // shadow\n                  var r_0_0_l_0;\n          var r_0_1;\n            // light\n              var r_0_1_l;\n      var r_1;\n        // light\n          var r_1_l;\n            // shadow\n              var r_1_l_0;\n        // shadow\n          var r_1_0;\n            // light\n              var r_1_0_l;\n          var r_1_1;\n            // light\n              var r_1_1_l;\n\n  suiteSetup(function() {\n    r = document.querySelector('x-shadow-host-root');\n      r_l = r.querySelector('x-shadow-host-root-light');\n      r_0 = r.root.querySelector('x-shadow-host-root-0');\n        r_0_l = r_0.querySelector('x-shadow-host-root-0-light');\n        r_0_0 = r_0.root.querySelector('x-shadow-host-root-0-0');\n          r_0_0_l = r_0_0.querySelector('x-shadow-host-root-0-0-light');\n            r_0_0_l_0 = r_0_0_l.root.querySelector('x-shadow-host-root-0-0-light-0');\n        r_0_1 = r_0.root.querySelector('x-shadow-host-root-0-1');\n          r_0_1_l = r_0_1.querySelector('x-shadow-host-root-0-1-light');\n      r_1 = r.root.querySelector('x-shadow-host-root-1');\n        r_1_l = r_1.querySelector('x-shadow-host-root-1-light');\n          r_1_l_0 = r_1_l.root.querySelector('x-shadow-host-root-1-light-0');\n        r_1_0 = r_1.root.querySelector('x-shadow-host-root-1-0');\n          r_1_0_l = r_1_0.querySelector('x-shadow-host-root-1-0-light');\n        r_1_1 = r_1.root.querySelector('x-shadow-host-root-1-1');\n          r_1_1_l = r_1_1.querySelector('x-shadow-host-root-1-1-light');\n  });\n\n  test('r.focus()', function() {\n    r.focus();\n\n    assert.equal(document._activeElement, r, 'document.activeElement === r');\n    assert.equal(r.root.activeElement, null, 'r.root.activeElement === null');\n    assert.equal(r_0.root.activeElement, null, 'r_0.root.activeElement === null');\n    assert.equal(r_0_0.root.activeElement, null, 'r_0_0.root.activeElement === null');\n    assert.equal(r_0_1.root.activeElement, null, 'r_0_1.root.activeElement === null');\n    assert.equal(r_1.root.activeElement, null, 'r_1.root.activeElement === null');\n    assert.equal(r_1_0.root.activeElement, null, 'r_1_0.root.activeElement === null');\n    assert.equal(r_1_1.root.activeElement, null, 'r_1_1.root.activeElement === null');\n  });\n\n  test('r_l.focus()', function() {\n    r_l.focus();\n\n    assert.equal(document._activeElement, r_l, 'document.activeElement === r_l');\n    assert.equal(r.root.activeElement, null, 'r.root.activeElement === null');\n    assert.equal(r_0.root.activeElement, null, 'r_0.root.activeElement === null');\n    assert.equal(r_0_0.root.activeElement, null, 'r_0_0.root.activeElement === null');\n    assert.equal(r_0_1.root.activeElement, null, 'r_0_1.root.activeElement === null');\n    assert.equal(r_1.root.activeElement, null, 'r_1.root.activeElement === null');\n    assert.equal(r_1_0.root.activeElement, null, 'r_1_0.root.activeElement === null');\n    assert.equal(r_1_1.root.activeElement, null, 'r_1_1.root.activeElement === null');\n  });\n\n  test('r_0.focus()', function() {\n    r_0.focus();\n\n    assert.equal(document._activeElement, r, 'document.activeElement === r');\n    assert.equal(r.root.activeElement, r_0, 'r.root.activeElement === r_0');\n    assert.equal(r_0.root.activeElement, null, 'r_0.root.activeElement === null');\n    assert.equal(r_0_0.root.activeElement, null, 'r_0_0.root.activeElement === null');\n    assert.equal(r_0_1.root.activeElement, null, 'r_0_1.root.activeElement === null');\n    assert.equal(r_1.root.activeElement, null, 'r_1.root.activeElement === null');\n    assert.equal(r_1_0.root.activeElement, null, 'r_1_0.root.activeElement === null');\n    assert.equal(r_1_1.root.activeElement, null, 'r_1_1.root.activeElement === null');\n  });\n\n  test('r_0_l.focus()', function() {\n    r_0_l.focus();\n\n    assert.equal(document._activeElement, r, 'document.activeElement === r');\n    assert.equal(r.root.activeElement, r_0_l, 'r.root.activeElement === r_0_l');\n    assert.equal(r_0.root.activeElement, null, 'r_0.root.activeElement === null');\n    assert.equal(r_1.root.activeElement, null, 'r_1.root.activeElement === null');\n\n    assert.equal(r_0_0.root.activeElement, null, 'r_0_0.root.activeElement === null');\n    assert.equal(r_0_1.root.activeElement, null, 'r_0_1.root.activeElement === null');\n    assert.equal(r_1_0.root.activeElement, null, 'r_1_0.root.activeElement === null');\n    assert.equal(r_1_1.root.activeElement, null, 'r_1_1.root.activeElement === null');\n  });\n\n  test('r_0_0.focus()', function() {\n    r_0_0.focus();\n\n    assert.equal(document._activeElement, r, 'document.activeElement === r');\n    assert.equal(r.root.activeElement, r_0, 'r.root.activeElement === r_0');\n    assert.equal(r_0.root.activeElement, r_0_0, 'r_0.root.activeElement === r_0_0');\n    assert.equal(r_0_0.root.activeElement, null, 'r_0_0.root.activeElement === null');\n    assert.equal(r_0_1.root.activeElement, null, 'r_0_1.root.activeElement === null');\n    assert.equal(r_1.root.activeElement, null, 'r_1.root.activeElement === null');\n    assert.equal(r_1_0.root.activeElement, null, 'r_1_0.root.activeElement === null');\n    assert.equal(r_1_1.root.activeElement, null, 'r_1_1.root.activeElement === null');\n  });\n\n  test('r_0_0_l.focus()', function() {\n    r_0_0_l.focus();\n\n    assert.equal(document._activeElement, r, 'document.activeElement === r');\n    assert.equal(r.root.activeElement, r_0, 'r.root.activeElement === r_0');\n    assert.equal(r_0.root.activeElement, r_0_0_l, 'r_0.root.activeElement === r_0_0_l');\n    assert.equal(r_0_0.root.activeElement, null, 'r_0_0.root.activeElement === null');\n    assert.equal(r_0_1.root.activeElement, null, 'r_0_1.root.activeElement === null');\n    assert.equal(r_1.root.activeElement, null, 'r_1.root.activeElement === null');\n    assert.equal(r_1_0.root.activeElement, null, 'r_1_0.root.activeElement === null');\n    assert.equal(r_1_1.root.activeElement, null, 'r_1_1.root.activeElement === null');\n  });\n\n  test('r_0_0_l_0.focus()', function() {\n    r_0_0_l_0.focus();\n\n    assert.equal(document._activeElement, r, 'document.activeElement === r');\n    assert.equal(r.root.activeElement, r_0, 'r.root.activeElement === r_0');\n    assert.equal(r_0.root.activeElement, r_0_0_l, 'r_0.root.activeElement === r_0_0_l');\n    assert.equal(r_0_0.root.activeElement, null, 'r_0_0.root.activeElement === null');\n    assert.equal(r_0_0_l.root.activeElement, r_0_0_l_0, 'r_0_0_l.root.activeElement === r_0_0_l_0');\n    assert.equal(r_0_1.root.activeElement, null, 'r_0_1.root.activeElement === null');\n    assert.equal(r_1.root.activeElement, null, 'r_1.root.activeElement === null');\n    assert.equal(r_1_0.root.activeElement, null, 'r_1_0.root.activeElement === null');\n    assert.equal(r_1_1.root.activeElement, null, 'r_1_1.root.activeElement === null');\n  });\n\n  test('r_0_1.focus()', function() {\n    r_0_1.focus();\n\n    assert.equal(document._activeElement, r, 'document.activeElement === r');\n    assert.equal(r.root.activeElement, r_0, 'r.root.activeElement === r_0');\n    assert.equal(r_0.root.activeElement, r_0_1, 'r_0.root.activeElement === r_0_1');\n    assert.equal(r_0_0.root.activeElement, null, 'r_0_0.root.activeElement === null');\n    assert.equal(r_0_1.root.activeElement, null, 'r_0_1.root.activeElement === null');\n    assert.equal(r_1.root.activeElement, null, 'r_1.root.activeElement === null');\n    assert.equal(r_1_0.root.activeElement, null, 'r_1_0.root.activeElement === null');\n    assert.equal(r_1_1.root.activeElement, null, 'r_1_1.root.activeElement === null');\n  });\n\n  test('r_0_1_l.focus()', function() {\n    r_0_1_l.focus();\n\n    assert.equal(document._activeElement, r, 'document.activeElement === r');\n    assert.equal(r.root.activeElement, r_0, 'r.root.activeElement === r_0');\n    assert.equal(r_0.root.activeElement, r_0_1_l, 'r_0.root.activeElement === r_0_1_l');\n    assert.equal(r_0_0.root.activeElement, null, 'r_0_0.root.activeElement === null');\n    assert.equal(r_0_1.root.activeElement, null, 'r_0_1.root.activeElement === null');\n    assert.equal(r_1.root.activeElement, null, 'r_1.root.activeElement === null');\n    assert.equal(r_1_0.root.activeElement, null, 'r_1_0.root.activeElement === null');\n    assert.equal(r_1_1.root.activeElement, null, 'r_1_1.root.activeElement === null');\n  });\n\n  test('r_1.focus()', function() {\n    r_1.focus();\n\n    assert.equal(document._activeElement, r, 'document.activeElement === r');\n    assert.equal(r.root.activeElement, r_1, 'r.root.activeElement === r_1');\n    assert.equal(r_0.root.activeElement, null, 'r_0.root.activeElement === null');\n    assert.equal(r_0_0.root.activeElement, null, 'r_0_0.root.activeElement === null');\n    assert.equal(r_0_1.root.activeElement, null, 'r_0_1.root.activeElement === null');\n    assert.equal(r_1.root.activeElement, null, 'r_1.root.activeElement === null');\n    assert.equal(r_1_0.root.activeElement, null, 'r_1_0.root.activeElement === null');\n    assert.equal(r_1_1.root.activeElement, null, 'r_1_1.root.activeElement === null');\n  });\n\n  test('r_1_l.focus()', function() {\n    r_1_l.focus();\n\n    assert.equal(document._activeElement, r, 'document.activeElement === r');\n    assert.equal(r.root.activeElement, r_1_l, 'r.root.activeElement === r_1_l');\n    assert.equal(r_0.root.activeElement, null, 'r_0.root.activeElement === null');\n    assert.equal(r_0_0.root.activeElement, null, 'r_0_0.root.activeElement === null');\n    assert.equal(r_0_1.root.activeElement, null, 'r_0_1.root.activeElement === null');\n    assert.equal(r_1.root.activeElement, null, 'r_1.root.activeElement === null');\n    assert.equal(r_1_0.root.activeElement, null, 'r_1_0.root.activeElement === null');\n    assert.equal(r_1_1.root.activeElement, null, 'r_1_1.root.activeElement === null');\n  });\n\n  test('r_1_l_0.focus()', function() {\n    r_1_l_0.focus();\n\n    assert.equal(document._activeElement, r, 'document.activeElement === r');\n    assert.equal(r.root.activeElement, r_1_l, 'r.root.activeElement === r_1_l');\n    assert.equal(r_0.root.activeElement, null, 'r_0.root.activeElement === null');\n    assert.equal(r_0_0.root.activeElement, null, 'r_0_0.root.activeElement === null');\n    assert.equal(r_0_1.root.activeElement, null, 'r_0_1.root.activeElement === null');\n    assert.equal(r_1.root.activeElement, null, 'r_1.root.activeElement === null');\n    assert.equal(r_1_l.root.activeElement, r_1_l_0, 'r_1.root.activeElement === r_1_l_0');\n    assert.equal(r_1_0.root.activeElement, null, 'r_1_0.root.activeElement === null');\n    assert.equal(r_1_1.root.activeElement, null, 'r_1_1.root.activeElement === null');\n  });\n\n  test('r_1_0.focus()', function() {\n    r_1_0.focus();\n\n    assert.equal(document._activeElement, r, 'document.activeElement === r');\n    assert.equal(r.root.activeElement, r_1, 'r.root.activeElement === r_1');\n    assert.equal(r_0.root.activeElement, null, 'r_0.root.activeElement === null');\n    assert.equal(r_0_0.root.activeElement, null, 'r_0_0.root.activeElement === null');\n    assert.equal(r_0_1.root.activeElement, null, 'r_0_1.root.activeElement === null');\n    assert.equal(r_1.root.activeElement, r_1_0, 'r_1.root.activeElement === r_1_0');\n    assert.equal(r_1_0.root.activeElement, null, 'r_1_0.root.activeElement === null');\n    assert.equal(r_1_1.root.activeElement, null, 'r_1_1.root.activeElement === null');\n  });\n\n  test('r_1_0_l.focus()', function() {\n    r_1_0_l.focus();\n\n    assert.equal(document._activeElement, r, 'document.activeElement === r');\n    assert.equal(r.root.activeElement, r_1, 'r.root.activeElement === r_1');\n    assert.equal(r_0.root.activeElement, null, 'r_0.root.activeElement === null');\n    assert.equal(r_0_0.root.activeElement, null, 'r_0_0.root.activeElement === null');\n    assert.equal(r_0_1.root.activeElement, null, 'r_0_1.root.activeElement === null');\n    assert.equal(r_1.root.activeElement, r_1_0_l, 'r_1.root.activeElement === r_1_0_l');\n    assert.equal(r_1_0.root.activeElement, null, 'r_1_0.root.activeElement === null');\n    assert.equal(r_1_1.root.activeElement, null, 'r_1_1.root.activeElement === null');\n  });\n\n  test('r_1_1.focus()', function() {\n    r_1_1.focus();\n\n    assert.equal(document._activeElement, r, 'document.activeElement === r');\n    assert.equal(r.root.activeElement, r_1, 'r.root.activeElement === r_1');\n    assert.equal(r_0.root.activeElement, null, 'r_0.root.activeElement === null');\n    assert.equal(r_0_0.root.activeElement, null, 'r_0_0.root.activeElement === null');\n    assert.equal(r_0_1.root.activeElement, null, 'r_0_1.root.activeElement === null');\n    assert.equal(r_1.root.activeElement, r_1_1, 'r_1.root.activeElement === r_1_1');\n    assert.equal(r_1_0.root.activeElement, null, 'r_1_0.root.activeElement === null');\n    assert.equal(r_1_1.root.activeElement, null, 'r_1_1.root.activeElement === null');\n  });\n\n  test('r_1_1_l.focus()', function() {\n    r_1_1_l.focus();\n\n    assert.equal(document._activeElement, r, 'document.activeElement === r');\n    assert.equal(r.root.activeElement, r_1, 'r.root.activeElement === r_1');\n    assert.equal(r_0.root.activeElement, null, 'r_0.root.activeElement === null');\n    assert.equal(r_0_0.root.activeElement, null, 'r_0_0.root.activeElement === null');\n    assert.equal(r_0_1.root.activeElement, null, 'r_0_1.root.activeElement === null');\n    assert.equal(r_1.root.activeElement, r_1_1_l, 'r_1.root.activeElement === r_1_1_l');\n    assert.equal(r_1_0.root.activeElement, null, 'r_1_0.root.activeElement === null');\n    assert.equal(r_1_1.root.activeElement, null, 'r_1_1.root.activeElement === null');\n  });\n\n  test('setting activeElement on document has no effect', function() {\n    r_1_1.focus();\n\n    // throws on some browsers only\n    try {\n      document.activeElement = \"abc\";\n    } catch(e) {\n      // no need to do anything\n    }\n    assert.equal(document._activeElement, r, 'document.activeElement === r');\n    assert.equal(r.root.activeElement, r_1, 'r.root.activeElement === r_1');\n    assert.equal(r_0.root.activeElement, null, 'r_0.root.activeElement === null');\n    assert.equal(r_0_0.root.activeElement, null, 'r_0_0.root.activeElement === null');\n    assert.equal(r_0_1.root.activeElement, null, 'r_0_1.root.activeElement === null');\n    assert.equal(r_1.root.activeElement, r_1_1, 'r_1.root.activeElement === r_1_1');\n    assert.equal(r_1_0.root.activeElement, null, 'r_1_0.root.activeElement === null');\n    assert.equal(r_1_1.root.activeElement, null, 'r_1_1.root.activeElement === null');\n  });\n\n  test('setting activeElement on a shadow root has no effect', function() {\n    r_1_1.focus();\n\n    // throws on some browsers only\n    try {\n      r_1.root.activeElement = \"abc\";\n    } catch(e) {\n      // no need to do anything\n    }\n    assert.equal(document._activeElement, r, 'document.activeElement === r');\n    assert.equal(r.root.activeElement, r_1, 'r.root.activeElement === r_1');\n    assert.equal(r_0.root.activeElement, null, 'r_0.root.activeElement === null');\n    assert.equal(r_0_0.root.activeElement, null, 'r_0_0.root.activeElement === null');\n    assert.equal(r_0_1.root.activeElement, null, 'r_0_1.root.activeElement === null');\n    assert.equal(r_1.root.activeElement, r_1_1, 'r_1.root.activeElement === r_1_1');\n    assert.equal(r_1_0.root.activeElement, null, 'r_1_0.root.activeElement === null');\n    assert.equal(r_1_1.root.activeElement, null, 'r_1_1.root.activeElement === null');\n  });\n});\n\nsuite('non-distributed elements', function() {\n\n  var nd;\n\n  suiteSetup(function() {\n    nd = document.querySelector('#noDistribute');\n  });\n\n  test('finds undistributed child', function() {\n    assert.ok(nd.children.length, 2, 'light children includes distributed and non-distributed nodes');\n  });\n\n  test('removes/adds undistributed child', function() {\n    var b = nd.children[0];\n    assert.equal(allInsertionPoints(b).length, 0, 'element improperly distributed');\n    nd.removeChild(b);\n    flush();\n    assert.equal(nd.children.length, 1, 'children length not decremented due to element removal');\n    nd.appendChild(b);\n    flush();\n    assert.equal(nd.children.length, 2, 'children length not incremented due to element addition');\n    var d = document.createElement('div');\n    d.innerHTML = 'added';\n    nd.insertBefore(d, b);\n    flush();\n    assert.equal(nd.children.length, 3, 'children length not incremented due to element addition');\n    nd.removeChild(d);\n    flush();\n    assert.equal(nd.children.length, 2, 'children length not decremented due to element removal');\n  });\n\n  test('removes/adds between light and local dom', function() {\n    var b = nd.children[1];\n    assert.equal(allInsertionPoints(b).length, 0, 'element improperly distributed');\n    nd.root.appendChild(b);\n    flush();\n    assert.equal(nd.children.length, 1, 'children length not decremented due to element removal');\n    assert.equal(nd.root.children.length, 2, 'root children length not incremented due to element addition');\n    nd.appendChild(b);\n    flush();\n    assert.equal(nd.children.length, 2, 'children length not incremented due to element addition');\n    assert.equal(nd.root.children.length, 1, 'root children length not decremented due to element removal');\n  });\n\n  test('modifying slots correctly distributes changes to light dom', function() {\n    function testNoAttr() {\n      assert.equal(allInsertionPoints(child)[0], d.$.notTestContent, 'child not distributed logically');\n      if (checkUnpatchedDom) {\n        assert.equal(Polymer.TreeApi.Composed.getParentNode(child), d.$.notTestContainer, 'child not rendered in composed dom');\n      }\n    }\n    function testWithAttr() {\n      assert.equal(allInsertionPoints(child)[0], d.$.testContent, 'child not distributed logically');\n      if (checkUnpatchedDom) {\n        assert.equal(Polymer.TreeApi.Composed.getParentNode(child), d.$.testContainer, 'child not rendered in composed dom');\n      }\n    }\n    // test with x-distribute\n    var d = document.createElement('x-distribute');\n    document.body.appendChild(d);\n    var child = document.createElement('div');\n    child.classList.add('child');\n    child.textContent = 'Child';\n    d.appendChild(child);\n    flush();\n    assert.equal(d.children[0], child, 'child not added to logical dom');\n    testNoAttr();\n    // set / unset `test` attr and see if it distributes properly\n    child.setAttribute('slot', 'test');\n    flush();\n    testWithAttr();\n    //\n    child.removeAttribute('slot');\n    flush();\n    testNoAttr();\n    //\n    child.setAttribute('slot', 'test');\n    flush();\n    testWithAttr();\n  });\n\n  test('getRootNode', function() {\n    var test = document.createElement('div');\n    var c1 = createEnabledElement('x-compose');\n    var c2 = createEnabledElement('x-compose');\n    c1.$.project.appendChild(test);\n    flush();\n    assert.equal(test.getRootNode(), c1.root, 'getOwnerRoot incorrect for child added to element in root');\n    c2.$.project.appendChild(test);\n    flush();\n    assert.equal(test.getRootNode(), c2.root, 'getOwnerRoot not correctly reset when element moved to different root');\n    c1.appendChild(test);\n    assert.equal(test.getRootNode(), c1, 'getOwnerRoot incorrect for child moved from a root to no root');\n  });\n\n  test('getRootNode when out of tree', function() {\n    var test = document.createElement('div');\n    assert.equal(test.getRootNode(), test, 'getOwnerRoot incorrect when not in root');\n    var c1 = createEnabledElement('x-compose');\n    var project = c1.$.project;\n    project.appendChild(test);\n    flush();\n    assert.equal(test.getRootNode(), c1.root, 'getOwnerRoot incorrect for child added to element in root');\n    project.removeChild(test);\n    flush();\n    assert.equal(test.getRootNode(), test, 'getOwnerRoot incorrect for child moved from a root to no root');\n    project.appendChild(test);\n    flush();\n    assert.equal(test.getRootNode(), c1.root, 'getOwnerRoot incorrect for child added to element in root');\n  });\n\n  test('getRootNode when out of tree and adding subtree', function() {\n    var container = document.createDocumentFragment();\n    var test = document.createElement('div');\n    container.appendChild(test);\n    assert.equal(test.getRootNode(), container, 'getOwnerRoot incorrect when not in root');\n    var c1 = createEnabledElement('x-compose');\n    var project = c1.$.project;\n    project.appendChild(container);\n    flush();\n    assert.equal(test.getRootNode(), c1.root, 'getOwnerRoot incorrect for child added to element in root');\n    project.removeChild(test);\n    flush();\n    assert.equal(test.getRootNode(), test, 'getOwnerRoot incorrect for child moved from a root to no root');\n    project.appendChild(test);\n    flush();\n    assert.equal(test.getRootNode(), c1.root, 'getOwnerRoot incorrect for child added to element in root');\n  });\n\n  test('getRootNode, subtree', function() {\n    var test = document.createElement('div');\n    var testChild = document.createElement('div');\n    test.appendChild(testChild);\n    assert.equal(test.getRootNode(), test, 'getOwnerRoot incorrect when not in root');\n    var c1 = createEnabledElement('x-compose');\n    var project = c1.$.project;\n    project.appendChild(test);\n    flush();\n    assert.equal(test.getRootNode(), c1.root, 'getOwnerRoot incorrect for child added to element in root');\n    assert.equal(testChild.getRootNode(), c1.root, 'getOwnerRoot incorrect for sub-child added to element in root');\n    project.removeChild(test);\n    flush();\n    assert.equal(test.getRootNode(), test, 'getOwnerRoot incorrect for child moved from a root to no root');\n    assert.equal(testChild.getRootNode(), test, 'getOwnerRoot incorrect for sub-child moved from a root to no root');\n    project.appendChild(test);\n    flush();\n    assert.equal(test.getRootNode(), c1.root, 'getOwnerRoot incorrect for child added to element in root');\n    assert.equal(testChild.getRootNode(), c1.root, 'getOwnerRoot incorrect for sub-child added to element in root');\n  });\n\n  test('getRootNode (paper-ripple use case)', function() {\n    var test = document.createElement('div');\n    // child\n    var d = document.createElement('div');\n    test.appendChild(d);\n    var c1 = createEnabledElement('x-compose');\n    var c2 = createEnabledElement('x-compose');\n    c1.$.project.appendChild(test);\n    flush();\n    assert.equal(test.getRootNode(), c1.root, 'getOwnerRoot incorrect for child added to element in root');\n    c2.$.project.appendChild(test);\n    flush();\n    assert.equal(test.getRootNode(), c2.root, 'getOwnerRoot not correctly reset when element moved to different root');\n    c1.appendChild(test);\n    assert.equal(test.getRootNode(), c1, 'getOwnerRoot incorrect for child moved from a root to no root');\n  });\n\n  test('getDestinationInsertionPoints on non-distributable element', function() {\n    var d = document.createElement('div');\n    assert.equal(allInsertionPoints(d).length, 0);\n    assert.equal(allInsertionPoints(document).length, 0);\n  });\n\n  test('(Polymer.dom) Deep Contains', function() {\n    var el = document.querySelector('x-deep-contains');\n    var shadow = el.$.shadowed;\n    var light = el.querySelector('[slot=light]');\n    var notdistributed = el.children[1];\n    var disconnected = document.createElement('div');\n    var separate = document.createElement('div');\n    document.body.appendChild(separate);\n\n    var pd = dom(el);\n\n    assert.equal(pd.deepContains(el), true, 'Element should deepContain itself');\n    assert.equal(pd.deepContains(shadow), true, 'Shadowed Child element should be found');\n    assert.equal(pd.deepContains(light), true, 'Light Child element should be found');\n    assert.equal(pd.deepContains(notdistributed), true, 'Non-distributed child element should be found');\n    assert.equal(pd.deepContains(disconnected), false, 'Disconnected element should not be found');\n    assert.equal(pd.deepContains(separate), false, 'Unassociated, attached element should not be found');\n\n    document.body.removeChild(separate);\n  });\n\n});\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/shady-events.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n<script>\n  if (window.customElements) {\n    customElements.forcePolyfill = true;\n  }\n  window.ShadyDOM = {\n    force: true\n  };\n</script>\n<script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n<script src=\"wct-browser-config.js\"></script>\n<script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n<script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n</head>\n<body>\n\n  <dom-module id=\"x-event-scoped\">\n    <template>\n      <div id=\"scoped\" on-composed=\"childHandler\" on-scoped=\"childHandler\"></div>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-event-scoped',\n  properties: {\n    hostEvents: {\n      type: Array,\n      value: function() {\n        return [];\n      }\n    },\n    childEvents: {\n      type: Array,\n      value: function() {\n        return [];\n      }\n    }\n  },\n  listeners: {\n    'composed': 'hostHandler',\n    'scoped': 'hostHandler'\n  },\n  hostHandler: function(e) {\n    this.hostEvents.push({\n      target: e.target,\n      type: e.type,\n      path: e.composedPath()\n    });\n  },\n  childHandler: function(e) {\n    this.childEvents.push({\n      target: e.target,\n      type: e.type,\n      path: e.composedPath()\n    });\n  },\n  fireComposed: function() {\n    return this.fire('composed', null, {node: this.$.scoped});\n  },\n  fireScoped: function(){\n    return this.fire('scoped', null, {node: this.$.scoped, composed: false});\n  }\n});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-focus\">\n    <template>\n      <style>\n        :host {\n          display: block;\n        }\n      </style>\n      <div id=\"child\" on-focus=\"focusHandler\"></div>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-focus',\n  properties: {\n    events: {\n      type: Array,\n      value: function() {\n        return [];\n      }\n    }\n  },\n  listeners: {\n    focus: 'focusHandler'\n  },\n  focusHandler: function(e) {\n    this.events.push(e.target);\n  },\n  fireComposed: function() {\n    var ev = new Event('focus', {composed: true});\n    this.$.child.dispatchEvent(ev);\n  },\n  fireScoped: function() {\n    var ev = new Event('focus');\n    this.$.child.dispatchEvent(ev);\n  }\n});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-a\">\n    <template>\n      <div id=\"child\" on-foo=\"childFooHandler\"></div>\n      <div id=\"child2\"></div>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-a',\n  listeners: {\n    'foo': 'fooHandler'\n  },\n  fooHandler: function(e) {\n    this.event = {target: e.target, relatedTarget: e.relatedTarget};\n  },\n  childFooHandler: function(e) {\n    this.childEvent = {target: e.target, relatedTarget: e.relatedTarget};\n  }\n});\n</script>\n  </dom-module>\n\n  <test-fixture id=\"scoped\">\n    <template>\n      <x-event-scoped></x-event-scoped>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"globalpatch\">\n    <template>\n      <div></div>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"focus\">\n    <template>\n      <x-focus></x-focus>\n    </template>\n  </test-fixture>\n\n  <test-fixture id=\"relatedtarget\">\n    <template>\n      <x-a id=\"one\"></x-a>\n      <x-a id=\"two\"></x-a>\n    </template>\n  </test-fixture>\n\n  <dom-module id=\"x-slot-inner\">\n  </dom-module>\n\n  <test-fixture id=\"slot\">\n    <template>\n      <x-slot>\n        <span class=\"target\"></span>\n      </x-slot>\n    </template>\n  </test-fixture>\n\n<script type=\"module\">\nsuite('ShadyDOM event patching', function() {\n\n  test('events retarget', function() {\n    var el = fixture('scoped');\n    el.fireComposed();\n    assert.equal(el.hostEvents[0].target, el);\n    assert.equal(el.childEvents[0].target, el.$.scoped);\n  });\n\n  test('event.composedPath is consistent', function() {\n    var el = fixture('scoped');\n    el.fireComposed();\n    assert.equal(el.hostEvents.length, el.childEvents.length);\n  });\n\n  test('event patching works on non Polymer elements', function() {\n    var el = fixture('globalpatch');\n    var path;\n    el.addEventListener('foo', function(e) {\n      path = e.composedPath();\n    });\n    var e = new Event('foo', {composed: true});\n    el.dispatchEvent(e);\n    assert.deepEqual([el, el.parentNode, document.body, document.documentElement, document, window], path);\n  });\n\n  test('`composed` flag controls event propagation through roots', function() {\n    var el = fixture('scoped');\n    el.fireScoped();\n    el.fireComposed();\n    assert.equal(el.hostEvents.length, 1);\n    assert.equal(el.hostEvents[0].type, 'composed');\n    assert.equal(el.childEvents.length, 2);\n    assert.equal(el.childEvents[0].type, 'scoped');\n    assert.equal(el.childEvents[1].type, 'composed');\n  });\n\n  test('composed focus and blur events retarget up tree', function() {\n    var el = fixture('focus');\n    el.fireComposed();\n    assert.equal(el.events.length, 2);\n    assert.equal(el.events[0], el.$.child);\n    assert.equal(el.events[1], el);\n  });\n\n  test('scoped focus and blur events do not retarget', function() {\n    var el = fixture('focus');\n    var e = new Event('focus');\n    if (e.isTrused !== false) {\n      // skip browser if we cannot distinguish\n      // native focus events from user created ones\n      this.skip();\n    }\n    el.fireScoped();\n    assert.equal(el.events.length, 1);\n    assert.equal(el.events[0], el.$.child);\n  });\n\n  test('composed relatedTarget retargets', function() {\n    var els = fixture('relatedtarget');\n    var a = els[0];\n    var b = els[1];\n    var ev = new MouseEvent('foo', {bubbles: true, composed: true, relatedTarget: b.$.child});\n    a.$.child.dispatchEvent(ev);\n    assert.property(a, 'childEvent');\n    assert.deepEqual(a.childEvent, {target: a.$.child, relatedTarget: b});\n    assert.property(a, 'event');\n    assert.deepEqual(a.event, {target: a, relatedTarget: b});\n  });\n\n  test('events do not fire if relatedtarget and target are the same node after retargeting', function() {\n    var els = fixture('relatedtarget');\n    var a = els[0];\n    var ev = new MouseEvent('foo', {bubbles: true, composed: true, relatedTarget: a.$.child2});\n    a.$.child.dispatchEvent(ev);\n    assert.property(a, 'childEvent');\n    assert.deepEqual(a.childEvent, {target: a.$.child, relatedTarget: a.$.child2});\n    assert.notProperty(a, 'event');\n  });\n\n  test('capturing event listeners fire correctly for focus and blur', function() {\n    var el = fixture('focus');\n    var timeStamp;\n    el.addEventListener('focus', function(e) {\n      timeStamp = e.timeStamp;\n    }, true);\n    el.fireComposed();\n    assert.ok(timeStamp);\n    assert.equal(el.events.length, 2);\n    assert.equal(el.events[0], el.$.child);\n    assert.equal(el.events[1], el);\n  });\n\n});\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/shady-unscoped-style-import.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\nconst $_documentContainer = document.createElement('template');\n$_documentContainer.setAttribute('style', 'display: none;');\n\n$_documentContainer.innerHTML = `<dom-module id=\"global-shared1\">\n  <template>\n    <style shady-unscoped=\"\">\n      :root {\n        --zug: margin: 10px;\n      }\n\n      .happy {\n        @apply --zug;\n        border: 1px solid green;\n      }\n    </style>\n\n    <style>\n      .normal {\n        border: 3px solid orange;\n      }\n    </style>\n  </template>\n</dom-module><dom-module id=\"global-shared2\">\n</dom-module>`;\n\ndocument.head.appendChild($_documentContainer.content);\n"
  },
  {
    "path": "test/unit/shady-unscoped-style.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n  <script type=\"module\" src=\"./shady-unscoped-style-import.js\"></script>\n</head>\n<body>\n\n<custom-style>\n  <style is=\"custom-style\">\n    html {\n      --foo: {\n        padding: 10px;\n      }\n    }\n  </style>\n</custom-style>\n\n <dom-module id=\"my-element\">\n\n    <template>\n      <style include=\"global-shared1 global-shared2\">\n        :host {\n          display: block;\n        }\n\n        .happy {\n          @apply --foo;\n        }\n      </style>\n      <div id=\"fromStyle\" class=\"happy\">Happy: green</div>\n      <div id=\"fromImport\" class=\"import\">Happy: yellow</div>\n      <div id=\"normal\" class=\"normal\">Happy: orange</div>\n    </template>\n\n    <script type=\"module\">\nimport './shady-unscoped-style-import.js';\nimport { Polymer } from '../../lib/legacy/polymer-fn.js';\nPolymer({\n  is: 'my-element'\n});\n</script>\n\n  </dom-module>\n\n  <dom-module id=\"my-element2\">\n\n    <template>\n      <style include=\"global-shared1\">\n        :host {\n          display: block;\n        }\n\n      </style>\n      <div id=\"fromStyle\" class=\"happy\">Happy: green</div>\n      <div id=\"fromImport\" class=\"import\">Happy: yellow</div>\n      <div id=\"normal\" class=\"normal\">Happy: orange</div>\n    </template>\n\n    <script type=\"module\">\nimport './shady-unscoped-style-import.js';\nimport { Polymer } from '../../lib/legacy/polymer-fn.js';\nPolymer({ is: 'my-element2'});\n</script>\n\n  </dom-module>\n\n  <my-element></my-element>\n  <my-element2></my-element2>\n\n<script type=\"module\">\nimport './shady-unscoped-style-import.js';\nsuite('shady-unscoped styles', function() {\n\n  function assertComputed(element, value, property, pseudo) {\n    var computed = getComputedStyle(element, pseudo);\n    property = property || 'border-top-width';\n    if (Array.isArray(value)) {\n      assert.oneOf(computed[property], value, 'computed style incorrect for ' + property);\n    } else {\n      assert.equal(computed[property], value, 'computed style incorrect for ' + property);\n    }\n  }\n\n  var el1 = document.querySelector('my-element');\n  var el2 = document.querySelector('my-element2');\n\n  test('unscoped styles apply', function() {\n    assertComputed(el1.$.fromStyle, '1px');\n    assertComputed(el2.$.fromStyle, '1px');\n  });\n\n  test('shared and @apply apply when used with unscoped styles', function() {\n    assertComputed(el1.$.fromStyle, '10px', 'padding-top');\n    assertComputed(el1.$.normal, '3px');\n    assertComputed(el2.$.normal, '3px');\n  });\n\n  test('@apply does not apply under ShadyDOM for shady-unscoped styles', function() {\n    assertComputed(el1.$.fromStyle, '0px', 'margin-top');\n    assertComputed(el2.$.fromStyle, '0px', 'margin-top');\n  });\n});\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/shady.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\" register=\"true\" shadydom=\"true\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n</head>\n<body>\n<template></template>\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nvar template = document.querySelector('template');\nPolymer({\n  is: 'x-content-test',\n  _template: template\n});\n\n/*\n * Test the `<slot>` element distribution algorithm by verifying the\n * resulting composed tree structure.\n */\nfunction testRender(descr, hostInnerHtml, shadowRootHtml, expectedHtml) {\n  test(descr, function() {\n    // Create an instance of the test element.\n    var host = document.createElement('x-content-test');\n    // Populate the initial pool of light DOM children.\n    host.innerHTML = hostInnerHtml;\n    document.body.appendChild(host);\n    // Pretend we're stamping the template contents.\n    if (shadowRootHtml) {\n      host.shadowRoot.innerHTML = shadowRootHtml;\n    }\n    // Invoke distribution and verify the resulting tree.\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), expectedHtml);\n    document.body.removeChild(host);\n  });\n  test(descr + ' fragment', function() {\n    // Create an instance of the test element.\n    var host = document.createElement('x-content-test');\n    // Populate the initial pool of light DOM children.\n    host.innerHTML = hostInnerHtml;\n    document.body.appendChild(host);\n    // Pretend we're stamping the template contents.\n    var div = document.createElement('div');\n    div.innerHTML = shadowRootHtml;\n    var frag = document.createDocumentFragment();\n    while (div.firstChild) {\n      frag.appendChild(div.firstChild);\n    }\n    host.shadowRoot.appendChild(frag);\n    // Invoke distribution and verify the resulting tree.\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), expectedHtml);\n    document.body.removeChild(host);\n  });\n}\n\ntestRender('Empty shadow', 'abc', '', '');\ntestRender('Simple shadow', 'abc', 'def', 'def');\ntestRender('Fallback shadow', 'abc',\n           '<slot name=\"xxx\">fallback</name>', 'fallback');\ntestRender('Fallback shadow, empty host', '',\n           '<slot name=\"xxx\">fallback</name>', 'fallback');\ntestRender('Content', 'abc',\n           '<slot>fallback</slot>', 'abc');\ntestRender('Content before', 'abc',\n           'before<slot>fallback</slot>', 'beforeabc');\ntestRender('Content after', 'abc',\n           '<slot>fallback</slot>after', 'abcafter');\n\nsuite('render content', function() {\n  testRender('no select', '<a href=\"\">Link</a> <b>bold</b>',\n             '<slot></slot>',\n             '<a href=\"\">Link</a> <b>bold</b>');\n  testRender('select \"\"', '<a href=\"\">Link</a> <b>bold</b>',\n             '<slot></slot>',\n             '<a href=\"\">Link</a> <b>bold</b>');\n\n  testRender('slot a',\n             '<a slot=\"a\">a</a> <a slot=\"b\">b</a>',\n             '<slot name=\"a\"></slot>',\n             '<a slot=\"a\">a</a>');\n\n  testRender('slot b a',\n             '<a slot=\"a\">a</a> <a slot=\"b\">b</a>',\n             '<slot name=\"b\"></slot><slot name=\"a\"></slot>',\n             '<a slot=\"b\">b</a><a slot=\"a\">a</a>');\n\n  testRender('slot b a 2',\n             '<a slot=\"a\">a</a> <a slot=\"b\">b</a> <a slot=\"b\">c</a>',\n             '<slot name=\"b\"></slot><slot name=\"a\"></slot>',\n             '<a slot=\"b\">b</a><a slot=\"b\">c</a><a slot=\"a\">a</a>');\n\n  testRender('slot c catchall',\n             '<span>a</span><span>b</span><span slot=\"c\">c</span><span>d</span>',\n             '<slot name=\"c\"></slot><slot></slot>',\n             '<span slot=\"c\">c</span><span>a</span><span>b</span><span>d</span>');\n});\n\n\ntest('Reproject', function() {\n  var host = document.createElement('x-content-test');\n  document.body.appendChild(host);\n  host.innerHTML = '<a></a>';\n  // pre-distirbution grab first composed node.\n  var a = getComposedChildAtIndex(host, 0);\n\n  host.shadowRoot.innerHTML = '<x-content-test id=\"p\"></x-content-test>';\n  // force upgrade on polyfilled browsers\n  var p = host.shadowRoot.firstChild;\n  p.innerHTML = '<b slot=\"b\"></b><slot slot=\"a\"></slot>';\n  var b = p.firstChild;\n  var content = p.lastChild;\n\n  p.shadowRoot.innerHTML =\n      'a: <slot name=\"a\"></slot>b: <slot name=\"b\"></slot>';\n  var textNodeA = p.shadowRoot.firstChild;\n  var contentA = p.shadowRoot.childNodes[1];\n  var textNodeB = p.shadowRoot.childNodes[2];\n  var contentB = p.shadowRoot.childNodes[3];\n\n  function testRender() {\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host),\n        '<x-content-test id=\"p\">a: <a></a>b: <b slot=\"b\"></b></x-content-test>');\n\n    assertArrayEqual(host.childNodes, [a]);\n    assert.strictEqual(a.parentNode, host);\n    assertArrayEqual(host.shadowRoot.childNodes, [p]);\n    assert.strictEqual(p.parentNode, host.shadowRoot);\n    assertArrayEqual(p.childNodes, [b, content]);\n    assert.strictEqual(b.parentNode, p);\n    assert.strictEqual(content.parentNode, p);\n    assertArrayEqual(p.shadowRoot.childNodes,\n        [textNodeA, contentA, textNodeB, contentB]);\n  }\n\n  testRender();\n  testRender();\n  document.body.removeChild(host);\n});\n\n\nsuite('Mutate light DOM', function() {\n  var host;\n\n  setup(function() {\n    host = document.createElement('x-content-test');\n    document.body.appendChild(host);\n  });\n\n  teardown(function() {\n    document.body.removeChild(host);\n  });\n\n  test('removeAllChildNodes - mutate host', function() {\n    host.innerHTML = '<a>Hello</a>';\n\n    host.shadowRoot.innerHTML = '<slot>fallback</slot>';\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');\n\n    host.firstChild.textContent = '';\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '<a></a>');\n\n    host.innerHTML = '';\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), 'fallback');\n  });\n\n\n  test('removeAllChildNodes - mutate shadow', function() {\n    host.innerHTML = '<a>Hello</a>';\n\n    host.shadowRoot.innerHTML = '<slot></slot><b>after</b>';\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b>after</b>');\n\n    host.shadowRoot.childNodes[1].textContent = '';\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b></b>');\n\n    host.shadowRoot.innerHTML = '';\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '');\n  });\n\n  test('removeAllChildNodes - mutate shadow fallback', function() {\n    host.innerHTML = '<a>Hello</a>';\n\n    host.shadowRoot.innerHTML = '<slot name=\"xxx\"><b>fallback</b></slot>';\n    var b = host.shadowRoot.firstChild.firstChild;\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '<b>fallback</b>');\n\n    b.textContent = '';\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '<b></b>');\n\n    host.shadowRoot.firstChild.innerHTML = '';\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '');\n\n    host.shadowRoot.innerHTML = '';\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '');\n  });\n\n  test('removeChild - mutate host', function() {\n    host.innerHTML = '<a>Hello</a>';\n\n    host.shadowRoot.innerHTML = '<slot>fallback</slot>';\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');\n\n    host.firstChild.removeChild(host.firstChild.firstChild);\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '<a></a>');\n\n    host.innerHTML = '';\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), 'fallback');\n  });\n\n  test('removeChild - mutate host 2', function() {\n    host.innerHTML = '<a></a><b></b>';\n    var a = getComposedChildAtIndex(host, 0);\n    var b = getComposedChildAtIndex(host, 1);\n\n    host.shadowRoot.innerHTML = '<slot>fallback</slot>';\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '<a></a><b></b>');\n\n    host.removeChild(b);\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '<a></a>');\n\n    host.removeChild(a);\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), 'fallback');\n  });\n\n  test('removeChild - mutate shadow', function() {\n    host.innerHTML = '<a>Hello</a>';\n\n    host.shadowRoot.innerHTML = '<slot></slot><b>after</b>';\n    var b = host.shadowRoot.lastChild;\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b>after</b>');\n\n    b.removeChild(b.firstChild);\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b></b>');\n\n    host.shadowRoot.removeChild(b);\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');\n\n    host.shadowRoot.removeChild(host.shadowRoot.firstChild);\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '');\n  });\n\n  test('setAttribute slot', function() {\n    host.innerHTML = '<a slot=\"a\">Hello</a><b slot=\"b\">World</b>';\n\n\n    host.shadowRoot.innerHTML = '<slot name=\"b\">fallback b</slot>' +\n                            '<slot name=\"a\">fallback a</slot>';\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '<b slot=\"b\">World</b><a slot=\"a\">Hello</a>');\n\n    host.shadowRoot.firstChild.setAttribute('name', 'xxx');\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), 'fallback b<a slot=\"a\">Hello</a>');\n\n    host.shadowRoot.firstChild.setAttribute('name', '');\n    host.shadowRoot.lastChild.setAttribute('name', '');\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), 'fallback bfallback a');\n  });\n\n  test('appendChild - mutate host', function() {\n    host.innerHTML = '<a>Hello</a>';\n    host.shadowRoot.innerHTML = '<slot></slot>';\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');\n\n    var b = document.createElement('b');\n    host.appendChild(b);\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b></b>');\n  });\n\n  test('appendChild - mutate shadow', function() {\n    host.innerHTML = '<a>Hello</a>';\n    host.shadowRoot.innerHTML = '<slot></slot>';\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');\n\n    var b = document.createElement('b');\n    host.shadowRoot.appendChild(b);\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b></b>');\n  });\n\n  test('insertBefore - mutate host', function() {\n    host.innerHTML = '<a>Hello</a>';\n    var a = getComposedChildAtIndex(host, 0);\n    host.shadowRoot.innerHTML = '<slot></slot>';\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');\n\n    var b = document.createElement('b');\n    host.insertBefore(b, a);\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '<b></b><a>Hello</a>');\n  });\n\n  test('insertBefore - mutate shadow', function() {\n    host.innerHTML = '<a>Hello</a>';\n\n\n    host.shadowRoot.innerHTML = '<slot></slot>';\n    var content = host.shadowRoot.firstChild;\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');\n\n    var b = document.createElement('b');\n    host.shadowRoot.insertBefore(b, content);\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '<b></b><a>Hello</a>');\n  });\n\n  test('replaceChild - mutate host', function() {\n    host.innerHTML = '<a>Hello</a>';\n    host.shadowRoot.innerHTML = '<slot></slot>';\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');\n    var b = document.createElement('b');\n    host.replaceChild(b, host.firstChild);\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '<b></b>');\n  });\n\n  test('replaceChild - mutate shadow', function() {\n    host.innerHTML = '<a>Hello</a>';\n    host.shadowRoot.innerHTML = '<slot></slot>';\n    var content = host.shadowRoot.firstChild;\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');\n    var b = document.createElement('b');\n    host.shadowRoot.replaceChild(b, content);\n    ShadyDOM.flush();\n    assert.strictEqual(getComposedHTML(host), '<b></b>');\n  });\n\n  test('querySelectorAll (shadowRoot)', function() {\n    host.innerHTML = '<div id=\"main\"></div>';\n    host.shadowRoot.innerHTML = '<slot></slot><span id=\"main\"></span>' +\n      '<x-content-test></x-content-test>';\n    // force upgrade on polyfilled browsers\n    ShadyDOM.flush();\n    var hostLocalMain = getComposedChildAtIndex(host.shadowRoot, 1);\n    var child = getComposedChildAtIndex(host.shadowRoot, 100);\n    child.innerHTML = '<div id=\"sub\"></div>';\n    var childLightSub = getComposedChildAtIndex(child, 0);\n    child.shadowRoot.innerHTML = '<slot></slot><span id=\"sub\"></span>';\n    var childLocalSub = child.shadowRoot.lastChild;\n    ShadyDOM.flush();\n    assert.deepEqual(Array.from(host.root.querySelectorAll('span#main')), [hostLocalMain]);\n    assert.deepEqual(Array.from(host.root.querySelectorAll('div#sub')), [childLightSub]);\n    assert.deepEqual(Array.from(child.root.querySelectorAll('span#sub')), [childLocalSub]);\n  });\n\n  test('querySelectorAll (light dom)', function() {\n    host.innerHTML = '<div id=\"main\"></div>';\n    var hostLightMain = getComposedChildAtIndex(host, 0);\n    host.shadowRoot.innerHTML = '<slot></slot><span id=\"main\"></span>' +\n      '<x-content-test></x-content-test>';\n    var child = getComposedChildAtIndex(host.shadowRoot, 100);\n    child.innerHTML = '<div id=\"sub\"></div>';\n    var childLightSub = getComposedChildAtIndex(child, 100) ;\n    child.shadowRoot.innerHTML = '<slot></slot><span id=\"sub\"></span>';\n    ShadyDOM.flush();\n    assert.deepEqual(Array.from(host.querySelectorAll('div#main')), [hostLightMain]);\n    assert.deepEqual(Array.from(host.querySelectorAll('#sub')), []);\n    assert.deepEqual(Array.from(child.querySelectorAll('div#sub')), [childLightSub]);\n  });\n\n});\n\nsuite('Add shadowRoot to element with childNodes', function() {\n\n  var el;\n\n  setup(function() {\n    el = document.createElement('div');\n    el.testHTML = '<div slot=\"a\">hi</div>';\n    el.innerHTML = el.testHTML;\n    el.attachShadow({mode: 'open'});\n  });\n\n  test('empty root', function() {\n    ShadyDOM.flush();\n    assert.equal(getComposedHTML(el), '');\n  });\n\n  test('simple root', function() {\n    var shadow = '<div>shadow</div>';\n    el.shadowRoot.innerHTML = shadow;\n    ShadyDOM.flush();\n    assert.equal(getComposedHTML(el), shadow);\n  });\n\n  test('slot matching', function() {\n    var shadow = '<div><slot name=\"a\"></slot></div>';\n    el.shadowRoot.innerHTML = shadow;\n    ShadyDOM.flush();\n    assert.equal(getComposedHTML(el), '<div>' + el.testHTML + '</div>');\n  });\n\n  test('slot not matching', function() {\n    var shadow = '<div><slot name=\"b\"></slot></div>';\n    el.shadowRoot.innerHTML = shadow;\n    ShadyDOM.flush();\n    assert.equal(getComposedHTML(el), '<div></div>');\n  });\n\n});\n\nfunction getEffectiveChildNodes(node) {\n  var list = [];\n  var c$ = node.childNodes;\n  for (var i=0, l=c$.length, c; (i<l) && (c=c$[i]); i++) {\n    if (c.localName && (c.localName === 'content' || c.localName === 'slot')) {\n      list = list.concat(c.assignedNodes({flatten: true}));\n    } else {\n      list.push(c);\n    }\n  }\n  return list;\n}\n\nfunction getComposedHTML(node) {\n  // Ignore shady CSS scoping\n  return ShadyDOM.nativeTree.innerHTML(node).replace(/ class=\"[^\"]*\"/g, '');\n}\n\nfunction getComposedChildAtIndex(node, index) {\n  var c$ = getEffectiveChildNodes(node);\n  if (c$) {\n    index = index || 0;\n    index = Math.max(0, Math.min(index, c$.length-1));\n    return c$[index];\n  }\n}\n\nfunction assertArrayEqual(a, b, msg) {\n  assert.equal(a.length, b.length, msg);\n  for (var i = 0; i < a.length; i++) {\n    assert.equal(a[i], b[i], msg);\n  }\n}\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/strict-template-policy.html",
    "content": "<!DOCTYPE html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"UTF-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\">\n      import { setStrictTemplatePolicy } from '../../lib/utils/settings.js';\n      import { Debouncer } from '../../lib/utils/debounce.js';\n      setStrictTemplatePolicy(true);\n      // Errors thrown in Polymer's debouncer queue get re-thrown\n      // via setTimeout, making them particulary difficult to verify;\n      // Wrap debouncer callbacks and store on the globalError to test later\n      const debounce = Debouncer.debounce;\n      Debouncer.debounce = function(debouncer, asyncModule, callback) {\n        return debounce(debouncer, asyncModule, function() {\n          try { \n            callback(); \n          } catch(error) {\n            if (!window.uncaughtErrorFilter || !window.uncaughtErrorFilter(error)) {\n              throw error;\n            }\n          }\n        });\n      };\n    </script>\n</head>\n<body>\n\n  <dom-module id=\"no-dm\">\n    <template>Should never be used</template>\n    <script type=\"module\">\n      import {PolymerElement} from '../../polymer-element.js';\n      class TrustedElement extends PolymerElement {\n        static get is() { return 'no-dm'; }\n      }\n      customElements.define(TrustedElement.is, TrustedElement);\n    </script>\n  </dom-module>\n\n  <dom-module id=\"no-dm-legacy\">\n    <template>Should never be used</template>\n    <script type=\"module\">\n      import {Polymer} from '../../polymer-legacy.js';\n      Polymer({is: 'no-dm-legacy'});\n    </script>\n  </dom-module>\n\n  <dom-module id=\"trusted-element\">\n    <template>Trusted</template>\n    <script type=\"module\">\n      import {PolymerElement} from '../../polymer-element.js';\n      class TrustedElement extends PolymerElement {\n        static get is() { return 'trusted-element'; }\n      }\n      customElements.define(TrustedElement.is, TrustedElement);\n    </script>\n  </dom-module>\n    \n  <dom-module id=\"trusted-element-legacy\">\n    <template>Trusted</template>\n    <script type=\"module\">\n      import {Polymer} from '../../polymer-legacy.js';\n      Polymer({is: 'trusted-element-legacy'});\n    </script>\n  </dom-module>\n  \n  <div id=\"target\"></div>\n    \n  <script type=\"module\">\n    import {PolymerElement, html} from '../../polymer-element.js';\n    import {Polymer} from '../../polymer-legacy.js';\n    import {flush} from '../../lib/utils/flush.js';\n    import {setAllowTemplateFromDomModule} from '../../lib/utils/settings.js';\n\n    suite('strictTemplatePolicy', function() {\n\n      function restoreOnError() {\n        window.uncaughtErrorFilter = window.top.uncaughtErrorFilter = null;\n      }\n\n      teardown(function() {\n        restoreOnError();\n        document.getElementById('target').textContent = '';\n      });\n\n      // Errors thrown in custom element reactions are not thrown up\n      // the call stack to the dom methods that provoked them, so this\n      // wraps Chai's assert.throws to re-throw uncaught errors\n      function assertThrows(fn, re) {\n        // Catch uncaught errors; note when running in iframe sometimes\n        // Safari errors are thrown on the top window, sometimes not, so\n        // catch in both places\n        let uncaughtError = null;\n        window.uncaughtErrorFilter = window.top.uncaughtErrorFilter = function(err) {\n          if (!uncaughtError) {\n            uncaughtError = err;\n          }\n          return true;\n        };\n        assert.throws(function() {\n          fn();\n          // Re-throw any uncaughtErrors\n          if (uncaughtError) {\n            throw new Error(uncaughtError.message);\n          }\n          // Force polyfill reactions and/or async template stamping\n          flush();\n          // Re-throw any uncaughtErrors\n          if (uncaughtError) {\n            throw new Error(uncaughtError.message);\n          }\n        }, re);\n        restoreOnError();\n      }\n\n      test('dom-bind', function() {\n        assertThrows(function() {\n          document.getElementById('target').innerHTML =\n          '<dom-bind>' +\n          '  <template>' +\n          '    <div id=\"injected\"></div>'+\n          '  </template>`' + \n          '</dom-bind>';\n        }, /dom-bind not allowed/);\n        assert.notOk(document.getElementById('injected'));\n      });\n\n      test('dom-if', function() {\n        assertThrows(function() {\n          document.getElementById('target').innerHTML =\n            '<dom-if if>' +\n            '  <template>' +\n            '    <div id=\"injected\"></div>'+\n            '  </template>' + \n            '</dom-if>';\n        }, /template owner not trusted/);\n        assert.notOk(document.getElementById('injected'));\n      });\n\n      test('dom-repeat', function() {\n        assertThrows(function() {\n          document.getElementById('target').innerHTML =\n            '<dom-repeat items=\"[0]\">' +\n            '  <template>' +\n            '    <div id=\"injected\"></div>'+\n            '  </template>`' + \n            '</dom-repeat>';\n        }, /template owner not trusted/);\n        assert.notOk(document.getElementById('injected'));\n      });\n\n      test('dom-module never used', function() {\n        var el = document.createElement('no-dm');\n        document.getElementById('target').appendChild(el);\n        assert.notOk(el.shadowRoot);\n      });\n\n      test('dom-module never used (legacy)', function() {\n        var el = document.createElement('no-dm-legacy');\n        document.getElementById('target').appendChild(el);\n        assert.notOk(el.shadowRoot);\n      });\n\n      // From this point down, dom-module lookup is globally enabled\n      test('setAllowTemplateFromDomModule', function() {\n        setAllowTemplateFromDomModule(true);\n      });\n\n      test('dom-module after registration', function() {\n        assertThrows(function() {\n          document.getElementById('target').innerHTML =\n            '<dom-module id=\"trusted-element\">' +\n            '  <template>' +\n            '    <div id=\"injected\"></div>'+\n            '  </template>`' +\n            '</dom-module>';\n        }, /trusted-element re-registered/);\n        let el;\n        assertThrows(function() {\n          el = document.createElement('trusted-element');\n          document.getElementById('target').appendChild(el);\n        }, /expecting dom-module or null template for trusted-element/);\n        assert.notOk(el && el.shadowRoot);\n        assert.notOk(document.getElementById('injected'));\n      });\n      \n      test('dom-module after registration, again', function() {\n        assertThrows(function() {\n          document.getElementById('target').innerHTML =\n            '<dom-module id=\"trusted-element\">' +\n            '  <template>' +\n            '    <div id=\"injected\"></div>'+\n            '  </template>`' +\n            '</dom-module>';\n        }, /trusted-element re-registered/);\n        const el = document.createElement('trusted-element');\n        document.getElementById('target').appendChild(el);\n        assert.notOk(el.shadowRoot);\n        assert.notOk(document.getElementById('injected'));\n      });\n      \n      test('dom-module before registration', function() {\n        document.getElementById('target').innerHTML =\n          '<dom-module id=\"has-no-template\">' +\n          '  <template>' +\n          '    <div id=\"injected\"></div>'+\n          '  </template>`' +\n          '</dom-module>';\n        class HasNoTemplate extends PolymerElement {\n          static get is() { return 'has-no-template'; }\n          static get template() { return null; }\n        }\n        customElements.define(HasNoTemplate.is, HasNoTemplate);\n        let el = document.createElement('has-no-template');\n        document.getElementById('target').appendChild(el);\n        assert.notOk(el.shadowRoot);\n        assert.notOk(document.getElementById('injected'));\n      });\n\n      test('dom-module after registration (legacy)', function() {\n        assertThrows(function() {\n          document.getElementById('target').innerHTML =\n            '<dom-module id=\"trusted-element-legacy\">' +\n            '  <template>' +\n            '    <div id=\"injected\"></div>'+\n            '  </template>`' +\n            '</dom-module>';\n        }, /trusted-element-legacy re-registered/);\n        let el;\n        assertThrows(function() {\n          el = document.createElement('trusted-element-legacy');\n          document.getElementById('target').appendChild(el);\n        }, /expecting dom-module or null template for trusted-element-legacy/);\n        assert.notOk(el && el.shadowRoot);\n        assert.notOk(document.getElementById('injected'));\n      });\n      \n      test('dom-module after registration, again (legacy)', function() {\n        assertThrows(function() {\n          document.getElementById('target').innerHTML =\n            '<dom-module id=\"trusted-element-legacy\">' +\n            '  <template>' +\n            '    <div id=\"injected\"></div>'+\n            '  </template>`' +\n            '</dom-module>';\n        }, /trusted-element-legacy re-registered/);\n        const el = document.createElement('trusted-element-legacy');\n        document.getElementById('target').appendChild(el);\n        assert.notOk(el.shadowRoot);\n        assert.notOk(document.getElementById('injected'));\n      });\n            \n      test('dom-module before registration (legacy)', function() {\n        document.getElementById('target').innerHTML =\n          '<dom-module id=\"has-no-template-legacy\">' +\n          '  <template>' +\n          '    <div id=\"injected\"></div>'+\n          '  </template>`' +\n          '</dom-module>';\n        Polymer({\n          is: 'has-no-template-legacy',\n          _template: null\n        });\n        let el = document.createElement('has-no-template-legacy');\n        document.getElementById('target').appendChild(el);\n        assert.notOk(el.shadowRoot);\n        assert.notOk(document.getElementById('injected'));\n      });\n\n      test('element without explicit template throws', function() {\n        assertThrows(function() {\n          class HasNoTemplateThrows extends PolymerElement {\n            static get is() { return 'has-no-template-throws'; }\n          }\n          customElements.define(HasNoTemplateThrows.is, HasNoTemplateThrows); \n          var el = document.createElement('has-no-template-throws');\n          document.getElementById('target').appendChild(el);\n        }, /expecting dom-module or null template/);\n      });\n\n      test('element without explicit template throws (legacy)', function() {\n        assertThrows(function() {\n          Polymer({\n            is: 'has-no-template-throws-legacy'\n          });\n          var el = document.createElement('has-no-template-throws-legacy');\n          document.getElementById('target').appendChild(el);\n        }, /expecting dom-module or null template/);\n      });\n\n      test('template helpers in trusted templates work', function() {\n        \n        class TrustedTemplates extends PolymerElement {\n          static get template() { return html`\n            <dom-repeat items=\"[0]\">\n              <template>\n                <div id=\"dom-repeat-ok\"></div>\n                <dom-if if>\n                  <template><div id=\"nested-dom-if-ok\"></div></template>\n                </dom-if>\n              </template>\n            </dom-repeat>\n            <dom-if if>\n              <template>\n                <div id=\"dom-if-ok\"></div>\n                <dom-repeat items=\"[0]\">\n                  <template>\n                    <div id=\"nested-dom-repeat-ok\"></div>\n                  </template>\n                </dom-repeat>\n              </template>\n            </dom-if>`; \n          }\n        }\n        customElements.define('trusted-templates', TrustedTemplates);\n    \n        var el = document.createElement('trusted-templates');\n        document.getElementById('target').appendChild(el);\n        flush();\n        assert.ok(el.shadowRoot.querySelector('#dom-repeat-ok'));\n        assert.ok(el.shadowRoot.querySelector('#dom-if-ok'));\n        assert.ok(el.shadowRoot.querySelector('#nested-dom-repeat-ok'));\n        assert.ok(el.shadowRoot.querySelector('#nested-dom-if-ok'));\n      });\n\n      test('template helpers in trusted templates work (legacy)', function() {\n\n        Polymer({\n          is: 'trusted-templates-legacy',\n          _template: html`\n            <template is=\"dom-repeat\" items=\"[0]\">\n              <div id=\"dom-repeat-ok\"></div>\n              <template is=\"dom-if\" if><div id=\"nested-dom-if-ok\"></div></template>\n            </template>\n            <template is=\"dom-if\" if>\n              <div id=\"dom-if-ok\"></div>\n              <template is=\"dom-repeat\" items=\"[0]\"><div id=\"nested-dom-repeat-ok\"></div></template>\n            </template>`\n        });\n\n        var el = document.createElement('trusted-templates-legacy');\n        document.getElementById('target').appendChild(el);\n        flush();\n        assert.ok(el.shadowRoot.querySelector('#dom-repeat-ok'));\n        assert.ok(el.shadowRoot.querySelector('#dom-if-ok'));\n        assert.ok(el.shadowRoot.querySelector('#nested-dom-repeat-ok'));\n        assert.ok(el.shadowRoot.querySelector('#nested-dom-if-ok'));\n      });\n\n    });\n\n  </script>\n    \n</body>\n</html>"
  },
  {
    "path": "test/unit/styling-build-adopted-stylesheets.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script>\n    window.ShadyCSS['cssBuild'] = true;\n  </script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\">\n    import {\n      setUseAdoptedStyleSheetsWithBuiltCSS,\n      supportsAdoptingStyleSheets,\n    } from '../../lib/utils/settings.js';\n    setUseAdoptedStyleSheetsWithBuiltCSS(true);\n    window.supportsAdoptingStyleSheets = supportsAdoptingStyleSheets;\n    let define = window.customElements.define;\n    let order = [];\n    window.customElements.define = function(name, fn, options) {\n      order.push(name);\n      return define.call(window.customElements, name, fn, options);\n    };\n    customElements.defineOrder = order;\n  </script>\n</head>\n<body>\n\n<dom-module id=\"x-keyframes\">\n  <template css-build=\"shadow\">\n    <style>\n      :host {\n        display: block;\n        position: relative;\n        border: 10px solid blue;\n        left: 0px;\n        /* Prefix required by Safari <= 8 */\n        -webkit-animation-duration: 0.3s;\n        animation-duration: 0.3s;\n        -webkit-animation-fill-mode: forwards;\n        animation-fill-mode: forwards;\n      }\n\n      :host([animated]) {\n        /* Prefix required by Safari <= 8 */\n        -webkit-animation-name: x-keyframes-animation;\n        animation-name: x-keyframes-animation;\n      }\n\n      /* Prefix required by Safari <= 8 */\n      @-webkit-keyframes x-keyframes-animation {\n        0% {\n          left: var(--keyframes0, 0px);\n        }\n\n        100% {\n          left: var(--keyframes100, 10px);\n        }\n      }\n      @keyframes x-keyframes-animation {\n        0% {\n          left: var(--keyframes0, 0px);\n        }\n\n        100% {\n          left: var(--keyframes100, 10px);\n        }\n      }\n    </style>\n    x-keyframes\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-keyframes',\n  properties: {\n    animated: {\n      type: Boolean,\n      value: false,\n      reflectToAttribute: true\n    }\n  }\n});\n</script>\n</dom-module>\n<dom-module id=\"x-gchild\">\n  <template css-build=\"shadow\">\n    <style>\n    </style>\n    <div id=\"target\">x-gchild</div>\n  </template>\n</dom-module>\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-gchild'\n});\n</script>\n\n<dom-module id=\"x-child\">\n  <template css-build=\"shadow\">\n    <div id=\"simple\">simple</div>\n    <div id=\"complex1\" class=\"scoped\">complex1</div>\n    <div id=\"complex2\" selected>complex2</div>\n    <div id=\"media\">media</div>\n    <div id=\"shadow\" class=\"shadowTarget\">shadowTarget</div>\n    <div id=\"deep\" class=\"deepTarget\">deepTarget</div>\n    <x-gchild id=\"gchild1\"></x-gchild>\n    <x-gchild id=\"gchild2\" class=\"wide\"></x-gchild>\n  </template>\n</dom-module>\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-child',\n  hostAttributes: {\n    class: 'nug'\n  }\n});\n</script>\n\n<dom-module id=\"x-child2\">\n  <template css-build=\"shadow\">\n    <style>\n      :host(.wide) #target{\n        border: none;\n      }\n    </style>\n    <div id=\"target\">x-child2</div>\n  </template>\n</dom-module>\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-child2'\n});\n</script>\n\n<dom-module id=\"x-scope-class\">\n  <template css-build=\"shadow\">\n    <div id=\"scope\">Trivial</div>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-scope-class'\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-class-literal\">\n  <template css-build=\"shadow\">\n    <div id=\"scope\" class$=\"a [[b]] c\" class=\"d e\">Trivial</div>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-class-literal'\n});\n</script>\n</dom-module>\n\n\n\n<dom-module id=\"x-styled\">\n  <template css-build=\"shadow\">\n    <style>\n      :host {\n        display: block;\n        border: 1px solid orange;\n        --keyframes100: 100px;\n      }\n\n      :host(.wide) {\n        border-width: 2px;\n      }\n\n      :host(.wide)::after {\n        content: '-content-';\n      }\n\n      #keyframes2.special {\n        --keyframes100: 200px;\n      }\n\n      #simple {\n        border: 3px solid orange;\n      }\n\n      .scoped, [selected] {\n        border: 4px solid pink;\n      }\n\n      @media(max-width: 10000px) {\n        .media {\n          border: 5px solid brown;\n        }\n      }\n\n      .container ::slotted(*) {\n        border: 6px solid navy;\n      }\n\n      #priority {\n        border: 9px solid orange;\n      }\n\n      .container1 > ::slotted([slot=content1]) {\n        border: 13px solid navy;\n      }\n\n      .container2 > ::slotted([slot=content2]) {\n        border: 14px solid navy;\n      }\n\n      .computed {\n        border: 15px solid orange;\n      }\n\n      .computeda {\n        border: 20px solid orange;\n      }\n\n      .a.computedb {\n        border: 16px solid gray;\n      }\n\n      #child {\n        border: 16px solid tomato;\n        display: block;\n      }\n\n      svg {\n        margin-top: 20px;\n      }\n\n      #circle {\n        fill: seagreen;\n        stroke-width: 1px;\n        stroke: tomato;\n      }\n    </style>\n    <slot name=\"blank\"></slot>\n    <div id=\"simple\">simple</div>\n    <div id=\"complex1\" class=\"scoped\">complex1</div>\n    <div id=\"complex2\" selected>complex2</div>\n    <div id=\"media\" class=\"media\">media</div>\n    <div class=\"container1\">\n      <slot name=\"content1\"></slot>\n    </div>\n    <div class=\"container2\">\n      <slot name=\"content2\"></slot>\n    </div>\n    <div class=\"container\">\n      <slot></slot>\n    </div>\n    <x-child id=\"child\"></x-child>\n    <div id=\"priority\">priority</div>\n    <x-child2 class=\"wide\" id=\"child2\"></x-child2>\n    <div id=\"computed\" class$=\"{{computeClass(aClass)}}\">Computed</div>\n    <div>\n      <div id=\"computed2\" class$=\"a {{computeClass('computedb')}}\">Computed</div>\n    </div>\n    <div id=\"repeatContainer\">\n      <template css-build=\"shadow\" id=\"repeat\" is=\"dom-repeat\" items=\"{{items}}\">\n        <a class$=\"{{aaClass}}\">A Computed</a>\n      </template>\n    </div>\n    <svg height=\"25\" width=\"25\">\n      <circle id=\"circle\" cx=\"12\" cy=\"12\" r=\"10\"></circle>\n    </svg>\n    <x-scope-class id=\"scopeClass\"></x-scope-class>\n    <x-keyframes id=\"keyframes\"></x-keyframes>\n    <x-keyframes id=\"keyframes2\"></x-keyframes>\n  </template>\n</dom-module>\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-styled',\n\n  properties: {\n    items: {value: [{}]}\n  },\n\n  computeClass: function(className) {\n    return className;\n  }\n\n});\n</script>\n\n<template css-build=\"shadow\" id=\"dynamic\">\n  <div class=\"added\">\n    Added\n    <div class=\"sub-added\">\n      Sub-added\n    </div>\n  </div>\n</template>\n\n<dom-module id=\"x-dynamic-scope\">\n  <template css-build=\"shadow\">\n    <style>\n      .added {\n        border: 17px solid beige;\n      }\n\n      .sub-added {\n        border: 18px solid #fafafa;\n      }\n    </style>\n    <div id=\"container\"></div>\n  </template>\n</dom-module>\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nvar doc = window.document;\nvar dynamic = doc.querySelector('template#dynamic');\n\nPolymer({\n  is: 'x-dynamic-scope',\n  ready: function() {\n    // simulate 3rd party action by using normal dom to add to element.\n    var dom = document.importNode(dynamic.content, true);\n    this.$.container.appendChild(dom);\n  }\n});\n</script>\n\n<template css-build=\"shadow\" id=\"dynamic-style-template\">\n  <style>\n    :host {\n      border: 40px solid tomato;\n    }\n  </style>\n  <div>big border</div>\n</template>\n\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nvar doc = window.document;\nvar template = doc.querySelector('template#dynamic-style-template');\n\nPolymer({\n  is: 'x-dynamic-template',\n  registered: function() {\n    this._template = template;\n  }\n});\n</script>\n\n<template css-build=\"shadow\" id=\"svg\">\n  <svg class=\"svg\" viewBox=\"0 0 24 24\">\n    <circle id=\"circle\" r=\"12\" cx=\"12\" cy=\"12\" />\n  </svg>\n</template>\n\n<dom-module id=\"x-dynamic-svg\">\n  <template css-build=\"shadow\">\n    <style>\n      .svg {\n        height: 24px;\n        width: 24px;\n      }\n      #circle {\n        fill: red;\n        fill-opacity: 0.5;\n      }\n    </style>\n    <div id=\"container\"></div>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nvar doc = window.document;\nvar template = doc.querySelector('template#svg');\n\nPolymer({\n  is: 'x-dynamic-svg',\n  ready: function() {\n    this.scopeSubtree(this.$.container, true);\n    var dom = document.importNode(template.content, true);\n    this.$.container.appendChild(dom);\n  }\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-specificity\">\n  <template css-build=\"shadow\">\n    <style>\n      :host {\n        border-top: 1px solid red;\n      }\n      :host(.bar) {\n        border-top: 2px solid red;\n      }\n    </style>\n    <slot></slot>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-specificity'});\n</script>\n</dom-module>\n\n<custom-style>\n  <style>\n    html {\n      --x-specificity-parent: 10px solid blue;\n      --x-specificity-nested: 3px solid red;\n    }\n  </style>\n</custom-style>\n\n<dom-module id=\"x-specificity-parent\">\n  <template css-build=\"shadow\">\n    <style>\n      ::slotted(:not(template)) {\n        border: var(--x-specificity-parent);\n      }\n    </style>\n    <slot></slot>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-specificity-parent'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-specificity-nested\">\n  <template css-build=\"shadow\">\n    <style>\n      :host {\n        border: var(--x-specificity-nested);\n      }\n    </style>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-specificity-nested'});\n</script>\n</dom-module>\n\n<custom-style>\n  <style>\n    html {\n      --x-overriding: 1px solid red;\n    }\n  </style>\n</custom-style>\n\n<dom-module id=\"x-overriding\">\n  <template css-build=\"shadow\">\n    <style>\n      .red {\n        border-top: var(--x-overriding);\n      }\n      .green {\n        border-top: var(--x-overriding);\n        border-top: 2px solid green;\n      }\n      .red-2 {\n        border-top: 2px solid green;\n        border-top: var(--x-overriding);\n      }\n      .blue {\n        border-top: var(--x-overriding);\n        border-top: 3px solid blue;\n      }\n    </style>\n\n    <div class=\"red\">red</div>\n    <div class=\"green\">green</div>\n    <div class=\"red-2\">green-2</div>\n    <div class=\"blue\">blue</div>\n  </template>\n</dom-module>\n\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-overriding'\n});\n</script>\n\n<dom-module id=\"x-attr-selector\">\n  <template css-build=\"shadow\">\n    <style>\n      #foo1 ~ #bar1 {\n        border: 2px solid red;\n      }\n\n      #foo1 ~ #bar1 ~ #foo2[attr~=foo2] ~ #bar2[attr~=bar2]  {\n        border: 4px solid red;\n      }\n\n      #foo1 ~ #bar1 ~ #foo2[attr~=foo2] ~ #bar2[attr~=bar2] ~ #foo3[attr~=foo3][a~=a] ~ #bar3[attr~=bar3][a~=a] {\n        border: 6px solid red;\n      }\n    </style>\n    <div id=\"foo1\"></div>\n    <div id=\"bar1\">bar1</div>\n    <div id=\"foo2\" attr=\"foo2\"></div>\n    <div id=\"bar2\" attr=\"bar2\">bar2</div>\n    <div id=\"foo3\" attr=\"foo3\" a=\"a\"></div>\n    <div id=\"bar3\" attr=\"bar3\" a=\"a\">bar3</div>\n\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-attr-selector'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-shared1\">\n  <template css-build=\"shadow\">\n    <style>\n      :host(x-shared1) {\n        display: block;\n        border: 2px solid orange;\n      }\n\n      :host(x-shared2) {\n        display: block;\n        border: 4px solid orange;\n      }\n\n      :host(.x-shared1) {\n        top: 10px;\n      };\n    </style>\n    x-shared1\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-shared1'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-shared2\">\n  <template css-build=\"shadow\">\n    <style>\n      :host(x-shared1) {\n        display: block;\n        border: 2px solid orange;\n      }\n\n      :host(x-shared2) {\n        display: block;\n        border: 4px solid orange;\n      }\n\n      :host(.x-shared1) {\n        top: 10px;\n      };\n    </style>\n    x-shared2\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-shared2'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-slotted\">\n  <template css-build=\"shadow\">\n    <style>\n    ::slotted(.auto-content) {\n      border: 2px solid orange;\n    }\n    .bar, ::slotted(.complex-child) {\n      border: 6px solid navy;\n    }\n    #container ::slotted(*) {\n      border: 8px solid green;\n    }\n    </style>\n    <slot></slot>\n    <div id=\"container\">\n      <slot name=\"container\"></slot>\n    </div>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-slotted'});\n</script>\n</dom-module>\n\n<template css-build=\"shadow\" id=\"xClass\">\n  <style>\n    :host {\n      display: block;\n      border: 1px solid orange;\n    }\n  </style>\n</template>\n<script type=\"module\">\nimport { PolymerElement, html } from '../../polymer-element.js';\ncustomElements.define('x-class-no-is', class extends PolymerElement {\n  static get template() {\n    return window.xClass;\n  }\n});\n\ncustomElements.define('x-template-string', class extends PolymerElement {\n  static get template() {\n    return html`<style>\n      :host {\n        display: block;\n        border: 1px solid orange;\n      }\n    </style>;`;\n  }\n});\n</script>\n\n\n  <div class=\"scoped\">no margin</div>\n\n  <x-styled>\n    <div slot=\"content1\">Foo</div>\n    <div slot=\"content2\">Bar</div>\n    <div class=\"content\">Content</div>\n  </x-styled>\n\n  <x-styled class=\"wide\"></x-styled>\n\n  <x-dynamic-scope></x-dynamic-scope>\n\n  <dom-bind id=\"bind\">\n    <template css-build=\"shadow\">\n      <div id=\"dom-bind-static\" class=\"static\">static</div>\n      <span id=\"dom-bind-dynamic\" class$=\"[[dynamic]]\">[[dynamic]]</span>\n    </template>\n  </dom-bind>\n\n  <x-dynamic-svg></x-dynamic-svg>\n  <x-specificity></x-specificity>\n  <x-specificity class=\"bar\"></x-specificity>\n  <x-specificity-parent>\n    <x-specificity-nested></x-specificity-nested>\n  </x-specificity-parent>\n  <x-overriding></x-overriding>\n\n  <dom-module id=\"x-nested-style\">\n    <template css-build=\"shadow\">\n      <div id=\"container\">\n        <style>\n          :host {\n            display: block;\n            border: 10px solid black;\n          }\n        </style>\n        <style>\n            :host {\n              padding-top: 10px;\n            }\n          </style>\n      </div>\n    </template>\n    <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nclass XNestedStyle extends PolymerElement {\n  static get is() {return 'x-nested-style';}\n}\ncustomElements.define(XNestedStyle.is, XNestedStyle);\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-interleaved-styles\">\n    <template css-build=\"shadow\">\n      <style include=\"x-nested-style\"></style>\n      <style>\n        :host {\n          padding-top: 5px;\n        }\n      </style>\n      <style>\n        :host {\n          color: blue;\n        }\n      </style>\n    </template>\n    <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nclass XInterleaved extends PolymerElement {\n  static get is() {return 'x-interleaved-styles';}\n}\ncustomElements.define(XInterleaved.is, XInterleaved);\n</script>\n  </dom-module>\n\n<script type=\"module\">\n  import { PolymerElement, html } from '../../polymer-element.js';\n  class ClassBindingUndefined extends PolymerElement {\n    static get is() { return 'class-binding-undefined'; }\n    static get properties() {\n      return {\n        data: {\n          type: Object\n        }\n      };\n    }\n    static get template() {\n      return html`\n      <style>\n        div {\n          border: 10px solid black;\n        }\n      </style>\n      <div id=\"div\" class$=\"[[data.class]]\">Foo</div>\n      `;\n    }\n  }\n  customElements.define(ClassBindingUndefined.is, ClassBindingUndefined);\n</script>\n\n<script type=\"module\">\nimport { dom } from '../../lib/legacy/polymer.dom.js';\nimport { flush } from '../../lib/utils/flush.js';\nfunction assertComputed(element, value, property, pseudo) {\n  var computed = getComputedStyle(element, pseudo);\n  property = property || 'border-top-width';\n  if (Array.isArray(value)) {\n    assert.oneOf(computed[property], value, 'computed style incorrect for ' + property);\n  } else {\n    assert.equal(computed[property], value, 'computed style incorrect for ' + property);\n  }\n}\n\nvar styled = document.querySelector('x-styled');\nvar styledWide = document.querySelector('x-styled.wide');\nvar unscoped = document.querySelector('.scoped');\n\nsuite('scoped-styling', function() {\n\n  test('uses adoptedStyleSheets if possible', function() {\n    if (!window.supportsAdoptingStyleSheets) {\n      this.skip();\n    }\n    assert.ok(styled.shadowRoot.adoptedStyleSheets.length);\n  });\n\n  test(':host, :host(...)', function() {\n    assertComputed(styled, '1px');\n    assertComputed(styledWide, '2px');\n    assertComputed(styled, ['', 'none'], 'content', '::after');\n    assertComputed(styledWide, ['\"-content-\"', '-content-'], 'content', '::after');\n  });\n\n  test('scoped selectors, simple and complex', function() {\n    assertComputed(styled.$.simple, '3px');\n    assertComputed(styled.$.complex1, '4px');\n    assertComputed(styled.$.complex2, '4px');\n  });\n\n  test('media query scoped selectors', function() {\n    assertComputed(styled.$.media, '5px');\n  });\n\n  test('upper bound encapsulation', function() {\n    assertComputed(unscoped, '0px');\n  });\n\n  test('lower bound encapsulation', function() {\n    assertComputed(styled.$.child.$.simple, '0px');\n    assertComputed(styled.$.child.$.complex1, '0px');\n    assertComputed(styled.$.child.$.complex2, '0px');\n    assertComputed(styled.$.child.$.media, '0px');\n  });\n\n  test('::slotted selectors', function() {\n    var content = document.querySelector('.content');\n    var content1 = document.querySelector('[slot=content1]');\n    var content2 = document.querySelector('[slot=content2]');\n    assertComputed(content, '6px');\n    assertComputed(content1, '13px');\n    assertComputed(content2, '14px');\n  });\n\n  test('auto ::slotted selector', function() {\n    var x = document.createElement('x-slotted');\n    var d1 = document.createElement('div');\n    d1.classList.add('auto-content');\n    d1.textContent = 'auto-content';\n    document.body.appendChild(x);\n    dom(x).appendChild(d1);\n    flush();\n    assertComputed(d1, '2px');\n  });\n\n  test('::slotted + child in complex selector', function() {\n    var x = document.createElement('x-slotted');\n    var d1 = document.createElement('div');\n    d1.classList.add('complex-child');\n    d1.textContent = 'complex-child';\n    document.body.appendChild(x);\n    dom(x).appendChild(d1);\n    flush();\n    assertComputed(d1, '6px');\n  });\n\n  test('::slotted + named slot', function() {\n    var x = document.createElement('x-slotted');\n    var d1 = document.createElement('div');\n    d1.setAttribute('slot', 'container');\n    d1.textContent = 'named slot child';\n    document.body.appendChild(x);\n    dom(x).appendChild(d1);\n    flush();\n    assertComputed(d1, '8px');\n  });\n\n  test('elements dynamically added/removed from root', function() {\n    var d = document.createElement('div');\n    d.classList.add('scoped');\n    d.textContent = 'Dynamically... Scoped!';\n    dom(styled.root).appendChild(d);\n    flush();\n    assertComputed(d, '4px');\n    dom(document.body).appendChild(d);\n    flush();\n    assert.notInclude(d.getAttribute('style-scoped') || '', styled.is, 'scoping attribute not removed when added to other root');\n    assert.notInclude(d.className, styled.is, 'scoping class not removed when added to other root');\n    assertComputed(d, '0px');\n    dom(styled.root).appendChild(d);\n    flush();\n    assertComputed(d, '4px');\n  });\n\n  test('elements dynamically added/removed from host', function() {\n    var d = document.createElement('div');\n    d.classList.add('scoped');\n    d.slot = 'blank';\n    d.textContent = 'Dynamically... unScoped!';\n    dom(styled).appendChild(d);\n    flush();\n    assertComputed(d, '0px');\n    dom(document.body).appendChild(d);\n    flush();\n    assert.notInclude(d.getAttribute('style-scoped') || '', styled.is, 'scoping attribute not removed when added to other root');\n    assert.notInclude(d.className, styled.is, 'scoping class not removed when added to other root');\n    dom(styled).appendChild(d);\n    flush();\n    assertComputed(d, '0px');\n    dom(styled).removeChild(d);\n    flush();\n    assert.notInclude(d.getAttribute('style-scoped') || '', styled.is, 'scoping attribute not removed when removed from root');\n    assert.notInclude(d.className, styled.is, 'scoping class not removed when removed from root');\n    dom(styled).appendChild(d);\n    flush();\n    assertComputed(d, '0px');\n  });\n\n  test('keyframes change scope', function(done) {\n    if (navigator.userAgent.match('Edge') && (!window.ShadyCSS || window.ShadyCSS.nativeCss)) {\n      // skip test due to missing variable support in keyframes\n      // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/12084341/\n      this.skip();\n    }\n    var xKeyframes = styled.$.keyframes;\n\n    var onAnimationEnd = function() {\n      xKeyframes.removeEventListener('animationend', onAnimationEnd);\n      xKeyframes.removeEventListener('webkitAnimationEnd', onAnimationEnd);\n      assertComputed(xKeyframes, '100px', 'left');\n\n      xKeyframes = styled.$.keyframes2;\n\n      onAnimationEnd = function() {\n        xKeyframes.removeEventListener('animationend', onAnimationEnd);\n        xKeyframes.removeEventListener('webkitAnimationEnd', onAnimationEnd);\n        assertComputed(xKeyframes, '200px', 'left');\n        done();\n      };\n\n      xKeyframes.addEventListener('animationend', onAnimationEnd);\n      xKeyframes.addEventListener('webkitAnimationEnd', onAnimationEnd);\n\n      dom(xKeyframes).classList.add('special');\n      xKeyframes.updateStyles();\n      xKeyframes.animated = true;\n    };\n\n    xKeyframes.addEventListener('animationend', onAnimationEnd);\n    xKeyframes.addEventListener('webkitAnimationEnd', onAnimationEnd);\n\n    xKeyframes.animated = true;\n    assertComputed(xKeyframes, '0px', 'left');\n  });\n\n  test('elements with computed classes', function() {\n    assertComputed(styled.$.computed, '0px');\n    styled.aClass = 'computed';\n    assertComputed(styled.$.computed, '15px');\n    assertComputed(styled.$.computed2, '16px');\n  });\n\n  test('<a> with computed classes dynamically added', function() {\n    assertComputed(styled.$.repeatContainer.firstElementChild, '0px');\n    styled.aaClass = 'computeda';\n    assertComputed(styled.$.repeatContainer.firstElementChild, '20px');\n  });\n\n  test('elements with hostAttributes: class', function() {\n    assertComputed(styled.$.child, '16px');\n  });\n\n  test('element subtree added via dom api', function() {\n    var container = document.querySelector('x-dynamic-scope').$.container;\n    var a = container.querySelector('.added');\n    assertComputed(a, '17px');\n    var b = container.querySelector('.sub-added');\n    assertComputed(b, '18px');\n  });\n\n  test('styles in dynamically selected template', function() {\n    var el = document.createElement('x-dynamic-template');\n    document.body.appendChild(el);\n    if (el.shadowRoot) {\n      // style properly removed\n      assert.notOk(el.querySelector('style'));\n    }\n    assertComputed(el, '40px');\n    document.body.removeChild(el);\n  });\n\n  test('attribute inclusive selector and general sibling selectors', function() {\n    var e = document.createElement('x-attr-selector');\n    document.body.appendChild(e);\n    flush();\n    assertComputed(e.$.bar1, '2px');\n    assertComputed(e.$.bar2, '4px');\n    assertComputed(e.$.bar3, '6px');\n  });\n\n  test('svg classes are dynamically scoped correctly', function() {\n    var container = document.querySelector('x-dynamic-svg').$.container;\n    var svg = container.querySelector('.svg');\n    var computed = getComputedStyle(svg);\n    assert.equal(computed.height, '24px');\n    assert.equal(computed.width, '24px');\n    var circle = container.querySelector('#circle');\n    computed = getComputedStyle(circle);\n    assert.equal(computed['fill-opacity'], '0.5');\n  });\n\n  test(':host with element tag selector', function() {\n    var s1 = document.createElement('x-shared1');\n    document.body.appendChild(s1);\n    assertComputed(s1, '2px');\n    var s2 = document.createElement('x-shared2');\n    document.body.appendChild(s2);\n    assertComputed(s2, '4px');\n  });\n\n  test(':host with superset of element tag selector does not leak', function() {\n    var t = document.createElement('div');\n    t.textContent = 'host leak test';\n    t.classList.add('x-shared1');\n    document.body.appendChild(t);\n    assertComputed(t, 'auto', 'top');\n  });\n\n  test(':host(...) with non-matching type selector does not leak', function() {\n    var t = document.createElement('x-shared1x-shared2');\n    t.textContent = ':host(non-matching-type-selector)';\n    document.body.appendChild(t);\n    assertComputed(t, '0px');\n    t = document.createElement('x-shared2x-shared1');\n    t.textContent = ':host(non-matching-type-selector)';\n    document.body.appendChild(t);\n    assertComputed(t, '0px');\n  });\n\n  test('static is not required for scoping styling', function() {\n    var e = document.createElement('x-class-no-is');\n    document.body.appendChild(e);\n    assertComputed(e, '1px');\n  });\n\n  test('template string has scoped styling', function() {\n    var e = document.createElement('x-template-string');\n    document.body.appendChild(e);\n    assertComputed(e, '1px');\n  });\n\n  test('styles work correctly when not direct children of the template', function() {\n    var e = document.createElement('x-nested-style');\n    document.body.appendChild(e);\n    assertComputed(e, '10px');\n    assertComputed(e, '10px', 'padding-top');\n  });\n\n  test('interleaved styles and styles with includes work as expected', function() {\n    var e = document.createElement('x-interleaved-styles');\n    document.body.appendChild(e);\n    assertComputed(e, '5px', 'padding-top');\n  });\n\n  test('initial literal values in class are preserved when a class$ binding is present', function() {\n    var e = document.createElement('x-class-literal');\n    document.body.appendChild(e);\n    var el = e.$.scope;\n    assert.isTrue(el.classList.contains('a'));\n    assert.isTrue(el.classList.contains('c'));\n    assert.isTrue(el.classList.contains('d'));\n    assert.isTrue(el.classList.contains('e'));\n  });\n\n  test('scoping classes are preserved when a class$ binding resolves to undefined', function() {\n    const e = document.createElement('class-binding-undefined');\n    document.body.appendChild(e);\n    const el = e.$.div;\n    assertComputed(el, '10px');\n  });\n\n});\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/styling-cross-scope-apply.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n</head>\n<body>\n\n  <x-scope></x-scope>\n\n  <dom-module id=\"story-card\">\n    <template>\n    <style>\n      :host {\n        display: block;\n      }\n\n      #story-card .story-content {\n        font-family: 'Roboto', sans-serif;\n        font-size: 1.2em;\n        @apply --story-content;\n      }\n    </style>\n\n      <div id=\"story-card\">\n        <div class=\"story-content\" id=\"content\">Content</div>\n      </div>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'story-card'});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-child-scope\">\n    <template>\n    <style>\n      :host {\n        display: block;\n\n        --mixin2: {\n          border: 3px solid seagreen;\n          background: url(http://www.google.com/icon.png);\n        };\n      }\n\n      #mixin1 {\n        @apply --mixin1;\n      }\n\n      #mixin2 {\n        @apply --mixin2;\n      }\n\n      #mixin3 {\n        padding: 3px;\n        @apply --mixin3;\n      }\n\n      #mixin4 {\n        @apply --mixin4;\n      }\n\n      #mixin6 {\n        @apply --mixin6\n      }\n\n      #mixin7 {@apply --mixin7}\n\n      #mixin8 {\n        @apply --mixin8\n      }\n\n      #mixin9 {\n        @apply --mixin9\n      }\n    </style>\n\n      <div id=\"mixin1\">mixin1</div>\n      <div id=\"mixin2\">mixin2</div>\n      <div id=\"mixin3\">mixin3</div>\n      <div id=\"mixin4\">mixin4</div>\n      <div id=\"mixin6\">mixin6</div>\n      <div id=\"mixin7\">mixin7</div>\n      <div id=\"mixin8\">mixin8</div>\n      <div id=\"mixin9\">mixin9</div>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-child-scope'});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-keyframes\">\n    <template>\n      <style>\n        :host {\n          display: block;\n          position: relative;\n          border: 10px solid blue;\n          left: 0px;\n          /* Prefix required by Safari <= 8 */\n          -webkit-animation-duration: 0.3s;\n          animation-duration: 0.3s;\n          -webkit-animation-fill-mode: forwards;\n          animation-fill-mode: forwards;\n        }\n\n        :host([animated]) {\n          /* Prefix required by Safari <= 8 */\n          -webkit-animation-name: x-keyframes-animation;\n          animation-name: x-keyframes-animation;\n        }\n\n        /* Prefix required by Safari <= 8 */\n        @-webkit-keyframes x-keyframes-animation {\n          0% {\n            left: var(--c1);\n          }\n\n          100% {\n            left: var(--c2);\n            @apply --keyframe-finish;\n          }\n        }\n        @keyframes x-keyframes-animation {\n          0% {\n            left: var(--c1);\n          }\n\n          100% {\n            left: var(--c2);\n            @apply --keyframe-finish;\n          }\n        }\n      </style>\n      x-keyframes\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-keyframes',\n  properties: {\n    animated: {\n      type: Boolean,\n      value: false,\n      reflectToAttribute: true\n    }\n  }\n});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-scope\">\n    <template>\n    <style>\n      :host {\n        display: block;\n        padding: 8px;\n\n        --override-me: {\n          border: 11px solid black;\n        };\n\n        --mixin1: {\n          border: 1px solid black;\n        };\n\n        --b: 2px solid orange;\n\n        --m1: 1px;\n        --m2: 2px;\n\n        --c1: 5px;\n        --c2: 10px;\n\n        --mixin2: {\n          border: var(--b);\n        };\n\n        --mixin3: {\n          @apply --mixin2;\n        };\n\n        --mixin4: {\n          padding: 2px;\n          @apply --mixin3;\n          margin: var(--m2);\n        };\n\n        --mixin5: {\n          border: calc(var(--c1) + var(--c2)) solid orange;\n        };\n\n        --mixin6: {\n          border: 16px solid orange;\n        };\n\n        --mixin7: {\n          border: 17px solid navy;\n        };\n\n        --mixin8: {\n          border: 17px dotted navy;\n        };\n\n        --mixin9: var(--mixin8);\n      }\n\n      #mixin1 {\n        @apply --mixin1;\n      }\n\n      #mixin2 {\n        @apply --mixin2;\n      }\n\n      #mixin3 {\n        padding: 1px;\n        margin: var(--m1);\n        @apply --mixin3;\n      }\n\n      #mixin4 {\n        @apply --mixin4;\n      }\n\n      #mixin5 {\n        @apply --mixin5;\n      }\n\n      #keyframes2 {\n        --keyframe-finish: {\n          left: 20px;\n        };\n      }\n\n      x-child-scope {\n        padding: 10px;\n      }\n\n      #card {\n        --story-content: {\n          border: 11px solid orange;\n        };\n      }\n\n      #override {\n        @apply --override-me;\n        border: 19px solid steelblue;\n      }\n\n    </style>\n\n      <div id=\"mixin1\">mixin1</div>\n      <div id=\"mixin2\">mixin2</div>\n      <div id=\"mixin3\">mixin3</div>\n      <div id=\"mixin4\">mixin4</div>\n      <div id=\"mixin5\">mixin5</div>\n      <hr>\n      <x-keyframes id=\"keyframes1\"></x-keyframes>\n      <x-keyframes id=\"keyframes2\"></x-keyframes>\n      <x-child-scope id=\"child\"></x-child-scope>\n      <story-card id=\"card\"></story-card>\n      <div id=\"override\">override</div>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-scope'});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-var-produce-via-consume\">\n  <template>\n    <style>\n      :host {\n        display: block;\n        border: 10px solid orange;\n        --foo: {\n          color: var(--bar);\n        }\n      }\n    </style>\n        </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-var-produce-via-consume'\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-cache-child\">\n  <template>\n    <style>\n    :host {\n      display: block;\n      color: var(--foo);\n      @apply --bar;\n    }\n    </style>\n    X\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-cache-child'\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-cache-host-1\">\n  <template>\n    <style>\n    :host {\n      display: block;\n      --foo: blue;\n      --bar: {\n        border: 10px solid black;\n      };\n    }\n    </style>\n    <x-cache-child id=\"child\"></x-bad-child>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-cache-host-1'\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-cache-host-2\">\n  <template>\n    <style>\n    :host {\n      display: block;\n      --foo: blue;\n      --bar: {\n        border: 1px dotted green;\n      };\n    }\n    </style>\n    <x-cache-child id=\"child\"></x-bad-child>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-cache-host-2'\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-no-paren-apply-only\">\n  <template>\n    <style>\n    :host {\n      --bar: {\n        border: 2px solid green;\n      }\n    }\n    #child {\n      @apply --bar;\n    }\n    </style>\n    <div id=\"child\">X</div>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-no-paren-apply-only'\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-redefine-three\">\n  <template>\n    <style>\n      div {\n        @apply --redefine;\n      }\n    </style>\n    <div id=\"div\"></div>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-redefine-three'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-redefine-two\">\n  <template>\n    <style>\n      x-redefine-three {\n        --redefine: {\n          border: 2px solid gray;\n        };\n      }\n    </style>\n    <x-redefine-three id=\"three\"></x-redefine-three>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-redefine-two'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-redefine-one\">\n  <template>\n    <style>\n      x-redefine-two {\n        --redefine: {\n          height: 100px;\n          width: 100px;\n        };\n      }\n    </style>\n    <x-redefine-two id=\"two\"></x-redefine-two>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-redefine-one'});\n</script>\n</dom-module>\n\n<dom-module id=\"order-child\">\n  <template>\n    <style>\n      div {\n        @apply --order-mixin;\n      }\n    </style>\n    <div id=\"target\"></div>\n  </template>\n</dom-module>\n\n<dom-module id=\"order-parent\">\n  <template>\n    <style>\n      order-child {\n        --order-mixin: {\n          border: 10px solid black;\n        };\n      }\n    </style>\n    <order-child id=\"child\"></order-child>\n  </template>\n</dom-module>\n\n<dom-module id=\"order-gp\">\n  <template>\n    <style>\n      order-child {\n        --order-mixin: {\n        };\n      }\n    </style>\n    <order-child id=\"child\"></order-child>\n    <order-parent id=\"parent\"></order-parent>\n  </template>\n</dom-module>\n\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'order-child'});\nPolymer({is: 'order-parent'});\nPolymer({is: 'order-gp'});\n</script>\n<script type=\"module\">\nimport { flush } from '../../lib/utils/flush.js';\nsuite('scoped-styling-apply', function() {\n  function assertComputed(element, value, property) {\n    var computed = getComputedStyle(element);\n    property = property || 'border-top-width';\n    assert.equal(computed[property], value, 'computed style incorrect for ' + property);\n  }\n\n  var styled = document.querySelector('x-scope');\n\n  test('variable mixins calculated correctly and inherit', function() {\n    if (!window.ShadyCSS || ShadyCSS.nativeCss) {\n      this.skip();\n    }\n    var suffix = window.ShadyCSS.ApplyShim._separator + 'border';\n    var e = styled;\n    let mixin1 = ShadyCSS.ScopingShim.getComputedStyleValue(e, '--mixin1' + suffix);\n    let mixin2 = ShadyCSS.ScopingShim.getComputedStyleValue(e, '--mixin2' + suffix);\n    let mixin3 = ShadyCSS.ScopingShim.getComputedStyleValue(e, '--mixin3' + suffix);\n    let mixin4 = ShadyCSS.ScopingShim.getComputedStyleValue(e, '--mixin4' + suffix);\n    e = styled.$.child;\n    let cmixin1 = ShadyCSS.ScopingShim.getComputedStyleValue(e, '--mixin1' + suffix);\n    let cmixin2 = ShadyCSS.ScopingShim.getComputedStyleValue(e, '--mixin2' + suffix);\n    let cmixin3 = ShadyCSS.ScopingShim.getComputedStyleValue(e, '--mixin3' + suffix);\n    let cmixin4 = ShadyCSS.ScopingShim.getComputedStyleValue(e, '--mixin4' + suffix);\n    assert.equal(mixin1, cmixin1);\n    assert.equal(mixin2, cmixin2);\n    assert.equal(mixin3, cmixin3);\n    assert.equal(mixin4, cmixin4);\n  });\n\n  test('variable mixins apply', function() {\n    assertComputed(styled.$.mixin1, '1px');\n    assertComputed(styled.$.mixin2, '2px');\n    assertComputed(styled.$.mixin3, '2px');\n    assertComputed(styled.$.mixin3, '1px', 'padding-top');\n    assertComputed(styled.$.mixin3, '1px', 'margin-top');\n    assertComputed(styled.$.mixin4, '2px');\n    assertComputed(styled.$.mixin4, '2px', 'padding-top');\n    assertComputed(styled.$.mixin4, '2px', 'margin-top');\n  });\n\n  test('mixins apply with url values', function() {\n    var url = 'http://www.google.com/icon.png';\n    var e = styled.$.child;\n    var actual, unescaped, propertyName;\n    if (window.ShadyCSS && ShadyCSS.nativeCssApply) {\n      actual = getComputedStyle(e).getPropertyValue('--mixin2');\n      // if strings aren't used in the url, getPropertyValue will escape the string, which breaks assert.include\n      unescaped = actual.replace(/\\\\/g, '');\n      assert.include(unescaped, url);\n    } else if (!window.ShadyCSS || ShadyCSS.nativeCss) {\n      propertyName = '--mixin2' + window.ShadyCSS.ApplyShim._separator + 'background';\n      actual = getComputedStyle(e).getPropertyValue(propertyName);\n      // if strings aren't used in the url, getPropertyValue will escape the string, which breaks assert.include\n      unescaped = actual.replace(/\\\\/g, '');\n      assert.include(unescaped, url);\n    } else {\n      propertyName = '--mixin2';\n      actual = ShadyCSS.ScopingShim.getComputedStyleValue(e, propertyName);\n      unescaped = actual.replace(/\\\\/g, '');\n      assert.include(unescaped, url);\n    }\n  });\n\n  test('variable mixins inherit and override', function() {\n    var e = styled.$.child;\n    assertComputed(e.$.mixin1, '1px');\n    assertComputed(e.$.mixin2, '3px');\n    assertComputed(e.$.mixin3, '2px');\n    assertComputed(e.$.mixin3, '3px', 'padding-top');\n    assertComputed(e.$.mixin4, '2px');\n    assertComputed(e.$.mixin4, '2px', 'padding-top');\n    assertComputed(e.$.mixin4, '2px', 'margin-top');\n  });\n\n  test('calc can be used in mixins', function() {\n    assertComputed(styled.$.mixin5, '15px');\n  });\n\n  test('mixins work with selectors that contain element name', function() {\n    assertComputed(styled.$.card.$.content, '11px');\n  });\n\n  test('mixins with trailing new line or } apply', function() {\n    assertComputed(styled.$.child.$.mixin6, '16px');\n    assertComputed(styled.$.child.$.mixin7, '17px');\n  });\n\n  test('mixins with new `@apply --foo` syntax', function() {\n    assertComputed(styled.$.child.$.mixin8, '17px');\n  });\n\n  test('mixins can be realiased with var()', function() {\n    assertComputed(styled.$.child.$.mixin9, '17px');\n  });\n\n  test('mixins apply to @keyframe rules', function(done) {\n    if (navigator.userAgent.match('Edge') && (!window.ShadyCSS || window.ShadyCSS.nativeCss)) {\n      // skip test due to missing variable support in keyframes\n      // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/12084341/\n      this.skip();\n    }\n    var xKeyframes1 = styled.$.keyframes1;\n    var xKeyframes2 = styled.$.keyframes2;\n    var completed = 0;\n\n    [xKeyframes1, xKeyframes2].forEach(function(xKeyframes, index) {\n      var target = index === 0 ? '10px' : '20px';\n      var onAnimationEnd = function() {\n        assert.include(xKeyframes.getComputedStyleValue('left'), target, xKeyframes.id);\n\n        xKeyframes.removeEventListener('animationend', onAnimationEnd);\n        xKeyframes.removeEventListener('webkitAnimationEnd', onAnimationEnd);\n        xKeyframes.animated = false;\n        if (++completed > 1) {\n          done();\n        }\n      };\n\n      xKeyframes.addEventListener('animationend', onAnimationEnd);\n      xKeyframes.addEventListener('webkitAnimationEnd', onAnimationEnd);\n\n      xKeyframes.animated = true;\n    });\n  });\n\n  test('producing a var that consumes another var preserves static styling', function() {\n    var d = document.createElement('x-var-produce-via-consume');\n    document.body.appendChild(d);\n    assertComputed(d, '10px');\n  });\n\n  test('producing a var that consumes results in static and not dynamic stylesheet', function() {\n    var d = document.createElement('x-var-produce-via-consume');\n    document.body.appendChild(d);\n    var styleRoot = (!window.ShadyDOM || !ShadyDOM.isShadyRoot(d.shadowRoot)) ? d.shadowRoot : document.head;\n    var selector = window.ShadyDOM ? 'style[scope~=x-var-produce-via-consume]' : 'style';\n    var staticStyle = styleRoot.querySelector(selector);\n    assert.ok(staticStyle);\n    assert.match(staticStyle.textContent, /display/, 'static style does not contain style content');\n    assert.equal(styleRoot.querySelectorAll(selector).length, 1);\n  });\n\n  test('mixin values can be overridden by subsequent concrete properties', function() {\n    assertComputed(styled.$.override, '19px');\n  });\n\n  test('@apply without parens is included in style cache behavior', function() {\n    var e1 = document.createElement('x-cache-host-1');\n    var e2 = document.createElement('x-cache-host-2');\n    document.body.appendChild(e1);\n    document.body.appendChild(e2);\n    flush();\n    assertComputed(e1.$.child, '10px');\n    assertComputed(e2.$.child, '1px');\n  });\n\n  test('@apply without parens triggers property shim', function() {\n    var e = document.createElement('x-no-paren-apply-only');\n    document.body.appendChild(e);\n    flush();\n    assertComputed(e.$.child, '2px');\n  });\n\n  test('mixin redefinition resets old properties', function() {\n    var e = document.createElement('x-redefine-one');\n    document.body.appendChild(e);\n    flush();\n    var div = e.$.two.$.three.$.div;\n    assertComputed(div, '2px');\n    assertComputed(div, '0px', 'height');\n  });\n\n  test('mixin redefinition applies to complicated hierarchies', function() {\n    var e = document.createElement('order-gp');\n    document.body.appendChild(e);\n    flush();\n    var childDiv = e.$.child.$.target;\n    var parentDiv = e.$.parent.$.child.$.target;\n    assertComputed(childDiv, '0px');\n    assertComputed(parentDiv, '10px');\n  });\n});\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/styling-cross-scope-unknown-host.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n</head>\n<body>\n  <custom-style>\n    <style is=\"custom-style\">\n      unknown-host {\n        display: block;\n      }\n\n      html {\n        --border: 2px solid steelblue;\n        --mixin: {\n          color: blue;\n        };\n      }\n    </style>\n  </custom-style>\n\n  <script type=\"module\">\n'use strict';\nclass UnknownHost extends HTMLElement {\n  constructor() {\n    super();\n    this.attachShadow({mode: 'open'});\n  }\n}\ncustomElements.define('unknown-host', UnknownHost);\n</script>\n\n  <dom-module id=\"x-foo\">\n    <template>\n    <style>\n      :host {\n        border: var(--border);\n        display: block;\n        @apply --mixin;\n      }\n    </style>\n      x-foo\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-foo'\n});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-nest\">\n    <template>\n    <style>\n      :host {\n        --border: 4px solid tomato;\n      }\n    </style>\n      <unknown-host id=\"unknown\"></unknown-host>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-nest',\n\n  attached: function() {\n    this.$.unknown.shadowRoot.appendChild(document.createElement('x-foo'));\n  }\n});\n</script>\n  </dom-module>\n\n  <script type=\"module\">\nsuite('scoped-styling-unknown-host', function() {\n\n  function assertComputed(element, value, pseudo) {\n    var computed = getComputedStyle(element, pseudo);\n    assert.equal(computed['border-top-width'], value, 'computed style incorrect');\n  }\n\n  /* eslint-disable no-unused-vars */\n  function assertStylePropertyValue(properties, name, includeValue) {\n    assert.property(properties, name);\n    assert.include(properties[name], includeValue);\n  }\n  /* eslint-enable no-unused-vars */\n\n  test('element in top level unknown host styled via property defaults', function() {\n    var host = document.createElement('unknown-host');\n    var foo = document.createElement('x-foo');\n    host.shadowRoot.appendChild(foo);\n    document.body.appendChild(host);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    assertComputed(foo, '2px');\n  });\n\n  test('element in unknown host styled via containing polymer element', function() {\n    var n = document.createElement('x-nest');\n    document.body.appendChild(n);\n    if (window.ShadyDOM) {\n      ShadyDOM.flush();\n    }\n    if (window.customElements.flush) {\n      customElements.flush();\n    }\n    var foo = n.$.unknown.shadowRoot.querySelector('x-foo');\n    assertComputed(foo, '4px');\n  });\n\n});\n</script>\n\n\n</body>\n"
  },
  {
    "path": "test/unit/styling-cross-scope-var.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n  <style>\n  .variable-override {\n    border-top-width: 10px;\n  }\n</style>\n</head>\n<body>\n\n  <simple-element></simple-element>\n  <simple-element></simple-element>\n\n  <x-scope></x-scope>\n\n  <dom-module id=\"x-grand-child-scope\">\n    <template>\n      <style>\n        :host {\n          display: block;\n          padding: 8px;\n        }\n\n        #scope {\n          border: var(--scope-var);\n        }\n\n        #child {\n          border: var(--child-scope-var);\n        }\n\n        #me {\n          border: var(--grand-child-scope-var);\n        }\n\n      </style>\n      <div id=\"me\">x-grand-child-scope</div>\n      <div id=\"scope\">From x-scope</div>\n      <div id=\"child\">From x-child-scope</div>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-grand-child-scope'});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-host-property\">\n    <template>\n      <style>\n        :host {\n          display: block;\n          padding: 8px;\n          border: var(--scope-var);\n        }\n\n        :host(.foo) {\n          border: var(--scope-var-foo);\n        }\n      </style>\n      Host property\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-host-property'});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-host-host-property\">\n    <template>\n      <x-host-property id=\"hosted\"></x-host-property>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-host-host-property'});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-produce-use-property\">\n    <template>\n      <style>\n        :host {\n          --scope-var: 6px solid steelblue;\n          --scope-var-foo: 8px solid steelblue;\n        }\n      </style>\n      <x-host-host-property id=\"hosted\"></x-host-host-property>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-produce-use-property'});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-child-scope\">\n    <template>\n      <style>\n        :host {\n          display: block;\n          padding: 8px;\n        }\n\n        :host > * {\n          --gc4-scope: 5px solid green;\n        }\n\n        #me {\n          border: var(--child-scope-var);\n        }\n\n        #gc2 {\n          --grand-child-scope-var: 4px solid seagreen;\n        }\n\n        #gc4 {\n          --grand-child-scope-var:\n          var(--gc4-scope);\n        }\n      </style>\n      <div id=\"me\">x-child-scope</div>\n      <x-grand-child-scope id=\"gc1\"></x-grand-child-scope>\n      <x-grand-child-scope id=\"gc2\"></x-grand-child-scope>\n      <x-grand-child-scope id=\"gc3\"></x-grand-child-scope>\n      <x-grand-child-scope id=\"gc4\"></x-grand-child-scope>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-child-scope'});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-overrides\">\n    <template>\n      <style>\n        :host {\n          border: 1px dashed gray;\n          margin: 8px;\n          padding: 8px;\n          display: block;\n          --grand-child-scope-var: var(--rename);\n        }\n      </style>\n      overrides:\n      <x-grand-child-scope id=\"gc1\"></x-grand-child-scope>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-overrides'});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-overrides2\">\n    <template>\n      <style>\n        :host {\n          border: 1px dashed gray;\n          margin: 8px;\n          padding: 8px;\n          display: block;\n        }\n\n        :host > * {\n          --grand-child-scope-var: var(--rename);\n        }\n\n      </style>\n      overrides:\n      <x-grand-child-scope id=\"gc1\"></x-grand-child-scope>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-overrides2'});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-late\">\n    <template>\n      <style>\n        :host {\n          border: var(--late);\n          display: block;\n        }\n      </style>\n      late\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-late'});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-overrides3\">\n    <template>\n      <style>\n        :host {\n          border: 1px dashed gray;\n          margin: 8px;\n          padding: 8px;\n          display: block;\n        }\n\n        :host > * {\n          --fillin: 16px;\n        }\n      </style>\n      overrides:\n      <x-late id=\"late\"></x-late>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-overrides3'});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-has-def\">\n    <template>\n      <style>\n        :host {\n          border: var(--border, var(--defaultBorder));\n          margin: 8px;\n          padding: 8px;\n          display: block;\n        }\n      </style>\n      Element with default variable.\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-has-def'});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-has-if\">\n    <template>\n      <style>\n        .iffy {\n          border: var(--scope-var);\n        }\n      </style>\n      <template is=\"dom-if\" if=\"{{gogo}}\">\n        <div class=\"iffy\">iffy</div>\n      </template>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-has-if',\n  properties: {\n    gogo: {value: true}\n  }\n});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-button\">\n    <template>\n      <style>\n        :host {\n          display: block;\n          border: var(--button-border);\n        }\n      </style>\n      Button!\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-button',\n  extends: 'button'\n});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-dynamic\">\n    <template>\n      <style>\n        :host {\n          display: block;\n          margin: 20px;\n          border: var(--dynamic);\n        }\n      </style>\n      Dynamic\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-dynamic'\n});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-keyframes\">\n    <template>\n      <style>\n        :host {\n          display: block;\n          position: relative;\n          border: 10px solid blue;\n          left: 0px;\n          /* Prefix required by Safari <= 8 */\n          -webkit-animation-duration: 0.3s;\n          animation-duration: 0.3s;\n          -webkit-animation-fill-mode: forwards;\n          animation-fill-mode: forwards;\n        }\n\n        :host([animated]) {\n          /* Prefix required by Safari <= 8 */\n          -webkit-animation-name: x-keyframes-animation;\n          animation-name: x-keyframes-animation;\n        }\n\n        /* Prefix required by Safari <= 8 */\n        @-webkit-keyframes x-keyframes-animation {\n          0% {\n            left: var(--a);\n          }\n\n          100% {\n            left: var(--b);\n          }\n        }\n        @keyframes x-keyframes-animation {\n          0% {\n            left: var(--a);\n          }\n\n          100% {\n            left: var(--b);\n          }\n        }\n      </style>\n      x-keyframes\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-keyframes',\n  properties: {\n    animated: {\n      type: Boolean,\n      value: false,\n      reflectToAttribute: true\n    }\n  }\n});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-scope\">\n    <template>\n      <style>\n        :host {\n          x--invalid: 15px solid gray;\n          display: block;\n          padding: 8px;\n          --scope-var: 1px solid black;\n          --fallback: 7px solid orange;\n          --default1: var(--undefined, 6px solid yellow);\n          --default2: var(--undefined, var(--fallback));\n          --default3: var(--undefined, rgb(128, 200, 250));\n          --defaultBorder: 22px solid green;\n          --a: 10px;\n          --b: 5px;\n          --primary-color: rgb(128, 128, 128);\n          --late: var(--fillin);\n\n          --button-border: 16px solid tomato;\n          --after: 17px solid brown;\n\n          --end-term: 19px solid blue}\n\n        :host > *{--ws-term: 18px solid orange}\n\n        #me {\n          border: var(--scope-var);\n        }\n\n        x-child-scope {\n          --child-scope-var: 2px solid orange;\n          --grand-child-scope-var: 3px solid steelblue;\n        }\n\n        x-child-scope.special {\n          --child-scope-var: 12px solid orange;\n        }\n\n        #applyDefault1 {\n          border: var(--undefined, 6px solid yellow);\n        }\n\n        #applyDefault2 {\n          border: var(--undefined, var(--fallback));\n        }\n\n        #default1 {\n          border: var(--default1);\n        }\n\n        #default2 {\n          border: var(--default2);\n        }\n\n        #default3 {\n          padding: 8px;\n          background-color: var(--default3);\n        }\n\n        #defaultElement2 {\n          --defaultBorder: 23px solid goldenrod;\n        }\n\n        #overrides1a, #overrides1b, #overrides2 {\n          --rename: 8px solid navy;\n        }\n\n        #overrides1b, #overrides2 {\n          --grand-child-scope-var: 9px solid orange;\n        }\n\n        #overridesConcrete {\n          border: var(--scope-var);\n          border: 4px solid steelblue;\n        }\n\n        #calc {\n          border: solid red;\n          border-width: calc(var(--a) + var(--b));\n        }\n\n        #shadow {\n          box-shadow: 10px 10px 10px var(--primary-color);\n          -webkit-box-shadow: 10px 10px 10px var(--primary-color);\n        }\n\n        x-host-property {\n          border: 10px solid purple;\n        }\n\n        #invalid {\n          border: var(--invalid);\n        }\n\n        #after::after {\n          content: 'after';\n          border: var(--after);\n        }\n\n        #wsTerm {\n          border: var(--ws-term)\n        }\n\n        x-keyframes:nth-of-type(2) {\n          --b: -5px;\n        }\n\n        #endTerm {border: var(--end-term)}\n\n        #parenthesis {\n          background-image: var(--foo-background-image, url(http://placehold.it/400x300));\n        }\n\n        #nestedFallback {\n          border: var(--undefined, var(--undefined, 20px solid blue));\n        }\n\n        #doubleNestedFallback {\n          border: var(--undefined, var(--undefined, var(--undefined, 20px solid red)));\n        }\n\n        #cornerFallback {\n          background-image: var(--undefined, var(--undefined, var(--undefined, url(http://placehold.it/400x300))));\n        }\n      </style>\n      <div id=\"me\">x-scope</div>\n      <x-keyframes id=\"keyframes\"></x-keyframes>\n      <x-keyframes id=\"keyframes2\"></x-keyframes>\n      <x-child-scope id=\"child\"></x-child-scope>\n      <x-child-scope id=\"child2\"></x-child-scope>\n      <x-overrides id=\"overrides1a\"></x-overrides>\n      <x-overrides id=\"overrides1b\"></x-overrides>\n      <x-overrides2 id=\"overrides2\"></x-overrides2>\n      <x-overrides3 id=\"overrides3\"></x-overrides3>\n      <div id=\"overridesConcrete\">override concrete</div>\n      <button id=\"button\" is=\"x-button\"></button>\n      <div id=\"default1\">default</div>\n      <div id=\"default2\">var default</div>\n      <div id=\"default3\">tricky property rgb(...) default</div>\n      <x-has-def id=\"defaultElement1\"></x-has-def>\n      <x-has-def id=\"defaultElement2\"></x-has-def>\n      <div id=\"applyDefault1\">default</div>\n      <div id=\"applyDefault2\">var default</div>\n      <div id=\"calc\">Calc</div>\n      <div id=\"shadow\">Shadow</div>\n      <div id=\"invalid\">invalid</div>\n      <x-host-property id=\"hostProp\"></x-host-property>\n      <x-has-if id=\"iffy\"></x-has-if>\n      <div id=\"after\"></div>\n      <x-dynamic id=\"dynamic\"></x-dynamic>\n      <div id=\"wsTerm\">new line var</div>\n      <div id=\"endTerm\">end var</div>\n      <div id=\"parenthesis\">parenthesis</div>\n      <div id=\"nestedFallback\"></div>\n      <div id=\"doubleNestedFallback\"></div>\n      <div id=\"cornerFallback\"></div>\n      <div id=\"badFallback\"></div>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-scope'\n});\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-inside\">\n    <template>\n      <style>\n        :host {\n          display: inline-block;\n          border: var(--border) solid orange;\n          height: 10px;\n          width: 10px;\n          background-color: tomato;\n        }\n      </style>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-inside'\n});\n</script>\n  </dom-module>\n\n  <dom-module id=\"simple-element\">\n    <template>\n      <style>\n        :host {\n          display: block;\n        }\n\n        x-inside {\n          color: var(--dne);\n          --border: 10px;\n        }\n      </style>\n      <x-inside id=\"inner\"></x-inside>\n    </template>\n    <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'simple-element'\n});\n</script>\n  </dom-module>\n\n\n<dom-module id=\"x-variable-override\">\n  <template>\n    <style>\n      :host {\n        --b: 2px solid black;\n        display: block;\n        border: var(--b);\n      }\n    </style>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-variable-override'\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-variable-consumer\">\n  <template>\n    <style>\n      :host(.foo) {\n        border: var(--consumer);\n      }\n    </style>\n    test\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-variable-consumer'\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-host-variable-consumer\">\n  <template>\n    <style>\n      :host {\n        --consumer: 2px solid orange;\n      }\n\n      .foo {\n        display: block;\n        /* should override */\n        border: 10px solid black;\n      }\n    </style>\n    <x-variable-consumer id=\"consumer\" class=\"foo\"></x-variable-consumer>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-host-variable-consumer'\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-var-produce-via-consume\">\n  <template>\n    <style>\n      :host {\n        display: block;\n        border: 10px solid orange;\n        --foo: var(--bar);\n      }\n    </style>\n        </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-var-produce-via-consume'\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-non-media-matching\">\n  <template>\n    <style>\n      @media (min-width: 100000px) {\n        #inside {\n          --consumer: 10px solid red;\n        }\n      }\n    </style>\n    <x-variable-consumer id=\"inside\" class=\"foo\"></x-variable-consumer>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-non-media-matching'\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-non-media-matching-host\">\n  <template>\n    <style>\n      @media (min-width: 100000px) {\n        :host {\n          --border: 10px solid red;\n        }\n      }\n\n      :host {\n        display: block;\n        border: var(--border);\n      }\n    </style>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-non-media-matching-host'\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-update-styles\">\n  <template>\n    <style>\n      :host {\n        --border: 10px solid red;\n      }\n\n      :host([active]) {\n        --consumer: 6px solid orange;\n      }\n\n      :host {\n        display: block;\n        border: var(--border);\n      }\n    </style>\n    <x-variable-consumer id=\"child\" class=\"foo\"></x-variable-consumer>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-update-styles',\n  properties: {\n    active: {\n      reflectToAttribute: true,\n      observer: '_activeChanged'\n    }\n  },\n\n  _activeChanged: function() {\n    this.updateStyles();\n  }\n});\n</script>\n</dom-module>\n\n<script type=\"module\">\nimport { updateStyles } from '../../lib/mixins/element-mixin.js';\nimport { dom } from '../../lib/legacy/polymer.dom.js';\nsuite('scoped-styling-var', function() {\n\nfunction assertComputed(element, value, pseudo, name) {\n  // force a style-recalc for Safari missing updated CSS Custom Properties\n  // https://bugs.webkit.org/show_bug.cgi?id=170708\n  element.offsetWidth;\n  name = name || 'border-top-width';\n  var computed = element.getComputedStyleValue && !pseudo ?\n    element.getComputedStyleValue(name) :\n    getComputedStyle(element, pseudo)[name];\n  assert.equal(computed, value, 'computed style incorrect');\n}\n\nfunction assertStylePropertyValue(element, name, includeValue) {\n  var value = element.getComputedStyleValue(name);\n  assert.include(value, includeValue);\n}\n\nvar styled = document.querySelector('x-scope');\n\ntest('variables in @keyframes', function(done) {\n  var xKeyframes = styled.$.keyframes;\n  var onAnimationEnd = function() {\n    assertStylePropertyValue(xKeyframes, 'left', '5px');\n\n    xKeyframes.removeEventListener('animationend', onAnimationEnd);\n    xKeyframes.removeEventListener('webkitAnimationEnd', onAnimationEnd);\n    xKeyframes.animated = false;\n    done();\n  };\n\n  assertStylePropertyValue(xKeyframes, '--a', '10px');\n  assertStylePropertyValue(xKeyframes, '--b', '5px');\n\n  xKeyframes.addEventListener('animationend', onAnimationEnd);\n  xKeyframes.addEventListener('webkitAnimationEnd', onAnimationEnd);\n\n  xKeyframes.animated = true;\n});\n\ntest('instances of scoped @keyframes', function(done) {\n  if (navigator.userAgent.match(/Safari/) && ShadyCSS.nativeCss && ShadyCSS.nativeShadow) {\n    // `:nth-of-type` is broken in shadow roots on Safari 10.1\n    // https://bugs.webkit.org/show_bug.cgi?id=166748\n    this.skip();\n  }\n  var xKeyframes = styled.$.keyframes2;\n  var onAnimationEnd = function() {\n    assertStylePropertyValue(xKeyframes, 'left', '5px');\n\n    xKeyframes.removeEventListener('animationend', onAnimationEnd);\n    xKeyframes.removeEventListener('webkitAnimationEnd', onAnimationEnd);\n    xKeyframes.animated = false;\n    done();\n  };\n\n  assertStylePropertyValue(xKeyframes, '--a', '10px');\n  assertStylePropertyValue(xKeyframes, '--b', '-5px');\n\n  xKeyframes.addEventListener('animationend', onAnimationEnd);\n  xKeyframes.addEventListener('webkitAnimationEnd', onAnimationEnd);\n\n  xKeyframes.animated = true;\n});\n\ntest('multiple elements in document', function() {\n  var e$ = document.querySelectorAll('simple-element');\n  assertComputed(e$[0].$.inner, '10px');\n  assertComputed(e$[1].$.inner, '10px');\n});\n\ntest('simple variables calculated correctly between scopes', function() {\n   assertStylePropertyValue(styled, '--scope-var', '1px');\n   //\n   var child = styled.$.child;\n   assertStylePropertyValue(child, '--scope-var', '1px');\n   assertStylePropertyValue(child, '--child-scope-var', '2px');\n   assertStylePropertyValue(child, '--grand-child-scope-var', '3px');\n   //\n   var gc1 = child.$.gc1;\n   assertStylePropertyValue(gc1, '--scope-var', '1px');\n   assertStylePropertyValue(gc1, '--child-scope-var', '2px');\n   assertStylePropertyValue(gc1, '--grand-child-scope-var', '3px');\n   //\n   var gc2 = child.$.gc2;\n   assertStylePropertyValue(gc2, '--scope-var', '1px');\n   assertStylePropertyValue(gc2, '--child-scope-var', '2px');\n   assertStylePropertyValue(gc2, '--grand-child-scope-var', '4px');\n   //\n   var gc3 = child.$.gc3;\n   assertStylePropertyValue(gc3, '--scope-var', '1px');\n   assertStylePropertyValue(gc3, '--child-scope-var', '2px');\n   assertStylePropertyValue(gc3, '--grand-child-scope-var', '3px');\n\n});\n\ntest('invalid variables not parsed', function() {\n  if (!window.ShadyCSS || ShadyCSS.nativeCss) {\n    this.skip();\n  }\n  assert.notOk(ShadyCSS.ScopingShim.getComputedStyleValue(styled, 'x--invalid'));\n  assertComputed(styled.$.invalid, '0px');\n});\n\ntest('simple variables applied correctly between scopes', function() {\n   assertComputed(styled.$.me, '1px');\n   assertComputed(styled.$.child.$.me, '2px');\n   assertComputed(styled.$.child.$.gc1.$.me, '3px');\n   assertComputed(styled.$.child.$.gc1.$.scope, '1px');\n   assertComputed(styled.$.child.$.gc1.$.child, '2px');\n   assertComputed(styled.$.child.$.gc2.$.me, '4px');\n   assertComputed(styled.$.child.$.gc2.$.scope, '1px');\n   assertComputed(styled.$.child.$.gc2.$.child, '2px');\n});\n\ntest('variable can be set to another variable', function() {\n  var gc4 = styled.$.child.$.gc4;\n  assertStylePropertyValue(gc4, '--grand-child-scope-var', '5px');\n  assertComputed(gc4.$.me, '5px');\n});\n\ntest('variable default values can be assigned to other variables', function() {\n  assertStylePropertyValue(styled, '--default1', '6px');\n  assertStylePropertyValue(styled, '--default2', '7px');\n  assertComputed(styled.$.default1, '6px');\n  assertComputed(styled.$.default2, '7px');\n  assertComputed(styled.$.applyDefault1, '6px');\n  assertComputed(styled.$.applyDefault2, '7px');\n});\n\ntest('variable literal defaults can contain one (...)', function() {\n  var b = getComputedStyle(styled.$.default3).backgroundColor;\n  assert.match(b, /rgb\\(128/, 'literal fallback containing (...) not set');\n});\n\ntest('variable values can be used with calc', function() {\n  assertComputed(styled.$.calc, '15px');\n});\n\ntest('variable values can be used with box-shadow', function() {\n  var b = getComputedStyle(styled.$.shadow).boxShadow;\n  assert.match(b, /rgb\\(128/, 'box shadow not set correctly');\n});\n\ntest('host properties can be overridden with outer scope styles', function() {\n  assertComputed(styled.$.hostProp, '10px');\n});\n\ntest('updateStyles changes property values and using style cache', function() {\n  styled.$.child.classList.add('special');\n  var l = document.querySelectorAll('style').length;\n  styled.updateStyles();\n  if (styled.shadowRoot && window.ShadyCSS && !ShadyCSS.nativeCss) {\n    assert.equal(document.querySelectorAll('style').length, l+4);\n  }\n  assertComputed(styled.$.child.$.me, '12px');\n  styled.$.child.classList.remove('special');\n  styled.updateStyles();\n  if (styled.shadowRoot && window.ShadyCSS && !ShadyCSS.nativeCss) {\n    assert.equal(document.querySelectorAll('style').length, l);\n  }\n  assertComputed(styled.$.child.$.me, '2px');\n});\n\ntest('Nested element uses style cache when attached and updateStyles is called', function() {\n  var l = document.querySelectorAll('style').length;\n  var e1 = document.createElement('x-produce-use-property');\n  document.body.appendChild(e1);\n  var e1t = e1.$.hosted.$.hosted;\n  var e2 = document.createElement('x-produce-use-property');\n  document.body.appendChild(e2);\n  var e2t = e2.$.hosted.$.hosted;\n  if (styled.shadowRoot && window.ShadyDOM) {\n    assert.equal(document.querySelectorAll('style').length, l+1);\n  }\n  assertComputed(e1t, '6px');\n  assertComputed(e2t, '6px');\n  e1.updateStyles({'--scope-var': '8px solid purple'});\n  e2.updateStyles({'--scope-var': '8px solid purple'});\n  assertComputed(e1t, '8px');\n  assertComputed(e2t, '8px');\n  if (styled.shadowRoot && window.ShadyDOM) {\n    assert.equal(document.querySelectorAll('style').length, l+1);\n  }\n  e1.updateStyles({'--scope-var': null});\n  e2.updateStyles({'--scope-var': null});\n  assertComputed(e1t, '6px');\n  assertComputed(e2t, '6px');\n  if (styled.shadowRoot && window.ShadyDOM) {\n    assert.equal(document.querySelectorAll('style').length, l+1);\n  }\n});\n\ntest('updateStyles with properties argument changes styles', function() {\n  styled.$.child.updateStyles({'--child-scope-var': '26px solid seagreen'});\n  assertComputed(styled.$.child.$.me, '26px');\n  styled.$.child.updateStyles({'--child-scope-var': null});\n  assertComputed(styled.$.child.$.me, '2px');\n});\n\ntest('updateStyles on when element when not attached', function() {\n  var x = document.createElement('x-update-styles');\n  document.body.appendChild(x);\n  assertComputed(x, '10px');\n  document.body.removeChild(x);\n  x.updateStyles({'--border': '8px solid orange'});\n  document.body.appendChild(x);\n  assertComputed(x, '8px');\n});\n\ntest('updateStyles called in observer when element not attached', function() {\n  var x = document.createElement('x-update-styles');\n  document.body.appendChild(x);\n  assertComputed(x.$.child, '0px');\n  x.active = true;\n  assertComputed(x.$.child, '6px');\n  x.active = false;\n  assertComputed(x.$.child, '0px');\n  document.body.removeChild(x);\n  x.active = true;\n  // disable element's updateStyles to show that observer for `active`'s call to updateStyles\n  // functions correctly.\n  x.updateStyles = function(){};\n  document.body.appendChild(x);\n  assertComputed(x.$.child, '6px');\n});\n\n\n\ntest('styles update based on root customStyle changes', function() {\n  assertComputed(styled.$.dynamic, '0px');\n  updateStyles({'--dynamic': '4px solid navy'});\n  assertComputed(styled.$.dynamic, '4px');\n  updateStyles({'--dynamic': '6px solid gray'});\n  assertComputed(styled.$.dynamic, '6px');\n});\n\ntest('null customStyles unapply', function() {\n  styled.$.dynamic.updateStyles({'--dynamic': '8px solid black'});\n  assertComputed(styled.$.dynamic, '8px');\n  styled.$.dynamic.updateStyles({'--dynamic': null});\n  assertComputed(styled.$.dynamic, '6px');\n  styled.$.dynamic.updateStyles({'--dynamic': '8px solid black'});\n  assertComputed(styled.$.dynamic, '8px');\n  styled.$.dynamic.updateStyles({'--dynamic': null});\n  assertComputed(styled.$.dynamic, '6px');\n});\n\ntest('style properties with dom-if', function() {\n  var e = styled.$.iffy;\n  var c = dom(e.root).querySelector('.iffy');\n  assert.ok(c, 'dom-if did not stamp');\n  assertComputed(c, '1px');\n});\n\ntest('variable precedence and overrides', function() {\n  // renamed property applied\n  var o1a = styled.$.overrides1a;\n  assertStylePropertyValue(o1a, '--rename', '8px');\n  assertStylePropertyValue(o1a, '--grand-child-scope-var', '8px');\n  assertComputed(o1a.$.gc1.$.me, '8px');\n  // :host property overridden by outer scope\n  var o1b = styled.$.overrides1b;\n  assertStylePropertyValue(o1b, '--rename', '8px');\n  assertStylePropertyValue(o1b, '--grand-child-scope-var', '9px');\n  assertComputed(o1b.$.gc1.$.me, '9px');\n  // own scope property overrides outer scope\n  var o2 = styled.$.overrides2;\n  assertStylePropertyValue(o2, '--rename', '8px');\n  assertStylePropertyValue(o2.$.gc1, '--grand-child-scope-var', '8px');\n  assertComputed(o2.$.gc1.$.me, '8px');\n\n  // late bound property does *not* resolve using inherited value\n  var o3 = styled.$.overrides3;\n  if (window.ShadyCSS && !ShadyCSS.nativeCss) {\n    assert.equal(ShadyCSS.ScopingShim.getComputedStyleValue(o3, '--late'), '', 'property should not be late bound');\n  }\n  assertStylePropertyValue(o3.$.late, '--fillin', '16px');\n  assertComputed(o3.$.late, '0px');\n\n});\n\ntest('pseudo-elements can consume custom properties', function() {\n  assertComputed(styled.$.after, '17px', '::after');\n});\n\ntest('elements using only variable defaults are styled properly', function() {\n  assertComputed(styled.$.defaultElement1, '22px');\n  assertComputed(styled.$.defaultElement2, '23px');\n});\n\ntest('vars with trailing new line or } apply', function() {\n  assertComputed(styled.$.wsTerm, '18px');\n  assertComputed(styled.$.endTerm, '19px');\n});\n\ntest('variable with parenthesis', function() {\n  var url = getComputedStyle(styled.$.parenthesis).backgroundImage.replace(/['\"]/g, '');\n  assert.equal('url(http://placehold.it/400x300)', url);\n});\n\ntest('custom style class overrides css variable', function() {\n  var d = document.createElement('x-variable-override');\n  d.classList.add('variable-override');\n  document.body.appendChild(d);\n  assertComputed(d, '10px');\n});\n\ntest('class selector overrides :host(class) property on element with only dynamic styles', function() {\n  var d = document.createElement('x-host-variable-consumer');\n  document.body.appendChild(d);\n  assertComputed(d.$.consumer, '10px');\n});\n\ntest('var values can be overridden by subsequent concrete properties', function() {\n  assertComputed(styled.$.overridesConcrete, '4px');\n});\n\ntest('producing a var that consumes another var preserves static styling', function() {\n  var d = document.createElement('x-var-produce-via-consume');\n  document.body.appendChild(d);\n  assertComputed(d, '10px');\n});\n\ntest('producing a var that consumes results in static and not dynamic stylesheet', function() {\n  if (!window.ShadyCSS || ShadyCSS.nativeCss) {\n    this.skip();\n  }\n  var d = document.createElement('x-var-produce-via-consume');\n  document.body.appendChild(d);\n  var styleRoot = (!window.ShadyCSS || ShadyCSS.nativeShadow) ? d.shadowRoot : document.head;\n  var staticStyle = styleRoot.querySelector('style[scope=x-var-produce-via-consume]');\n  assert.ok(staticStyle);\n  assert.match(staticStyle.textContent, /display/, 'static style does not contain style content');\n  assert.equal(styleRoot.querySelectorAll('style[scope~=x-var-produce-via-consume]').length, 1);\n});\n\ntest('Nested var fallback syntax', function() {\n  assertComputed(styled.$.nestedFallback, '20px');\n  assertComputed(styled.$.doubleNestedFallback, '20px');\n  var url = getComputedStyle(styled.$.cornerFallback).backgroundImage.replace(/['\"]/g, '');\n  assert.equal('url(http://placehold.it/400x300)', url);\n});\n\ntest('invalid @media rules do not match', function() {\n  var e = document.createElement('x-non-media-matching');\n  document.body.appendChild(e);\n  assertComputed(e.$.inside, '0px');\n});\n\ntest('invalid @media rules do not match :host rule', function() {\n  var e = document.createElement('x-non-media-matching-host');\n  document.body.appendChild(e);\n  assertComputed(e, '0px');\n});\n\n});\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/styling-import-host2.css",
    "content": "/*\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n:host {\n  display: block;\n  border: 2px solid black;\n}"
  },
  {
    "path": "test/unit/styling-import-shared-styles.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\nconst $_documentContainer = document.createElement('template');\n$_documentContainer.setAttribute('style', 'display: none;');\n\n$_documentContainer.innerHTML = `<dom-module id=\"shared-styles\">\n  <style>\n    :host {\n      border: 4px solid tomato;\n    }\n  </style>\n\n\n  <template>\n    <style>\n      #three {\n        border: 3px solid tomato;\n      }\n    </style>\n  </template>\n</dom-module>`;\n\ndocument.head.appendChild($_documentContainer.content);\n"
  },
  {
    "path": "test/unit/styling-only-with-template.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n</head>\n\n<body>\n  <custom-style>\n    <style is=\"custom-style\">\n      html {\n        --mixin: {\n          border: 2px solid rgb(255, 0, 0);\n        };\n      }\n    </style>\n  </custom-style>\n\n  <custom-style>\n    <style is=\"custom-style\">\n      #target {\n        @apply --mixin;\n      }\n    </style>\n  </custom-style>\n\n  <div id=\"target\"></div>\n  <dom-if><template></template></dom-if>\n  <dom-repeat><template></template></dom-repeat>\n\n  <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nclass XFoo extends PolymerElement {\n  connectedCallback() {\n    this.spy = sinon.spy(window.ShadyCSS, 'styleElement');\n    super.connectedCallback();\n    this.spy.restore();\n  }\n}\ncustomElements.define('x-foo', XFoo);\n</script>\n\n  <script type=\"module\">\nsuite('styling-only-template', function () {\n\n  function assertComputed(element, value, pseudo) {\n    var computed = getComputedStyle(element, pseudo);\n    assert.equal(computed['border-top-width'], value, 'computed style incorrect');\n  }\n\n  test('elements without templates do not call ShadyCSS', () => {\n    let el = document.createElement('x-foo');\n    document.body.appendChild(el);\n    assert.ok(el.spy);\n    assert.isTrue(el.spy.notCalled);\n  });\n\n  test('dom-repeat and dom-if do not break custom-style', () => {\n    // force custom-style flushing\n    let target = document.querySelector('#target');\n    window.ShadyCSS.styleDocument();\n    assertComputed(target, '2px');\n  });\n});\n</script>\n</body>\n"
  },
  {
    "path": "test/unit/styling-scoped-nopatch.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2019 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script>\n    window.ShadyDOM = {force: true, noPatch: true};\n  </script>\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n</head>\n<body>\n\n<script type=\"module\">\n  import {Polymer, html} from '../../polymer-legacy.js';\n  Polymer({\n    is: 'scope-subtree-legacy',\n    _template: html`\n    <style>\n      #container * {\n        border: 10px solid black;\n      }\n    </style>\n    <div id=\"container\"></div>`\n  });\n</script>\n\n<script type=\"module\">\n  import {PolymerElement, html} from '../../polymer-element.js';\n  class ScopeSubtreeElement extends PolymerElement {\n    static get template() {\n      return html`\n        <style>\n          #container * {\n            border: 10px solid black;\n          }\n        </style>\n        <div id=\"container\"></div>`;\n    }\n  }\n  customElements.define('scope-subtree-element', ScopeSubtreeElement);\n</script>\n\n<script type=\"module\">\n  import {Polymer, html} from '../../polymer-legacy.js';\n  Polymer({\n    is: 'scope-subtree-deep',\n    _template: html`\n      <style>\n        div {\n          border: 20px dotted orange !important;\n        }\n      </style>\n      <div id=\"target\"></div>\n      <div id=\"container\">\n        <scope-subtree-legacy id=\"other\"></scope-subtree-legacy>\n      </div>\n    `,\n  });\n</script>\n\n<test-fixture id=\"legacy\">\n  <template>\n    <scope-subtree-legacy></scope-subtree-legacy>\n  </template>\n</test-fixture>\n\n<test-fixture id=\"element\">\n  <template>\n    <scope-subtree-element></scope-subtree-element>\n  </template>\n</test-fixture>\n\n<test-fixture id=\"deep\">\n  <template>\n    <scope-subtree-deep></scope-subtree-deep>\n  </template>\n</test-fixture>\n\n<script type=\"module\">\n  import { scopeSubtree } from '../../lib/utils/scope-subtree.js';\n\n  function assertComputed(element, value, property, pseudo) {\n    var computed = getComputedStyle(element, pseudo);\n    property = property || 'border-top-width';\n    if (Array.isArray(value)) {\n      assert.oneOf(computed[property], value, 'computed style incorrect for ' + property);\n    } else {\n      assert.equal(computed[property], value, 'computed style incorrect for ' + property);\n    }\n  }\n\n  suite('LegacyElement.scopeSubtree', function() {\n    let el;\n    setup(function() {\n      el = fixture('legacy');\n    });\n    test('elements are scoped', function() {\n      const div = document.createElement('div');\n      const innerDiv = document.createElement('div');\n      div.appendChild(innerDiv);\n      el.$.container.appendChild(div);\n      el.scopeSubtree(el.$.container);\n      assertComputed(div, '10px');\n      assertComputed(innerDiv, '10px');\n    });\n    test('second argument creates a mutation observer', async function() {\n      const mo = el.scopeSubtree(el.$.container, true);\n      assert.instanceOf(mo, MutationObserver);\n      const div = document.createElement('div');\n      const innerDiv = document.createElement('div');\n      div.appendChild(innerDiv);\n      el.$.container.appendChild(div);\n      await new Promise((resolve) => setTimeout(resolve, 0));\n      assertComputed(div, '10px');\n      assertComputed(innerDiv, '10px');\n    });\n  });\n\n  suite('PolymerElement and scopeSubtree util', function() {\n    let el;\n    setup(function() {\n      el = fixture('element');\n    });\n    test('elements are scoped', function() {\n      const div = document.createElement('div');\n      const innerDiv = document.createElement('div');\n      div.appendChild(innerDiv);\n      el.$.container.appendChild(div);\n      scopeSubtree(el.$.container);\n      assertComputed(div, '10px');\n      assertComputed(innerDiv, '10px');\n    });\n    test('second argument creates a mutation observer', async function() {\n      const mo = scopeSubtree(el.$.container, true);\n      assert.instanceOf(mo, MutationObserver);\n      const div = document.createElement('div');\n      const innerDiv = document.createElement('div');\n      div.appendChild(innerDiv);\n      el.$.container.appendChild(div);\n      await new Promise((resolve) => setTimeout(resolve, 0));\n      assertComputed(div, '10px');\n      assertComputed(innerDiv, '10px');\n    });\n\n    suite('scopeSubtree containment', function() {\n      let el;\n      setup(function() {\n        el = fixture('deep');\n      });\n      test('scopeSubtree does not modify other elements\\' trees', function() {\n        const container = el.$.container;\n        const deepContainer = el.$.other.$.container;\n        const deep = document.createElement('div');\n        deepContainer.appendChild(deep);\n        el.$.other.scopeSubtree(deepContainer);\n        el.scopeSubtree(container);\n        assertComputed(deep, '10px');\n      });\n    });\n  });\n</script>\n</body>\n</html>"
  },
  {
    "path": "test/unit/styling-scoped.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\">\n    let define = window.customElements.define;\n    let order = [];\n    window.customElements.define = function(name, fn, options) {\n      order.push(name);\n      return define.call(window.customElements, name, fn, options);\n    };\n    customElements.defineOrder = order;\n  </script>\n  <style>\n    #priority[style-scope=x-styled], #priority.style-scope.x-styled {\n      border: 1px solid black;\n    }\n  </style>\n</head>\n<body>\n\n<dom-module id=\"x-keyframes\">\n  <template>\n    <style>\n      :host {\n        display: block;\n        position: relative;\n        border: 10px solid blue;\n        left: 0px;\n        /* Prefix required by Safari <= 8 */\n        -webkit-animation-duration: 0.3s;\n        animation-duration: 0.3s;\n        -webkit-animation-fill-mode: forwards;\n        animation-fill-mode: forwards;\n      }\n\n      :host([animated]) {\n        /* Prefix required by Safari <= 8 */\n        -webkit-animation-name: x-keyframes-animation;\n        animation-name: x-keyframes-animation;\n      }\n\n      /* Prefix required by Safari <= 8 */\n      @-webkit-keyframes x-keyframes-animation {\n        0% {\n          left: var(--keyframes0, 0px);\n        }\n\n        100% {\n          left: var(--keyframes100, 10px);\n        }\n      }\n      @keyframes x-keyframes-animation {\n        0% {\n          left: var(--keyframes0, 0px);\n        }\n\n        100% {\n          left: var(--keyframes100, 10px);\n        }\n      }\n    </style>\n    x-keyframes\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-keyframes',\n  properties: {\n    animated: {\n      type: Boolean,\n      value: false,\n      reflectToAttribute: true\n    }\n  }\n});\n</script>\n</dom-module>\n<dom-module id=\"x-gchild\">\n  <template>\n    <style>\n    </style>\n    <div id=\"target\">x-gchild</div>\n  </template>\n</dom-module>\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-gchild'\n});\n</script>\n\n<dom-module id=\"x-child\">\n  <template>\n    <div id=\"simple\">simple</div>\n    <div id=\"complex1\" class=\"scoped\">complex1</div>\n    <div id=\"complex2\" selected>complex2</div>\n    <div id=\"media\">media</div>\n    <div id=\"shadow\" class=\"shadowTarget\">shadowTarget</div>\n    <div id=\"deep\" class=\"deepTarget\">deepTarget</div>\n    <x-gchild id=\"gchild1\"></x-gchild>\n    <x-gchild id=\"gchild2\" class=\"wide\"></x-gchild>\n  </template>\n</dom-module>\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-child',\n  hostAttributes: {\n    class: 'nug'\n  }\n});\n</script>\n\n<dom-module id=\"x-child2\">\n  <template>\n    <style>\n      :host(.wide) #target{\n        border: none;\n      }\n    </style>\n    <div id=\"target\">x-child2</div>\n  </template>\n</dom-module>\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-child2'\n});\n</script>\n\n<dom-module id=\"x-scope-class\">\n  <template>\n    <div id=\"scope\">Trivial</div>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-scope-class'\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-class-literal\">\n  <template>\n    <div id=\"scope\" class$=\"a [[b]] c\" class=\"d e\">Trivial</div>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-class-literal'\n});\n</script>\n</dom-module>\n\n\n\n<dom-module id=\"x-styled\">\n  <template>\n    <style>\n      :host {\n        display: block;\n        border: 1px solid orange;\n        --keyframes100: 100px;\n      }\n\n      :host(.wide) {\n        border-width: 2px;\n      }\n\n      :host(.wide)::after {\n        content: '-content-';\n      };\n\n      #keyframes2.special {\n        --keyframes100: 200px;\n      }\n\n      #simple {\n        border: 3px solid orange;\n      }\n\n      .scoped, [selected] {\n        border: 4px solid pink;\n      }\n\n      @media(max-width: 10000px) {\n        .media {\n          border: 5px solid brown;\n        }\n      }\n\n      .container ::slotted(*) {\n        border: 6px solid navy;\n      }\n\n      #priority {\n        border: 9px solid orange;\n      }\n\n      .container1 > ::slotted([slot=content1]) {\n        border: 13px solid navy;\n      }\n\n      .container2 > ::slotted([slot=content2]) {\n        border: 14px solid navy;\n      }\n\n      .computed {\n        border: 15px solid orange;\n      }\n\n      .computeda {\n        border: 20px solid orange;\n      }\n\n      .a.computedb {\n        border: 16px solid gray;\n      }\n\n      #child {\n        border: 16px solid tomato;\n        display: block;\n      }\n\n      svg {\n        margin-top: 20px;\n      }\n\n      #circle {\n        fill: seagreen;\n        stroke-width: 1px;\n        stroke: tomato;\n      }\n    </style>\n    <slot name=\"blank\"></slot>\n    <div id=\"simple\">simple</div>\n    <div id=\"complex1\" class=\"scoped\">complex1</div>\n    <div id=\"complex2\" selected>complex2</div>\n    <div id=\"media\" class=\"media\">media</div>\n    <div class=\"container1\">\n      <slot name=\"content1\"></slot>\n    </div>\n    <div class=\"container2\">\n      <slot name=\"content2\"></slot>\n    </div>\n    <div class=\"container\">\n      <slot></slot>\n    </div>\n    <x-child id=\"child\"></x-child>\n    <div id=\"priority\">priority</div>\n    <x-child2 class=\"wide\" id=\"child2\"></x-child2>\n    <div id=\"computed\" class$=\"{{computeClass(aClass)}}\">Computed</div>\n    <div>\n      <div id=\"computed2\" class$=\"a {{computeClass('computedb')}}\">Computed</div>\n    </div>\n    <div id=\"repeatContainer\">\n      <template id=\"repeat\" is=\"dom-repeat\" items=\"{{items}}\">\n        <a class$=\"{{aaClass}}\">A Computed</a>\n      </template>\n    </div>\n    <svg height=\"25\" width=\"25\">\n      <circle id=\"circle\" cx=\"12\" cy=\"12\" r=\"10\"></circle>\n    </svg>\n    <x-scope-class id=\"scopeClass\"></x-scope-class>\n    <x-keyframes id=\"keyframes\"></x-keyframes>\n    <x-keyframes id=\"keyframes2\"></x-keyframes>\n  </template>\n</dom-module>\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-styled',\n\n  properties: {\n    items: {value: [{}]}\n  },\n\n  computeClass: function(className) {\n    return className;\n  }\n\n});\n</script>\n\n<template id=\"dynamic\">\n  <div class=\"added\">\n    Added\n    <div class=\"sub-added\">\n      Sub-added\n    </div>\n  </div>\n</template>\n\n<dom-module id=\"x-dynamic-scope\">\n  <template>\n    <style>\n      .added {\n        border: 17px solid beige;\n      }\n\n      .sub-added {\n        border: 18px solid #fafafa;\n      }\n    </style>\n    <div id=\"container\"></div>\n  </template>\n</dom-module>\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nvar doc = window.document;\nvar dynamic = doc.querySelector('template#dynamic');\n\nPolymer({\n  is: 'x-dynamic-scope',\n  ready: function() {\n    // simulate 3rd party action by using normal dom to add to element.\n    var dom = document.importNode(dynamic.content, true);\n    this.$.container.appendChild(dom);\n  }\n});\n</script>\n\n<template id=\"dynamic-style-template\">\n  <style>\n    :host {\n      border: 40px solid tomato;\n    }\n  </style>\n  <div>big border</div>\n</template>\n\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nvar doc = window.document;\nvar template = doc.querySelector('template#dynamic-style-template');\n\nPolymer({\n  is: 'x-dynamic-template',\n  registered: function() {\n    this._template = template;\n  }\n});\n</script>\n\n<template id=\"svg\">\n  <svg class=\"svg\" viewBox=\"0 0 24 24\">\n    <circle id=\"circle\" r=\"12\" cx=\"12\" cy=\"12\" />\n  </svg>\n</template>\n\n<dom-module id=\"x-dynamic-svg\">\n  <template>\n    <style>\n      .svg {\n        height: 24px;\n        width: 24px;\n      }\n      #circle {\n        fill: red;\n        fill-opacity: 0.5;\n      }\n    </style>\n    <div id=\"container\"></div>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nvar doc = window.document;\nvar template = doc.querySelector('template#svg');\n\nPolymer({\n  is: 'x-dynamic-svg',\n  ready: function() {\n    this.scopeSubtree(this.$.container, true);\n    var dom = document.importNode(template.content, true);\n    this.$.container.appendChild(dom);\n  }\n});\n</script>\n</dom-module>\n\n<dom-module id=\"x-specificity\">\n  <template>\n    <style>\n      :host {\n        border-top: 1px solid red;\n      }\n      :host(.bar) {\n        border-top: 2px solid red;\n      }\n    </style>\n    <slot></slot>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-specificity'});\n</script>\n</dom-module>\n\n<custom-style>\n  <style>\n    html {\n      --x-specificity-parent : {\n        border: 10px solid blue;\n      };\n      --x-specificity-nested : {\n        border: 3px solid red;\n      };\n    }\n  </style>\n</custom-style>\n\n<dom-module id=\"x-specificity-parent\">\n  <template>\n    <style>\n      ::slotted(:not(template)) {\n        @apply(--x-specificity-parent);\n      }\n    </style>\n    <slot></slot>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-specificity-parent'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-specificity-nested\">\n  <template>\n    <style>\n      :host {\n        @apply(--x-specificity-nested);\n      }\n    </style>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-specificity-nested'});\n</script>\n</dom-module>\n\n<custom-style>\n  <style>\n    html {\n      --x-overriding : {\n        border-top: 1px solid red;\n      }\n    }\n  </style>\n</custom-style>\n\n<dom-module id=\"x-overriding\">\n  <template>\n    <style>\n      .red {\n        @apply(--x-overriding);\n      }\n      .green {\n        @apply(--x-overriding);\n        border-top: 2px solid green;\n      }\n      .red-2 {\n        border-top: 2px solid green;\n        @apply(--x-overriding);\n      }\n      .blue {\n        @apply(--x-overriding);\n        border-top: 3px solid blue;\n      }\n    </style>\n\n    <div class=\"red\">red</div>\n    <div class=\"green\">green</div>\n    <div class=\"red-2\">green-2</div>\n    <div class=\"blue\">blue</div>\n  </template>\n</dom-module>\n\n<script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'x-overriding'\n});\n</script>\n\n<dom-module id=\"x-attr-selector\">\n  <template>\n    <style>\n      #foo1 ~ #bar1 {\n        border: 2px solid red;\n      }\n\n      #foo1 ~ #bar1 ~ #foo2[attr~=foo2] ~ #bar2[attr~=bar2]  {\n        border: 4px solid red;\n      }\n\n      #foo1 ~ #bar1 ~ #foo2[attr~=foo2] ~ #bar2[attr~=bar2] ~ #foo3[attr~=foo3][a~=a] ~ #bar3[attr~=bar3][a~=a] {\n        border: 6px solid red;\n      }\n    </style>\n    <div id=\"foo1\"></div>\n    <div id=\"bar1\">bar1</div>\n    <div id=\"foo2\" attr=\"foo2\"></div>\n    <div id=\"bar2\" attr=\"bar2\">bar2</div>\n    <div id=\"foo3\" attr=\"foo3\" a=\"a\"></div>\n    <div id=\"bar3\" attr=\"bar3\" a=\"a\">bar3</div>\n\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-attr-selector'});\n</script>\n</dom-module>\n\n<dom-module id=\"shared-style\">\n  <template>\n    <style>\n      :host(x-shared1) {\n        display: block;\n        border: 2px solid orange;\n      }\n\n      :host(x-shared2) {\n        display: block;\n        border: 4px solid orange;\n      }\n\n      :host(.x-shared1) {\n        top: 10px;\n      };\n    </style>\n  </template>\n</dom-module>\n\n<dom-module id=\"x-shared1\">\n  <template>\n    <style include=\"shared-style\"></style>\n    x-shared1\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-shared1'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-shared2\">\n  <template>\n    <style include=\"shared-style\"></style>\n    x-shared2\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-shared2'});\n</script>\n</dom-module>\n\n<dom-module id=\"x-slotted\">\n  <template>\n    <style>\n    ::slotted(.auto-content) {\n      border: 2px solid orange;\n    }\n    .bar, ::slotted(.complex-child) {\n      border: 6px solid navy;\n    }\n    #container ::slotted(*) {\n      border: 8px solid green;\n    }\n    </style>\n    <slot></slot>\n    <div id=\"container\">\n      <slot name=\"container\"></slot>\n    </div>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({is: 'x-slotted'});\n</script>\n</dom-module>\n\n<template id=\"xClass\">\n  <style>\n    :host {\n      display: block;\n      border: 1px solid orange;\n    }\n  </style>\n</template>\n<script type=\"module\">\nimport { PolymerElement, html } from '../../polymer-element.js';\ncustomElements.define('x-class-no-is', class extends PolymerElement {\n  static get template() {\n    return window.xClass;\n  }\n});\n\ncustomElements.define('x-template-string', class extends PolymerElement {\n  static get template() {\n    return html`<style>\n      :host {\n        display: block;\n        border: 1px solid orange;\n      }\n    </style>;`;\n  }\n});\n</script>\n\n\n  <div class=\"scoped\">no margin</div>\n\n  <x-styled>\n    <div slot=\"content1\">Foo</div>\n    <div slot=\"content2\">Bar</div>\n    <div class=\"content\">Content</div>\n  </x-styled>\n\n  <x-styled class=\"wide\"></x-styled>\n\n  <x-dynamic-scope></x-dynamic-scope>\n\n  <dom-bind id=\"bind\">\n    <template>\n      <div id=\"dom-bind-static\" class=\"static\">static</div>\n      <span id=\"dom-bind-dynamic\" class$=\"[[dynamic]]\">[[dynamic]]</span>\n    </template>\n  </dom-bind>\n\n  <x-dynamic-svg></x-dynamic-svg>\n  <x-specificity></x-specificity>\n  <x-specificity class=\"bar\"></x-specificity>\n  <x-specificity-parent>\n    <x-specificity-nested></x-specificity-nested>\n  </x-specificity-parent>\n  <x-overriding></x-overriding>\n\n  <dom-module id=\"nested-shared-style\">\n    <template>\n      <style>\n        :host {\n          padding-top: 10px;\n        }\n      </style>\n    </template>\n  </dom-module>\n\n  <dom-module id=\"x-nested-style\">\n    <template>\n      <div id=\"container\">\n        <style include=\"nested-shared-style\">\n          :host {\n            display: block;\n            border: 10px solid black;\n          }\n        </style>\n      </div>\n    </template>\n    <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nclass XNestedStyle extends PolymerElement {\n  static get is() {return 'x-nested-style';}\n}\ncustomElements.define(XNestedStyle.is, XNestedStyle);\n</script>\n  </dom-module>\n\n  <dom-module id=\"x-interleaved-styles\">\n    <template>\n      <style include=\"x-nested-style\"></style>\n      <style>\n        :host {\n          padding-top: 5px;\n        }\n      </style>\n      <style>\n        :host {\n          color: blue;\n        }\n      </style>\n    </template>\n    <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nclass XInterleaved extends PolymerElement {\n  static get is() {return 'x-interleaved-styles';}\n}\ncustomElements.define(XInterleaved.is, XInterleaved);\n</script>\n  </dom-module>\n\n  <dom-module id=\"double-shared-style\">\n    <template>\n      <style>\n        .double-shared-style {\n          color: green;\n        }\n      </style>\n    </template>\n  </dom-module>\n\n  <dom-module id=\"importing-double-shared-style\">\n    <template>\n      <style include=\"double-shared-style\">\n      </style>\n    </template>\n  </dom-module>\n\n  <dom-module id=\"double-shared-styling-element\">\n    <template>\n      <style include=\"importing-double-shared-style double-shared-style\"></style>\n    </template>\n    <script type=\"module\">\nimport { PolymerElement } from '../../polymer-element.js';\nclass DoubleSharedStylingElement extends PolymerElement {\n  static get is() { return 'double-shared-styling-element'; }\n}\ncustomElements.define(DoubleSharedStylingElement.is, DoubleSharedStylingElement);\n</script>\n  </dom-module>\n\n<script type=\"module\">\n  import { PolymerElement, html } from '../../polymer-element.js';\n  class ClassBindingUndefined extends PolymerElement {\n    static get is() { return 'class-binding-undefined'; }\n    static get properties() {\n      return {\n        data: {\n          type: Object\n        }\n      };\n    }\n    static get template() {\n      return html`\n      <style>\n        div {\n          border: 10px solid black;\n        }\n      </style>\n      <div id=\"div\" class$=\"[[data.class]]\">Foo</div>\n      `;\n    }\n  }\n  customElements.define(ClassBindingUndefined.is, ClassBindingUndefined);\n</script>\n\n<script type=\"module\">\nimport { dom } from '../../lib/legacy/polymer.dom.js';\nimport { flush } from '../../lib/utils/flush.js';\nfunction assertComputed(element, value, property, pseudo) {\n  var computed = getComputedStyle(element, pseudo);\n  property = property || 'border-top-width';\n  if (Array.isArray(value)) {\n    assert.oneOf(computed[property], value, 'computed style incorrect for ' + property);\n  } else {\n    assert.equal(computed[property], value, 'computed style incorrect for ' + property);\n  }\n}\n\nvar styled = document.querySelector('x-styled');\nvar styledWide = document.querySelector('x-styled.wide');\nvar unscoped = document.querySelector('.scoped');\n\nsuite('scoped-styling', function() {\n\n  test(':host, :host(...)', function() {\n    assertComputed(styled, '1px');\n    assertComputed(styledWide, '2px');\n    assertComputed(styled, ['', 'none'], 'content', '::after');\n    assertComputed(styledWide, ['\"-content-\"', '-content-'], 'content', '::after');\n  });\n\n  test('scoped selectors, simple and complex', function() {\n    assertComputed(styled.$.simple, '3px');\n    assertComputed(styled.$.complex1, '4px');\n    assertComputed(styled.$.complex2, '4px');\n  });\n\n  test('media query scoped selectors', function() {\n    assertComputed(styled.$.media, '5px');\n  });\n\n  test('upper bound encapsulation', function() {\n    assertComputed(unscoped, '0px');\n  });\n\n  test('lower bound encapsulation', function() {\n    assertComputed(styled.$.child.$.simple, '0px');\n    assertComputed(styled.$.child.$.complex1, '0px');\n    assertComputed(styled.$.child.$.complex2, '0px');\n    assertComputed(styled.$.child.$.media, '0px');\n  });\n\n  test('::slotted selectors', function() {\n    var content = document.querySelector('.content');\n    var content1 = document.querySelector('[slot=content1]');\n    var content2 = document.querySelector('[slot=content2]');\n    assertComputed(content, '6px');\n    assertComputed(content1, '13px');\n    assertComputed(content2, '14px');\n  });\n\n  test('auto ::slotted selector', function() {\n    var x = document.createElement('x-slotted');\n    var d1 = document.createElement('div');\n    d1.classList.add('auto-content');\n    d1.textContent = 'auto-content';\n    document.body.appendChild(x);\n    dom(x).appendChild(d1);\n    flush();\n    assertComputed(d1, '2px');\n  });\n\n  test('::slotted + child in complex selector', function() {\n    var x = document.createElement('x-slotted');\n    var d1 = document.createElement('div');\n    d1.classList.add('complex-child');\n    d1.textContent = 'complex-child';\n    document.body.appendChild(x);\n    dom(x).appendChild(d1);\n    flush();\n    assertComputed(d1, '6px');\n  });\n\n  test('::slotted + named slot', function() {\n    var x = document.createElement('x-slotted');\n    var d1 = document.createElement('div');\n    d1.setAttribute('slot', 'container');\n    d1.textContent = 'named slot child';\n    document.body.appendChild(x);\n    dom(x).appendChild(d1);\n    flush();\n    assertComputed(d1, '8px');\n  });\n\n  test('elements dynamically added/removed from root', function() {\n    var d = document.createElement('div');\n    d.classList.add('scoped');\n    d.textContent = 'Dynamically... Scoped!';\n    dom(styled.root).appendChild(d);\n    flush();\n    assertComputed(d, '4px');\n    dom(document.body).appendChild(d);\n    flush();\n    assert.notInclude(d.getAttribute('style-scoped') || '', styled.is, 'scoping attribute not removed when added to other root');\n    assert.notInclude(d.className, styled.is, 'scoping class not removed when added to other root');\n    assertComputed(d, '0px');\n    dom(styled.root).appendChild(d);\n    flush();\n    assertComputed(d, '4px');\n  });\n\n  test('elements dynamically added/removed from host', function() {\n    var d = document.createElement('div');\n    d.classList.add('scoped');\n    d.slot = 'blank';\n    d.textContent = 'Dynamically... unScoped!';\n    dom(styled).appendChild(d);\n    flush();\n    assertComputed(d, '0px');\n    dom(document.body).appendChild(d);\n    flush();\n    assert.notInclude(d.getAttribute('style-scoped') || '', styled.is, 'scoping attribute not removed when added to other root');\n    assert.notInclude(d.className, styled.is, 'scoping class not removed when added to other root');\n    dom(styled).appendChild(d);\n    flush();\n    assertComputed(d, '0px');\n    dom(styled).removeChild(d);\n    flush();\n    assert.notInclude(d.getAttribute('style-scoped') || '', styled.is, 'scoping attribute not removed when removed from root');\n    assert.notInclude(d.className, styled.is, 'scoping class not removed when removed from root');\n    dom(styled).appendChild(d);\n    flush();\n    assertComputed(d, '0px');\n  });\n\n  test('keyframes change scope', function(done) {\n    if (navigator.userAgent.match('Edge') && (!window.ShadyCSS || window.ShadyCSS.nativeCss)) {\n      // skip test due to missing variable support in keyframes\n      // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/12084341/\n      this.skip();\n    }\n    var xKeyframes = styled.$.keyframes;\n\n    var onAnimationEnd = function() {\n      xKeyframes.removeEventListener('animationend', onAnimationEnd);\n      xKeyframes.removeEventListener('webkitAnimationEnd', onAnimationEnd);\n      assertComputed(xKeyframes, '100px', 'left');\n\n      xKeyframes = styled.$.keyframes2;\n\n      onAnimationEnd = function() {\n        xKeyframes.removeEventListener('animationend', onAnimationEnd);\n        xKeyframes.removeEventListener('webkitAnimationEnd', onAnimationEnd);\n        assertComputed(xKeyframes, '200px', 'left');\n        done();\n      };\n\n      xKeyframes.addEventListener('animationend', onAnimationEnd);\n      xKeyframes.addEventListener('webkitAnimationEnd', onAnimationEnd);\n\n      dom(xKeyframes).classList.add('special');\n      xKeyframes.updateStyles();\n      xKeyframes.animated = true;\n    };\n\n    xKeyframes.addEventListener('animationend', onAnimationEnd);\n    xKeyframes.addEventListener('webkitAnimationEnd', onAnimationEnd);\n\n    xKeyframes.animated = true;\n    assertComputed(xKeyframes, '0px', 'left');\n  });\n\n  test('elements with computed classes', function() {\n    assertComputed(styled.$.computed, '0px');\n    styled.aClass = 'computed';\n    assertComputed(styled.$.computed, '15px');\n    assertComputed(styled.$.computed2, '16px');\n  });\n\n  test('<a> with computed classes dynamically added', function() {\n    assertComputed(styled.$.repeatContainer.firstElementChild, '0px');\n    styled.aaClass = 'computeda';\n    assertComputed(styled.$.repeatContainer.firstElementChild, '20px');\n  });\n\n  test('elements with hostAttributes: class', function() {\n    assertComputed(styled.$.child, '16px');\n  });\n\n  test('element subtree added via dom api', function() {\n    var container = document.querySelector('x-dynamic-scope').$.container;\n    var a = container.querySelector('.added');\n    assertComputed(a, '17px');\n    var b = container.querySelector('.sub-added');\n    assertComputed(b, '18px');\n  });\n\n  test('styles in dynamically selected template', function() {\n    var el = document.createElement('x-dynamic-template');\n    document.body.appendChild(el);\n    if (el.shadowRoot) {\n      // style properly removed\n      assert.notOk(el.querySelector('style'));\n    }\n    assertComputed(el, '40px');\n    document.body.removeChild(el);\n  });\n\n  test('attribute inclusive selector and general sibling selectors', function() {\n    var e = document.createElement('x-attr-selector');\n    document.body.appendChild(e);\n    flush();\n    assertComputed(e.$.bar1, '2px');\n    assertComputed(e.$.bar2, '4px');\n    assertComputed(e.$.bar3, '6px');\n  });\n\n  test('svg classes are dynamically scoped correctly', function() {\n    var container = document.querySelector('x-dynamic-svg').$.container;\n    var svg = container.querySelector('.svg');\n    var computed = getComputedStyle(svg);\n    assert.equal(computed.height, '24px');\n    assert.equal(computed.width, '24px');\n    var circle = container.querySelector('#circle');\n    computed = getComputedStyle(circle);\n    assert.equal(computed['fill-opacity'], '0.5');\n  });\n\n  test(':host with element tag selector', function() {\n    var s1 = document.createElement('x-shared1');\n    document.body.appendChild(s1);\n    assertComputed(s1, '2px');\n    var s2 = document.createElement('x-shared2');\n    document.body.appendChild(s2);\n    assertComputed(s2, '4px');\n  });\n\n  test(':host with superset of element tag selector does not leak', function() {\n    var t = document.createElement('div');\n    t.textContent = 'host leak test';\n    t.classList.add('x-shared1');\n    document.body.appendChild(t);\n    assertComputed(t, 'auto', 'top');\n  });\n\n  test(':host(...) with non-matching type selector does not leak', function() {\n    var t = document.createElement('x-shared1x-shared2');\n    t.textContent = ':host(non-matching-type-selector)';\n    document.body.appendChild(t);\n    assertComputed(t, '0px');\n    t = document.createElement('x-shared2x-shared1');\n    t.textContent = ':host(non-matching-type-selector)';\n    document.body.appendChild(t);\n    assertComputed(t, '0px');\n  });\n\n  test('static is not required for scoping styling', function() {\n    var e = document.createElement('x-class-no-is');\n    document.body.appendChild(e);\n    assertComputed(e, '1px');\n  });\n\n  test('template string has scoped styling', function() {\n    var e = document.createElement('x-template-string');\n    document.body.appendChild(e);\n    assertComputed(e, '1px');\n  });\n\n  test('styles work correctly when not direct children of the template', function() {\n    var e = document.createElement('x-nested-style');\n    document.body.appendChild(e);\n    assertComputed(e, '10px');\n    assertComputed(e, '10px', 'padding-top');\n  });\n\n  test('interleaved styles and styles with includes work as expected', function() {\n    var e = document.createElement('x-interleaved-styles');\n    document.body.appendChild(e);\n    assertComputed(e, '5px', 'padding-top');\n  });\n\n  test('initial literal values in class are preserved when a class$ binding is present', function() {\n    var e = document.createElement('x-class-literal');\n    document.body.appendChild(e);\n    var el = e.$.scope;\n    assert.isTrue(el.classList.contains('a'));\n    assert.isTrue(el.classList.contains('c'));\n    assert.isTrue(el.classList.contains('d'));\n    assert.isTrue(el.classList.contains('e'));\n  });\n\n  test('scoping classes are preserved when a class$ binding resolves to undefined', function() {\n    const e = document.createElement('class-binding-undefined');\n    document.body.appendChild(e);\n    const el = e.$.div;\n    assertComputed(el, '10px');\n  });\n\n});\n\nsuite('double including style sheets', function() {\n  let el;\n\n  setup(function() {\n    el = document.createElement('double-shared-styling-element');\n    document.body.appendChild(el);\n  });\n\n  teardown(function() {\n    document.body.removeChild(el);\n  });\n\n  test('only includes style modules once', function() {\n    const style = el.shadowRoot.querySelector('style');\n\n    // We cant use the regular \"does a sub-node have the correct style\",\n    // because we actually need to assert on the actual style content.\n    // In native shadow dom, the style element resides in the shadowRoot,\n    // but in shadyDOM it has moved to the head and the selector has been altered.\n    if (style) {\n      assert.equal(style.textContent, `.double-shared-style {\n  color: green;\n}`, 'There should be only one class selector in this style element');\n    } else {\n      assert.equal(document.head.querySelector('[scope=\"double-shared-styling-element\"]').textContent,\n`.double-shared-style.double-shared-styling-element {\n  color: green;\n}`);\n    }\n  });\n});\n\nif (window.ShadyDOM) {\n\n  suite('scoped-styling-shady-only', function() {\n\n    test('element style precedence below document styles', function() {\n      assertComputed(styledWide.$.priority, '1px');\n    });\n\n    test('styles shimmed in registration order', function() {\n      var regList = customElements.defineOrder;\n      function regIndex(styleScope) {\n        for (var i=0, r; (r=regList[i]); i++) {\n          if (styleScope.match(new RegExp(r + '\\\\-?\\\\d*$'))) {\n            return i;\n          }\n        }\n      }\n      var s$ = document.head.querySelectorAll('style[scope]');\n      for (var i=0, scope, prevScope, n=0, o=0; i<s$.length; i++) {\n        scope = s$[i].getAttribute('scope');\n        n = regIndex(scope);\n        assert.isTrue(n >= o, 'style not in registration order, expected `' +\n          scope + '` to be before `' + prevScope + '`');\n        o = n;\n        prevScope = scope;\n      }\n    });\n\n    test('svg elements properly scoped', function() {\n      assert.include(styled.$.circle.getAttribute('class'), 'x-styled');\n      assert.include(styled.$.circle.getAttribute('class'), 'style-scope');\n      assert.notInclude(styled.$.circle.getAttribute('class'), 'null');\n      assertComputed(styled.$.circle, '1px', 'strokeWidth');\n    });\n\n    test('dom-bind content is unscoped', function() {\n      var e = document.querySelector('#bind');\n      e.dynamic = 'dynamic';\n      var staticClassEl = document.querySelector('#dom-bind-static');\n      assert.equal(staticClassEl.className, 'static');\n      var dynamicClassEl = document.querySelector('#dom-bind-dynamic');\n      assert.equal(dynamicClassEl.className, 'dynamic');\n    });\n\n    test('serializeValueToAttribute for class', function() {\n      var s = styled.$.scopeClass;\n      var scope = s.$.scope;\n      assert.isTrue(s.classList.contains('style-scope'));\n      assert.isTrue(s.classList.contains('x-styled'));\n      s.serializeValueToAttribute('foo', 'class');\n      assert.isTrue(s.classList.contains('foo'));\n      assert.isTrue(s.classList.contains('style-scope'));\n      assert.isTrue(s.classList.contains('x-styled'));\n      //\n      assert.isTrue(scope.classList.contains('style-scope'));\n      assert.isTrue(scope.classList.contains('x-scope-class'));\n      s.serializeValueToAttribute('foo', 'class', scope);\n      assert.isTrue(scope.classList.contains('foo'));\n      assert.isTrue(scope.classList.contains('style-scope'));\n      assert.isTrue(scope.classList.contains('x-scope-class'));\n    });\n\n    test('specificity of :host selector with class', function() {\n      assertComputed(document.querySelector('x-specificity'), '1px');\n      assertComputed(document.querySelector('x-specificity.bar'), '2px');\n    });\n\n    test('specificity of ::slotted :not(template) selector', function() {\n      assertComputed(document.querySelector('x-specificity-nested'), '10px');\n    });\n\n    test('overwriting mixin properties', function() {\n      var el = document.querySelector('x-overriding');\n      assertComputed(el.shadowRoot.querySelector('.red'), '1px');\n      assertComputed(el.shadowRoot.querySelector('.green'), '2px');\n      assertComputed(el.shadowRoot.querySelector('.red-2'), '1px');\n      assertComputed(el.shadowRoot.querySelector('.blue'), '3px');\n    });\n\n    test('dynamically scope element class on add/remove', function () {\n      var el = document.createElement('x-scope-class');\n      document.body.appendChild(el);\n      flush();\n      var div = document.createElement('div');\n      el.shadowRoot.appendChild(div);\n      flush();\n      assert.isTrue(div.classList.contains('style-scope'));\n      assert.isTrue(div.classList.contains('x-scope-class'));\n      el.shadowRoot.appendChild(div);\n      flush();\n      document.body.removeChild(el);\n    });\n\n    test('dynamically scope element class on setAttribute class', function () {\n      var el = document.createElement('x-scope-class');\n      document.body.appendChild(el);\n      flush();\n      var div = document.createElement('div');\n      el.shadowRoot.appendChild(div);\n      flush();\n      div.setAttribute('class', 'foo');\n      assert.isTrue(div.classList.contains('foo'));\n      assert.isTrue(div.classList.contains('style-scope'));\n      assert.isTrue(div.classList.contains('x-scope-class'));\n      el.shadowRoot.appendChild(div);\n      flush();\n      document.body.removeChild(el);\n    });\n\n    test('dynamically scope element class on set className', function () {\n      var el = document.createElement('x-scope-class');\n      document.body.appendChild(el);\n      flush();\n      var div = document.createElement('div');\n      el.shadowRoot.appendChild(div);\n      flush();\n      div.className = 'foo';\n      assert.isTrue(div.classList.contains('foo'), 'foo should be in classList');\n      assert.isTrue(div.classList.contains('style-scope'), 'style-scope should be in classList');\n      assert.isTrue(div.classList.contains('x-scope-class'), 'x-scope-class should be in classList');\n      el.shadowRoot.appendChild(div);\n      flush();\n      document.body.removeChild(el);\n    });\n\n  });\n\n}\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/sub/resolveurl-elements.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport { html } from '../../../lib/utils/html-tag.js';\n\nimport { PolymerElement } from '../../../polymer-element.js';\nimport { DomModule } from '../../../lib/elements/dom-module.js';\nimport { Polymer } from '../../../lib/legacy/polymer-fn.js';\nimport { pathFromUrl } from '../../../lib/utils/resolve-url.js';\n\nconst $_documentContainer = document.createElement('template');\n$_documentContainer.setAttribute('style', 'display: none;');\nconst baseAssetPath = pathFromUrl(import.meta.url);\n$_documentContainer.innerHTML = `<dom-module id=\"p-r-ap\" assetpath=\"${baseAssetPath}../../assets/\"></dom-module>`;\ndocument.head.appendChild($_documentContainer.content);\n\nclass PR extends PolymerElement {\n  static get template() {\n    return html`\n    <style>\n      .logo {\n        background-image: url(foo.z);\n        clip-path: url('#bar');\n        mask-image: url('/zot');\n      }\n    </style>\n    <div id=\"div\" class=\"logo\" style\\$=\"background-image: url('[[importPath]]foo.z');\"></div>\n    <img id=\"img\" src$=\"[[importPath]]foo.z\">\n    <a id=\"a\" href$=\"[[importPath]]foo.z\">Foo</a>\n    <zonk id=\"import\" url$=\"[[importPath]]foo.z\"></zonk>\n    <zonk id=\"resolveUrl\" url$=\"[[resolveUrl('foo.z')]]\"></zonk>\n    <zonk id=\"resolveUrlHash\" url$=\"[[resolveUrl('#foo')]]\"></zonk>\n    <zonk id=\"resolveUrlAbs\" url$=\"[[resolveUrl('/foo')]]\"></zonk>\n    <zonk id=\"root\" url$=\"[[rootPath]]foo.z\"></zonk>\n    <a id=\"rel\" href$=\"[[importPath]]../foo.z?123\">Foo</a>\n    <a id=\"action\" action=\"foo.z\">Foo</a>\n    <form id=\"formAction\" action$=\"[[importPath]]foo.z\"></form>\n    <a id=\"hash\" href=\"#foo.z\">Foo</a>\n    <a id=\"absolute\" href=\"/foo.z\">Foo</a>\n    <a id=\"protocol\" href=\"data:foo.z\">Foo</a>\n`;\n  }\n  static get is() { return 'p-r'; }\n  static get importMeta() {\n    return import.meta;\n  }\n}\ncustomElements.define(PR.is, PR);\n\nconst PRHybrid = Polymer({\n  is: 'p-r-hybrid',\n  _template: PR.template,\n  importMeta: import.meta\n});\n\nclass PRAp extends PolymerElement {\n  static get is() { return 'p-r-ap'; }\n}\ncustomElements.define(PRAp.is, PRAp);\n"
  },
  {
    "path": "test/unit/sub/style-import.js",
    "content": "import { pathFromUrl } from '../../../lib/utils/resolve-url.js';\n\nconst $_documentContainer = document.createElement('template');\n$_documentContainer.setAttribute('style', 'display: none;');\nconst baseAssetPath = pathFromUrl(import.meta.url);\n$_documentContainer.innerHTML = `<dom-module id=\"style-import\" assetpath=\"${baseAssetPath}\">\n  <template>\n    <style>\n      .foo {\n        height: 2px;\n        border: 1px solid orange;\n        background: url(google.png);\n      }\n    </style>\n  </template>\n</dom-module><dom-module id=\"style-import2\" assetpath=\"${baseAssetPath}\">\n  <template>\n    <style>\n      .foo {\n        width: 4px;\n      }\n    </style>\n  </template>\n</dom-module>`;\n\ndocument.head.appendChild($_documentContainer.content);\n"
  },
  {
    "path": "test/unit/sub/x-sub.html",
    "content": "<dom-module id=\"x-sub\">\n  <template>\n    <div id=\"test\">test</div>\n  </template>\n  <script type=\"module\">\nimport { PolymerElement } from '../../../polymer-element.js';\nclass XSub extends PolymerElement {\n  static get is() { return 'x-sub' }\n}\ncustomElements.define(XSub.is, XSub);\n</script>\n</dom-module>"
  },
  {
    "path": "test/unit/sub/x-test.html",
    "content": "<dom-module id=\"x-test\">\n  <template>\n    <x-sub id=\"sub\">sub</x-sub>\n  </template>\n  <script type=\"module\">\nimport { Polymer } from '../../../lib/legacy/polymer-fn.js';\nPolymer({\n  is: 'x-test'\n})\n</script>\n</dom-module>\n"
  },
  {
    "path": "test/unit/template-stamp.html",
    "content": "<!DOCTYPE html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"UTF-8\">\n\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n\n  <script type=\"module\" src=\"../../lib/mixins/template-stamp.js\"></script>\n</head>\n<body>\n\n  <template id=\"test-template\" strip-whitespace>\n    <div id=\"a\">a</div>\n    <div id=\"eventHandler\" on-click=\"handleClick\"></div>\n    <div id=\"b\">b</div>\n    <template id=\"nestedTemplate\">\n      <div on-click=\"handleClick\"></div>\n    </template>\n    <template id=\"preservedTemplate\" preserve-content>\n      <div on-click=\"shouldNotBeRemoved\"></div>\n    </template>\n  </template>\n\n  <script type=\"module\">\nimport { TemplateStamp } from '../../lib/mixins/template-stamp.js';\nclass TemplateStamper extends TemplateStamp(HTMLElement) {\n  connectedCallback() {\n    this.handleClick = sinon.spy(event => {\n      this.handleClickTarget = event.target;\n    });\n    let template = document.getElementById('test-template');\n    this.dom = this._stampTemplate(template);\n    this.attachShadow({mode:'open'}).appendChild(this.dom);\n  }\n}\ncustomElements.define('template-stamper', TemplateStamper);\n</script>\n\n  <script type=\"module\">\nimport '../../lib/mixins/template-stamp.js';\n\nsuite('template-stamp', () => {\n\n  test('id map', () => {\n    let el = document.createElement('template-stamper');\n    document.body.appendChild(el);\n    assert.equal(el.dom.$.a.textContent, 'a');\n    assert.equal(el.dom.$.b.textContent, 'b');\n    document.body.removeChild(el);\n  });\n\n  test('declarative events', () => {\n    let el = document.createElement('template-stamper');\n    document.body.appendChild(el);\n    el.dom.$.eventHandler.click();\n    assert.equal(el.handleClick.callCount, 1);\n    assert.equal(el.handleClick.firstCall.args[0].type, 'click');\n    assert.equal(el.handleClickTarget, el.dom.$.eventHandler);\n    document.body.removeChild(el);\n  });\n\n  test('cached template content', () => {\n    let el = document.createElement('template-stamper');\n    document.body.appendChild(el);\n    let content = el.constructor._contentForTemplate(el.dom.$.nestedTemplate);\n    assert.isTrue(content instanceof DocumentFragment);\n    assert.notOk(content.ownerDocument.defaultView);\n    assert.equal(content.firstChild.getAttribute('on-click'), null);\n    document.body.removeChild(el);\n  });\n\n  test('preserved template content', () => {\n    let el = document.createElement('template-stamper');\n    document.body.appendChild(el);\n    let content = el.dom.$.preservedTemplate.content;\n    assert.isTrue(content instanceof DocumentFragment);\n    assert.equal(content.childNodes[1].getAttribute('on-click'), 'shouldNotBeRemoved');\n    document.body.removeChild(el);\n  });\n\n});\n\n// Note template parsing API is tested in `property-effects-template.html`,\n// combined with adding property effects\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/template-whitespace.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n</head>\n<body>\n\n<dom-module id=\"has-whitespace\">\n\n  <template> <div>A</div> <div>B</div> </template>\n\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'has-whitespace'\n});\n</script>\n\n</dom-module>\n\n\n\n<dom-module id=\"no-whitespace\">\n\n  <template strip-whitespace>\n    <div>A</div>\n    <div>A</div>\n    <div>B</div>\n  </template>\n\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'no-whitespace'\n});\n</script>\n\n</dom-module>\n\n\n\n<dom-module id=\"no-whitespace-style\">\n\n  <template strip-whitespace>\n    <style>\n      :host {\n        display: block;\n      }\n    </style>\n    <div>A</div>\n    <div>B</div>\n  </template>\n\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'no-whitespace-style'\n});\n</script>\n\n</dom-module>\n\n<dom-module id=\"no-whitespace-nested\">\n\n  <template strip-whitespace>\n    <div>\n      <div>A</div>\n    </div>\n    <div>\n      <div>B</div>\n    </div>\n  </template>\n\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  is: 'no-whitespace-nested'\n});\n</script>\n\n</dom-module>\n\n<dom-module id=\"no-whitespace-binding\">\n\n  <template strip-whitespace>\n\n    <div id=\"text\">{{text}}</div>\n    <div id=\"attr\" attr$=\"{{attr}}\">\n      <div>A</div>\n    </div>\n    <div>\n      <div>B</div>\n    </div>\n    <div id=\"compound\"> {{a}} {{b}} </div>\n  </template>\n\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  properties: {\n    text: {value: 'text'},\n    attr: {value: 'attr'},\n    a: {value: 'a'},\n    b: {value: 'b'}\n  },\n  is: 'no-whitespace-binding'\n});\n</script>\n\n</dom-module>\n\n<dom-module id=\"no-whitespace-repeat\">\n\n  <template strip-whitespace>\n\n    <template is=\"dom-repeat\" items=\"[[items]]\">\n      <div></div>\n    </template>\n\n  </template>\n\n  <script type=\"module\">\nimport { Polymer } from '../../polymer-legacy.js';\nPolymer({\n  properties: {\n    items: {\n      value: function() { return [1, 2, 3];}\n    }\n  },\n  is: 'no-whitespace-repeat'\n});\n</script>\n\n</dom-module>\n\n\n\n<script type=\"module\">\nimport { flush } from '../../lib/utils/flush.js';\n\nsuite('polymer: template whitespace', function() {\n\n  test('template stamped with whitespace preserved', function() {\n    var el = document.createElement('has-whitespace');\n    document.body.appendChild(el);\n    assert.equal(el.root.childNodes.length, 5);\n    assert.equal(el.root.childNodes[0].nodeType, Node.TEXT_NODE);\n  });\n\n  test('template stamped without whitespace when strip-template is used', function() {\n    var el = document.createElement('no-whitespace');\n    document.body.appendChild(el);\n    assert.equal(el.root.childNodes.length, 3);\n    assert.equal(el.root.childNodes.length, el.root.children.length);\n  });\n\n  test('template including style stamped without whitespace when strip-template is used', function() {\n    var el = document.createElement('no-whitespace-style');\n    document.body.appendChild(el);\n    var c$ = Array.from(el.root.childNodes).filter(function(e) {\n      return e.localName != 'style';});\n    assert.equal(c$.length, 2);\n  });\n\n  test('template with nested content stamped without whitespace when strip-template is used', function() {\n    var el = document.createElement('no-whitespace-nested');\n    document.body.appendChild(el);\n    assert.equal(el.root.childNodes.length, 2);\n    assert.equal(el.root.childNodes.length, el.root.children.length);\n    assert.equal(el.root.childNodes[0].childNodes.length, el.root.childNodes[0].children.length);\n    assert.equal(el.root.childNodes[1].childNodes.length, el.root.childNodes[1].children.length);\n  });\n\n  test('template with nested content stamped without whitespace when strip-template is used', function() {\n    var el = document.createElement('no-whitespace-binding');\n    document.body.appendChild(el);\n    assert.equal(el.$.text.textContent, 'text');\n    assert.equal(el.$.attr.getAttribute('attr'), 'attr');\n    assert.equal(el.$.compound.textContent, ' a b ');\n  });\n\n  test('template with dom-repeat stamped without whitespace when strip-template is used', function() {\n    var el = document.createElement('no-whitespace-repeat');\n    document.body.appendChild(el);\n    flush();\n    assert.equal(el.shadowRoot.childNodes.length, 4);\n  });\n\n});\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/templatize-elements.js",
    "content": "/**\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nimport { Polymer } from '../../lib/legacy/polymer-fn.js';\n\nimport { templatize } from '../../lib/utils/templatize.js';\nimport { Templatizer } from '../../lib/legacy/templatizer-behavior.js';\nimport { html } from '../../lib/utils/html-tag.js';\n\nPolymer({\n  is: 'x-child',\n  properties: {\n    outerProp: {\n      notify: true\n    },\n    outerObj: {\n      notify: true\n    },\n    outerObjProp: {\n      notify: true\n    },\n    prop: {\n      notify: true\n    },\n    obj: {\n      notify: true\n    },\n    objProp: {\n      notify: true\n    },\n    outerInnerConflict: {\n      notify: true\n    }\n  },\n  observers: [\n    'objChanged(obj.*)',\n    'outerObjChanged(outerObj.*)'\n  ],\n  objChanged: function() {},\n  outerObjChanged: function() {}\n});\n\nPolymer({\n  is: 'x-templatize',\n  properties: {\n    obj: {\n      notify: true\n    },\n    prop: {\n      notify: true,\n      observer: 'propChanged'\n    }\n  },\n  observers: [\n    'objChanged(obj.*)'\n  ],\n  propChanged: function(value) {\n    if (this.instance) {\n      this.instance.prop = value;\n    }\n  },\n  objChanged: function(info) {\n    if (this.instance) {\n      this.instance.notifyPath(info.path, info.value);\n    }\n  },\n  go: function(withProps) {\n    var template = this.querySelector('template');\n    var ctor = templatize(template, this, {\n      parentModel: true,\n      instanceProps: {\n        obj: true,\n        prop: true,\n        outerInnerConflict: true\n      },\n      forwardHostProp: function(prop, value) {\n        if (this.instance) {\n          this.instance.forwardHostProp(prop, value);\n        }\n      },\n      notifyInstanceProp: function(inst, prop, value) {\n        // notify path on host (set won't work since it dirty checks)\n        this.notifyPath(prop, value);\n      }\n    });\n    this.instance = new ctor(\n      withProps ? {\n        obj: this.obj,\n        prop: this.prop,\n        outerInnerConflict: {\n          prop: 'bar'\n        }\n      } : null);\n    this.parentNode.appendChild(this.instance.root);\n  }\n});\n\nPolymer({\n  is: 'x-templatize-behavior',\n  properties: {\n    obj: {\n      notify: true\n    },\n    prop: {\n      notify: true,\n      observer: 'propChanged'\n    }\n  },\n  observers: [\n    'objChanged(obj.*)'\n  ],\n  behaviors: [Templatizer],\n  propChanged: function(value) {\n    if (this.instance) {\n      this.instance.prop = value;\n    }\n  },\n  objChanged: function(info) {\n    if (this.instance) {\n      this.instance.notifyPath(info.path, info.value);\n    }\n  },\n  _parentModel: true,\n  _instanceProps: {\n    obj: true,\n    prop: true,\n    outerInnerConflict: true\n  },\n  _forwardHostPropV2: function(prop, value) {\n    if (this.instance) {\n      this.instance.forwardHostProp(prop, value);\n    }\n  },\n  _notifyInstancePropV2: function(inst, prop, value) {\n    // notify path on host (set won't work since it dirty checks)\n    this.notifyPath(prop, value);\n  },\n  go: function(withProps) {\n    var template = this.querySelector('template');\n    this.templatize(template);\n    this.instance = this.stamp(\n      withProps ? {\n        obj: this.obj,\n        prop: this.prop,\n        outerInnerConflict: {\n          prop: 'bar'\n        }\n      } : null);\n    this.parentNode.appendChild(this.instance.root);\n  }\n});\n\nPolymer({\n  _template: html`\n    <x-templatize obj=\"{{objA}}\" prop=\"{{propA}}\" id=\"templatizeA\">\n      <template>\n        <x-child on-tap=\"handleTap\" id=\"childA\" outer-prop=\"{{outerProp}}\" outer-obj=\"{{outerObj}}\" outer-obj-prop=\"{{outerObj.prop}}\" prop=\"{{prop}}\" obj=\"{{obj}}\" obj-prop=\"{{obj.prop}}\" conflict=\"{{outerInnerConflict.prop}}\" computed-from-literal=\"{{computeFromLiteral(33, prop)}}\"></x-child>\n      </template>\n    </x-templatize>\n\n    <x-templatize prop=\"prop-a\" name=\"templatizeB\">\n      <template>\n        <x-child id=\"childB\" computed-from-literal=\"{{computeFromLiteral(33, prop)}}\"></x-child>\n      </template>\n    </x-templatize>\n\n    <x-templatize-behavior obj=\"{{objA}}\" prop=\"{{propA}}\" id=\"templatizeC\">\n      <template>\n        <x-child on-tap=\"handleTap\" id=\"childC\" outer-prop=\"{{outerProp}}\" outer-obj=\"{{outerObj}}\" outer-obj-prop=\"{{outerObj.prop}}\" prop=\"{{prop}}\" obj=\"{{obj}}\" obj-prop=\"{{obj.prop}}\" conflict=\"{{outerInnerConflict.prop}}\" computed-from-literal=\"{{computeFromLiteral(33, prop)}}\"></x-child>\n      </template>\n\n\n  </x-templatize-behavior>\n`,\n\n  is: 'x-host',\n\n  properties: {\n    outerProp: {\n      value: 'outerProp'\n    },\n    outerObj: {\n      value: function() {\n        return { prop: 'outerObj.prop' };\n      }\n    },\n    propA: {\n      value: 'prop-a'\n    },\n    objA: {\n      value: function() {\n        return { prop: 'objA.prop' };\n      }\n    },\n    propB: {\n      value: 'prop-b'\n    },\n    objB: {\n      value: function() {\n        return { prop: 'objB.prop' };\n      }\n    },\n    outerInnerConflict: {\n      value: function() {\n        return { prop: 'conflict' };\n      }\n    }\n  },\n\n  observers: [\n    'outerObjChanged(outerObj.*)',\n    'objAChanged(objA.*)',\n    'objBChanged(objB.*)'\n  ],\n\n  created: function() {\n    this.handleTap = sinon.spy();\n  },\n\n  outerObjChanged: function() {},\n  objAChanged: function() {},\n  objBChanged: function() {},\n  computeFromLiteral: function(literal, prop) { return literal + '-' + prop; }\n});\n"
  },
  {
    "path": "test/unit/templatize.html",
    "content": "<!doctype html>\n<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n-->\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <script src=\"../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js\"></script>\n  <script src=\"wct-browser-config.js\"></script>\n  <script src=\"../../node_modules/wct-browser-legacy/browser.js\"></script>\n  <script type=\"module\" src=\"../../polymer-legacy.js\"></script>\n  <script type=\"module\" src=\"./templatize-elements.js\"></script>\n</head>\n<body>\n\n<template id=\"standalone\"><div prop=\"[[prop]]\">[[text]]</div></template>\n\n<script type=\"module\">\nimport './templatize-elements.js';\nimport { templatize } from '../../lib/utils/templatize.js';\n\nsuite('templatize basic', function() {\n\n  let host;\n  let childA;\n\n  setup(function() {\n    host = document.createElement('x-host');\n    document.body.appendChild(host);\n    host.$.templatizeA.go(true);\n    childA = host.shadowRoot.querySelector('#childA');\n    assert.ok(childA);\n  });\n\n  teardown(function() {\n    document.body.removeChild(host);\n  });\n\n  test('stamped with initial data', function() {\n    assert.equal(childA.outerProp, 'outerProp');\n    assert.equal(childA.outerObj, host.outerObj);\n    assert.equal(childA.outerObjProp, 'outerObj.prop');\n    assert.equal(childA.prop, 'prop-a');\n    assert.equal(childA.obj, host.objA);\n    assert.equal(childA.objProp, 'objA.prop');\n  });\n\n  test('host properties propagated in', function() {\n    host.outerProp = 'outerProp++';\n    assert.equal(childA.outerProp, 'outerProp++');\n    host.outerObj = { prop: 'outerObj++.prop' };\n    assert.equal(childA.outerObj, host.outerObj);\n    assert.equal(childA.outerObjProp, 'outerObj++.prop');\n  });\n\n  test('host paths propagated in', function() {\n    sinon.spy(childA, 'outerObjChanged');\n    host.set('outerObj.prop', 'outerObj.prop++');\n    assert.equal(childA.outerObjProp, 'outerObj.prop++');\n    assert.isTrue(childA.outerObjChanged.calledOnce);\n    assert.equal(childA.outerObjChanged.getCall(0).args[0].path, 'outerObj.prop');\n    assert.equal(childA.outerObjChanged.getCall(0).args[0].value, 'outerObj.prop++');\n  });\n\n  test('host properties propagated out', function() {\n    childA.outerProp = 'outerProp++';\n    assert.equal(host.outerProp, 'outerProp++');\n    childA.outerObj = { prop: 'outerObj++.prop' };\n    assert.equal(host.outerObj.prop, 'outerObj++.prop');\n  });\n\n  test('host paths propagated out', function() {\n    sinon.spy(host, 'outerObjChanged');\n    childA.set('outerObj.prop', 'outerObj.prop++');\n    assert.equal(host.outerObj.prop, 'outerObj.prop++');\n    assert.isTrue(host.outerObjChanged.calledOnce);\n    assert.equal(host.outerObjChanged.getCall(0).args[0].path, 'outerObj.prop');\n    assert.equal(host.outerObjChanged.getCall(0).args[0].value, 'outerObj.prop++');\n  });\n\n  test('instance properties propagated in', function() {\n    host.propA = 'prop-a++';\n    assert.equal(childA.prop, 'prop-a++');\n    host.objA = { prop: 'objA++.prop' };\n    assert.equal(childA.obj, host.objA);\n    assert.equal(childA.objProp, 'objA++.prop');\n  });\n\n  test('instance paths propagated in', function() {\n    sinon.spy(childA, 'objChanged');\n    host.set('objA.prop', 'objA.prop++');\n    assert.equal(childA.obj.prop, 'objA.prop++');\n    assert.isTrue(childA.objChanged.calledOnce);\n    assert.equal(childA.objChanged.getCall(0).args[0].path, 'obj.prop');\n    assert.equal(childA.objChanged.getCall(0).args[0].value, 'objA.prop++');\n  });\n\n  test('instance properties propagated out', function() {\n    childA.prop = 'prop-a++';\n    assert.equal(host.propA, 'prop-a++');\n    childA.obj = { prop: 'objA++.prop' };\n    assert.equal(host.objA.prop, 'objA++.prop');\n  });\n\n  test('instance paths propagated out', function() {\n    sinon.spy(host, 'objAChanged');\n    childA.set('obj.prop', 'objA.prop++');\n    assert.equal(host.objA.prop, 'objA.prop++');\n    assert.isTrue(host.objAChanged.calledOnce);\n    assert.equal(host.objAChanged.getCall(0).args[0].path, 'objA.prop');\n    assert.equal(host.objAChanged.getCall(0).args[0].value, 'objA.prop++');\n  });\n\n  test('outer & inner props conflict', function() {\n    assert.equal(childA.conflict, 'bar');\n    host.set('outerInnerConflict.prop', 'foo');\n    assert.equal(childA.conflict, 'bar');\n  });\n\n  test('inline computed functions', function() {\n    assert.equal(childA.computedFromLiteral, '33-prop-a');\n  });\n\n  test('ensure literals are not forwarded to templates', function() {\n    assert.notOk(host._hasAccessor(33));\n    assert.notOk(Object.getOwnPropertyDescriptor(Object.getPrototypeOf(host), 33));\n  });\n\n  test('ensure undefined is not set on templatizee', function() {\n    assert.equal(host.$.templatizeA[undefined], undefined);\n  });\n\n  test('able to add gesture listeners', function() {\n    assert.equal(host.handleTap.callCount, 0);\n    childA.click();\n    assert.equal(host.handleTap.callCount, 1);\n  });\n\n  test('listener event decorated with model', function() {\n    host.outerProp = 'foo';\n    childA.click();\n    assert.equal(host.handleTap.callCount, 1);\n    let event = host.handleTap.firstCall.args[0];\n    assert.instanceOf(event, Event);\n    assert.ok(event.model);\n    assert.equal(event.model.outerProp, 'foo');\n    host.outerProp = 'bar';\n    assert.equal(event.model.outerProp, 'bar');\n    assert.equal(event.model.parentModel, host);\n  });\n\n});\n\n\nsuite('templatize client with/without props', function() {\n\n  let host;\n  let childB;\n\n  setup(function() {\n    host = document.createElement('x-host');\n    document.body.appendChild(host);\n  });\n\n  teardown(function() {\n    document.body.removeChild(host);\n  });\n\n  test('templatize with no dataHost', function() {\n    host.shadowRoot.querySelector('[name=templatizeB]').go(true);\n    childB = host.shadowRoot.querySelector('#childB');\n    assert.ok(childB);\n    assert.equal(childB.computedFromLiteral, '33-prop-a');\n  });\n\n  test('templatize with no props', function() {\n    host.shadowRoot.querySelector('[name=templatizeB]').go(false);\n    childB = host.shadowRoot.querySelector('#childB');\n    assert.ok(childB);\n    assert.isUndefined(childB.computedFromLiteral);\n  });\n\n  test('templatize with no props, instance manually flushes', function() {\n    let templatizeA = host.shadowRoot.querySelector('[id=templatizeA]');\n    templatizeA.go(false);\n    let childA = host.shadowRoot.querySelector('#childA');\n    assert.ok(childA);\n    sinon.spy(childA, 'objChanged');\n    assert.isUndefined(childA.obj);\n    let o = {foo: true};\n    templatizeA.instance._setPendingProperty('obj', o);\n    templatizeA.instance._flushProperties();\n    assert.equal(childA.obj, o);\n    assert.isTrue(childA.objChanged.calledOnce);\n  });\n\n});\n\nsuite('templatizer behavior', function() {\n\n  let host;\n  let childC;\n\n  setup(function() {\n    host = document.createElement('x-host');\n    document.body.appendChild(host);\n    host.$.templatizeC.go(true);\n    childC = host.shadowRoot.querySelector('#childC');\n    assert.ok(childC);\n  });\n\n  teardown(function() {\n    document.body.removeChild(host);\n  });\n\n  test('stamped with initial data', function() {\n    assert.equal(childC.outerProp, 'outerProp');\n    assert.equal(childC.outerObj, host.outerObj);\n    assert.equal(childC.outerObjProp, 'outerObj.prop');\n    assert.equal(childC.prop, 'prop-a');\n    assert.equal(childC.obj, host.objA);\n    assert.equal(childC.objProp, 'objA.prop');\n  });\n\n  test('host properties propagated in', function() {\n    host.outerProp = 'outerProp++';\n    assert.equal(childC.outerProp, 'outerProp++');\n    host.outerObj = { prop: 'outerObj++.prop' };\n    assert.equal(childC.outerObj, host.outerObj);\n    assert.equal(childC.outerObjProp, 'outerObj++.prop');\n  });\n\n  test('host paths propagated in', function() {\n    sinon.spy(childC, 'outerObjChanged');\n    host.set('outerObj.prop', 'outerObj.prop++');\n    assert.equal(childC.outerObjProp, 'outerObj.prop++');\n    assert.isTrue(childC.outerObjChanged.calledOnce);\n    assert.equal(childC.outerObjChanged.getCall(0).args[0].path, 'outerObj.prop');\n    assert.equal(childC.outerObjChanged.getCall(0).args[0].value, 'outerObj.prop++');\n  });\n\n  test('host properties propagated out', function() {\n    childC.outerProp = 'outerProp++';\n    assert.equal(host.outerProp, 'outerProp++');\n    childC.outerObj = { prop: 'outerObj++.prop' };\n    assert.equal(host.outerObj.prop, 'outerObj++.prop');\n  });\n\n  test('host paths propagated out', function() {\n    sinon.spy(host, 'outerObjChanged');\n    childC.set('outerObj.prop', 'outerObj.prop++');\n    assert.equal(host.outerObj.prop, 'outerObj.prop++');\n    assert.isTrue(host.outerObjChanged.calledOnce);\n    assert.equal(host.outerObjChanged.getCall(0).args[0].path, 'outerObj.prop');\n    assert.equal(host.outerObjChanged.getCall(0).args[0].value, 'outerObj.prop++');\n  });\n\n  test('instance properties propagated in', function() {\n    host.propA = 'prop-a++';\n    assert.equal(childC.prop, 'prop-a++');\n    host.objA = { prop: 'objA++.prop' };\n    assert.equal(childC.obj, host.objA);\n    assert.equal(childC.objProp, 'objA++.prop');\n  });\n\n  test('instance paths propagated in', function() {\n    sinon.spy(childC, 'objChanged');\n    host.set('objA.prop', 'objA.prop++');\n    assert.equal(childC.obj.prop, 'objA.prop++');\n    assert.isTrue(childC.objChanged.calledOnce);\n    assert.equal(childC.objChanged.getCall(0).args[0].path, 'obj.prop');\n    assert.equal(childC.objChanged.getCall(0).args[0].value, 'objA.prop++');\n  });\n\n  test('instance properties propagated out', function() {\n    childC.prop = 'prop-a++';\n    assert.equal(host.propA, 'prop-a++');\n    childC.obj = { prop: 'objA++.prop' };\n    assert.equal(host.objA.prop, 'objA++.prop');\n  });\n\n  test('instance paths propagated out', function() {\n    sinon.spy(host, 'objAChanged');\n    childC.set('obj.prop', 'objA.prop++');\n    assert.equal(host.objA.prop, 'objA.prop++');\n    assert.isTrue(host.objAChanged.calledOnce);\n    assert.equal(host.objAChanged.getCall(0).args[0].path, 'objA.prop');\n    assert.equal(host.objAChanged.getCall(0).args[0].value, 'objA.prop++');\n  });\n\n  test('outer & inner props conflict', function() {\n    assert.equal(childC.conflict, 'bar');\n    host.set('outerInnerConflict.prop', 'foo');\n    assert.equal(childC.conflict, 'bar');\n  });\n\n  test('inline computed functions', function() {\n    assert.equal(childC.computedFromLiteral, '33-prop-a');\n  });\n\n  test('ensure literals are not forwarded to templates', function() {\n    assert.notOk(host._hasAccessor(33));\n    assert.notOk(Object.getOwnPropertyDescriptor(Object.getPrototypeOf(host), 33));\n  });\n\n  test('ensure undefined is not set on templatizee', function() {\n    assert.equal(host.$.templatizeA[undefined], undefined);\n  });\n\n  test('able to add gesture listeners', function() {\n    assert.equal(host.handleTap.callCount, 0);\n    childC.click();\n    assert.equal(host.handleTap.callCount, 1);\n  });\n\n  test('listener event decorated with model', function() {\n    host.outerProp = 'foo';\n    childC.click();\n    assert.equal(host.handleTap.callCount, 1);\n    let event = host.handleTap.firstCall.args[0];\n    assert.instanceOf(event, Event);\n    assert.ok(event.model);\n    assert.equal(event.model.outerProp, 'foo');\n    host.outerProp = 'bar';\n    assert.equal(event.model.outerProp, 'bar');\n  });\n\n});\n\nsuite('templatize with no host', function() {\n\n  test('stamped with initial data', function() {\n    const template = document.getElementById('standalone').cloneNode(true);\n    const Template = templatize(template);\n    const inst = new Template({prop: 'prop', text: 'text'});\n    const div = inst.root.firstChild;\n    assert.equal(div.prop, 'prop');\n    assert.equal(div.textContent, 'text');\n  });\n\n  test('stamped with no initial data', function() {\n    const template = document.getElementById('standalone').cloneNode(true);\n    const Template = templatize(template);\n    const inst = new Template();\n    const div = inst.root.firstChild;\n    assert.equal(div.prop, undefined);\n    assert.equal(div.textContent.trim(), '');\n    inst.setProperties({prop: 'prop', text: 'text'});\n    assert.equal(div.prop, 'prop');\n    assert.equal(div.textContent, 'text');\n  });\n\n  test('notifies path data changes', function() {\n    const template = document.getElementById('standalone').cloneNode(true);\n    const Template = templatize(template);\n    const inst = new Template();\n    const div = inst.root.firstChild;\n    inst.setProperties({prop: {foo: true}});\n    assert.equal(div.prop.foo, true);\n    inst.set('prop.foo', false);\n    assert.equal(div.prop.foo, false);\n  });\n\n});\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "test/unit/wct-browser-config.js",
    "content": "window.WCT = {\n  environmentScripts: [\n    'stacky/lib/parsing.js',\n    'stacky/lib/formatting.js',\n    'stacky/lib/normalization.js',\n    'mocha/mocha.js',\n    'chai/chai.js',\n    '@polymer/sinonjs/sinon.js',\n    'accessibility-developer-tools/dist/js/axs_testing.js',\n    '@polymer/test-fixture/test-fixture.js'\n]\n};\n"
  },
  {
    "path": "util/.eslintrc.json",
    "content": "{\n  \"env\": {\n    \"node\": true\n  }\n}\n"
  },
  {
    "path": "util/gen-changelog.sh",
    "content": "#!/bin/bash\n#\n# @license\n# Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\n# This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\n# The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\n# The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\n# Code distributed by Google as part of the polymer project is also\n# subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n#\n\nPRETTY=\"- %s ([commit](https://github.com/Polymer/polymer/commit/%h))%n\"\nstart=\"$1\"\nend=\"$2\"\n\nenddate=`git log -1 ${end} --pretty=\"%ai\" | cut -d ' ' -f 1`\n\nold=\"\"\nif [ -e CHANGELOG.md ]; then\n  old=\"`sed -e '1,2d' CHANGELOG.md`\"\nfi\n\ncat > CHANGELOG.md <<EOD\n# Change Log\n\n## [${end}](https://github.com/Polymer/polymer/tree/${end}) (${enddate})\n`git log --no-merges \"${start}\"..\"${end}^1\" --pretty=\"${PRETTY}\"`\n\n${old}\nEOD\n"
  },
  {
    "path": "util/minimalDocument.js",
    "content": "/**\n * @license\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\n * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\n * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\n * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\n * Code distributed by Google as part of the polymer project is also\n * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n */\n\nconst dom5 = require('dom5');\nconst parse5 = require('parse5');\nconst {Transform} = require('stream');\n\nconst p = dom5.predicates;\n\nfunction onlyOneLicense(doc) {\n  let comments = dom5.nodeWalkAll(doc, dom5.isCommentNode);\n  let hasLicense = false;\n  for (let i = 0; i < comments.length; i++) {\n    let c = comments[i];\n    let text = dom5.getTextContent(c);\n    if (text.indexOf('@license') === -1 || hasLicense) {\n      dom5.remove(c);\n    } else {\n      hasLicense = true;\n    }\n  }\n}\n\nconst blankRx = /^\\s+$/;\n\nconst isBlankNode = p.AND(dom5.isTextNode, (t) => blankRx.test(dom5.getTextContent(t)));\n\nclass MinimalDocTransform extends Transform {\n  constructor() {\n    super({objectMode: true});\n  }\n  _transform(file, enc, cb) {\n    let doc = parse5.parse(String(file.contents), {locationInfo: true});\n    let vulc = dom5.query(doc, p.AND(p.hasTagName('div'), p.hasAttr('by-polymer-bundler'), p.hasAttr('hidden')));\n    let charset = dom5.query(doc, p.AND(p.hasTagName('meta'), p.hasAttrValue('charset', 'UTF-8')));\n\n    if (charset) {\n      dom5.remove(charset);\n    }\n\n    dom5.removeNodeSaveChildren(vulc);\n\n    let scripts = dom5.queryAll(doc, p.hasTagName('script'));\n    let collector = scripts[0];\n    let contents = [dom5.getTextContent(collector)];\n    for (let i = 1, s; i < scripts.length; i++) {\n      s = scripts[i];\n      dom5.remove(s);\n      contents.push(dom5.getTextContent(s));\n    }\n    dom5.setTextContent(collector, contents.join(''));\n\n    onlyOneLicense(doc);\n\n    dom5.removeFakeRootElements(doc);\n\n    dom5.nodeWalkAll(doc, isBlankNode).forEach((t) => dom5.remove(t));\n\n    file.contents = new Buffer(parse5.serialize(doc));\n\n    cb(null, file);\n  }\n}\n\nmodule.exports = () => new MinimalDocTransform();\n"
  },
  {
    "path": "util/travis-sauce-test.sh",
    "content": "#!/usr/bin/env bash\n#\n# @license\n# Copyright (c) 2018 The Polymer Project Authors. All rights reserved.\n# This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\n# The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\n# The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\n# Code distributed by Google as part of the polymer project is also\n# subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n#\nset -x\nnode ./node_modules/.bin/polymer test --npm --module-resolution=node -s 'windows 10/microsoftedge@15' -s 'windows 10/microsoftedge@17' -s 'windows 8.1/internet explorer@11' -s 'macos 10.13/safari@11' -s 'macos 10.13/safari@12' -s 'macos 10.13/safari@13' -s 'Linux/chrome@41'"
  },
  {
    "path": "wct.conf.json",
    "content": "{\n  \"suites\": [\"test/runner.html\"],\n  \"environmentImports\": [\n    \"test-fixture/test-fixture.html\"\n  ],\n  \"plugins\": {\n    \"local\": {\n      \"browserOptions\": {\n        \"chrome\": [\n          \"headless\",\n          \"disable-gpu\",\n          \"no-sandbox\"\n        ]\n      }\n    }\n  }\n}\n"
  }
]