[
  {
    "path": ".gitignore",
    "content": "*.js\n!karma.conf.js\n!system.config.js\n*.d.ts\n\n# Created by https://www.gitignore.io/api/node,bower,typings\n\n### Node ###\n# Logs\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (http://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules\njspm_packages\n\n# Optional npm cache directory\n.npm\n\n# Optional REPL history\n.node_repl_history\n\n\n### Bower ###\nbower_components\n.bower-cache\n.bower-registry\n.bower-tmp\n\n### IntelliJ ###\n.idea\nangular-polymer.iml\n"
  },
  {
    "path": ".npmignore",
    "content": "# Source files\nbower.json\ntsconfig.json\ntslint.json\ntypings/\ntypings.json\n*.ts\n!*.d.ts\n\n# Tests and testing setup\n*.html\n*.spec.js\n*.spec.ts\n*.spec.d.ts\nsystem.config.js\nkarma.conf.js\ncircle.yml\n\n# Docs\ndocs/\n\n# Created by https://www.gitignore.io/api/node,bower,typings\n\n### Node ###\n# Logs\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (http://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules\njspm_packages\n\n# Optional npm cache directory\n.npm\n\n# Optional REPL history\n.node_repl_history\n\n\n### Bower ###\nbower_components\n.bower-cache\n.bower-registry\n.bower-tmp\n\n\n### Typings ###\n## Ignore downloaded typings\ntypings\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   Copyright 2016 Vaadin Ltd.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "README.md",
    "content": "[![CircleCI](https://img.shields.io/circleci/project/github/platosha/angular-polymer.svg)](https://circleci.com/gh/platosha/angular-polymer) [![Version](https://img.shields.io/npm/v/angular-polymer.svg)](https://www.npmjs.com/package/angular-polymer)\n\n# Angular-Polymer\n\n`angular-polymer` is a directive factory that aims at bridging the gaps between using [Polymer](https://www.polymer-project.org) based Web Components in [Angular](https://angular.io/) applications.\n\n> Note: Currently Angular-Polymer only works with Angular 2.x, or Angular-CLI 1.0.0-rc.2 and lower.\n> Work is being done to upgrade the library to work the latest Angular & CLI. [Want to help Contribute?](https://github.com/platosha/angular-polymer/issues/123)\n\n**In case you are using Angular 4+ and Polymer 2+** you might want to check out https://github.com/hotforfeature/origami\n\n---\n\n```typescript\nimport { NgModule, CUSTOM_ELEMENTS_SCHEMA, Component } from '@angular/core';\nimport { PolymerModule, PolymerElement } from '@vaadin/angular2-polymer';\n\n@NgModule({\n  imports: [ PolymerModule ],\n  declarations: [\n    AppComponent,\n    PolymerElement('paper-input'),\n    PolymerElement('vaadin-combo-box')\n  ],\n  bootstrap: [ AppComponent ],\n  schemas: [ CUSTOM_ELEMENTS_SCHEMA ]\n})\nexport class AppModule { }\n\n@Component({\n  selector: 'app-component',\n  template: `\n    <paper-input [(value)]=\"myValue\"></paper-input>\n    <vaadin-combo-box [(value)]=\"myValue\" [items]=\"myItems\"></vaadin-combo-box>\n  `\n})\nclass AppComponent {\n  myValue = 'A';\n  myItems = ['A', 'B', 'C'];\n}\n```\n\n## Getting started\n\nSee the overview for a [quick start](https://github.com/platosha/angular-polymer/blob/master/docs/overview.adoc#quick-start).\n\nSee the [tutorial](https://github.com/platosha/angular-polymer/blob/master/docs/tutorial-index.adoc) for complete instructions on how to use `angular-polymer` and how to build a working application with Angular data binding and routes.\n\nIf you are using [Webpack](https://webpack.github.io/) in your project, see the specific [document](https://github.com/platosha/angular-polymer/blob/master/docs/ng-cli-webpack.adoc) on how to build angular-polymer apps with webpack.\n\n## Demo app\n\nThe Expense Manager demo is an example of a real world application built using Angular and Polymer web components.\n\n- [Live demo](http://demo.vaadin.com/expense-manager-ng)\n- [Source code](https://github.com/vaadin/expense-manager-ng2-demo)\n\n## Where to get Polymer web components\n\nFor high quality Polymer web components, see the [Webcomponents Element Catalog](https://www.webcomponents.org/) and [Vaadin Elements](https://vaadin.com/elements).\n\n## Development\n\nFamiliarize yourself with the code and try to follow the same syntax conventions to make it easier for us to accept your pull requests.\n\nDiscuss / exchange ideas and ask questions here:\nhttps://polymer.slack.com/messages/polymer-angular/\n\n### Getting the Code\n\n1. Clone the angular-polymer project:\n\n  ```shell\n  $ git clone https://github.com/platosha/angular-polymer.git\n  $ cd angular-polymer\n  ```\n\n2. Install dependencies. We assume that you have already installed `npm` in your system.\n\n  ```shell\n  $ npm install\n  ```\n\n### Running Tests\n\nFor running the tests you need [Bower](http://bower.io) installed.\n\nThen, you can download all bower dependencies needed by the Tests.\n\n  ```shell\n  $ bower install\n  ```\n\nFinally, you can run the tests by typing:\n\n  ```shell\n  $ npm test\n  ```\n\nOptionally, you can watch for the source changes and keep the tests running automatically:\n\n  ```shell\n  $ npm run test:w\n  ```\n\n## License\n\nApache License 2.0\n"
  },
  {
    "path": "bower.json",
    "content": "{\n  \"name\": \"angular2-polymer\",\n  \"description\": \"Angular 2 support for Polymer elements\",\n  \"main\": \"index.js\",\n  \"authors\": [\n    \"Vaadin Ltd\"\n  ],\n  \"license\": \"Apache 2.0\",\n  \"homepage\": \"https://github.com/vaadin/angular2-polymer\",\n  \"moduleType\": [],\n  \"private\": false,\n  \"ignore\": [\n    \"**/.*\",\n    \"node_modules\",\n    \"bower_components\",\n    \"test\",\n    \"tests\"\n  ],\n  \"devDependencies\": {\n    \"polymer\": \"Polymer/polymer#^1.4.0\",\n    \"iron-form-element-behavior\": \"PolymerElements/iron-form-element-behavior#^1.0.6\",\n    \"paper-checkbox\": \"PolymerElements/paper-checkbox#^1.3.0\"\n  }\n}\n"
  },
  {
    "path": "circle.yml",
    "content": "machine:\n  node:\n    version: 6.9.1\n\ndependencies:\n  override:\n    - npm install\n    - npm run bower install\n  cache_directories:\n    - bower_components\n\ncompile:\n  override:\n    - npm run lint\n"
  },
  {
    "path": "docs/api.adoc",
    "content": "---\ntitle: API Reference\norder: 4\nlayout: page\n---\n\n[[vaadin-angular2-polymer.api]]\n= Angular2-Polymer API\n\nThis package consists of one generic Angular 2 directive factory method named [classname]#PolymerElement#, which is able to handle any Polymer element for easy integrating on Angular apps.\n\n== Features\n\nThe [classname]#PolymerElement# is composed of a set of low level directives which would be added to the module dynamically.\n\n`changeEventsAdapterDirective`::\nThis directive configures all the the public [propertyname]#properties#, that notify for their value change in a Polymer element, to be an Angular 2 link:https://angular.io/docs/js/latest/api/core/DirectiveMetadata-class.html+++#+++!+++#+++outputs-anchor[output].\nSo as any change made in a property in the polymer side, will be propagated to the Angular 2 parent component.\n\n`notifyForDiffersDirective`::\nConfigures all the public [propertyname]#properties# in a Polymer element to be an Angular 2 link:https://angular.io/docs/js/latest/api/core/DirectiveMetadata-class.html+++#+++!+++#+++inputs-anchor[input].\nIt allows to notify changes from the Angular side to Polymer. It supports primitive types, as well as both Array and Object properties, but not its children.\nIf you want to notify nested object changes, you can still do it by calling the Polymer's [methodname]#notifyPath# method on the element.\n\n`formElementDirective`::\nIf the element has the Polymer Form Element Behavior, this directive is added to the module, and it configures the element to be compatible with the Angular 2 `ngForm`.\n\n`validationDirective`::\nIt is another directive added in the case of the element has the Polymer Form Element Behavior. It sets the Polymer [propertyname]#invalid# flag based on the Angular 2 `ngControl` state.\n\n`reloadConfigurationDirective`::\nThis directive is added to those Polymer elements that need to run a configuration function after they are initialized.\nIt is added if the element has the [methodname]#isInitialized# and the [methodname]#reloadConfiguration# methods in its prototype.\n\n== Usage\n\nIn order to use the [classname]#PolymerElement# in the [propertyname]#declarations# block of your [classname]#NgModule#, you have to import it as is shown in the example below.\n\nThe only public API is the [classname]#PolymerElement(tagName: string): Array<Directive># factory method.\nThe argument [propertyname]#tagName# is mandatory, and must match the tag name of the Polymer element.\nThe factory returns the set of necessary directives for the given Polymer element.\nHence, you have to add the [classname]#PolymerElement# directive as many times as different Polymer elements you are using in your Angular module.\n\n[source,typescript]\n----\nimport { Component, NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';\nimport { BrowserModule } from '@angular/platform-browser';\nimport { PolymerElement } from '@vaadin/angular2-polymer';\n\n@Component({\n  selector: 'app-root',\n  template: `\n    <iron-icon icon=\"attachment\"></iron-icon>\n    <paper-input [(value)]=\"myValue\"></paper-input>\n    <vaadin-combo-box [(value)]=\"myValue\" [items]=\"myItems\"></vaadin-combo-box>\n  `\n})\nclass AppComponent {\n   myValue = 'A';\n   myItems = ['A', 'B', 'C'];\n}\n\n@NgModule({\n  imports: [ BrowserModule ],\n  declarations: [\n    AppComponent,\n    PolymerElement('iron-icon'),\n    PolymerElement('paper-input'),\n    PolymerElement('vaadin-combo-box')\n  ],\n  bootstrap: [ AppComponent ],\n  schemas: [ CUSTOM_ELEMENTS_SCHEMA ]\n})\nexport class AppModule { }\n----\n"
  },
  {
    "path": "docs/best-practices.adoc",
    "content": "---\ntitle: Best practices\norder: 1\nlayout: page\n---\n\n[[angular-polymer.best-practices]]\n= Angular Polymer best practices\n\nThis document describes various best practices when using the `angular-polymer` library.\n\n== Lists (with `iron-list`)\nAngular has it's own mechanism for dealing with `<template>` elements. That is why something like this:\n``` html\n<iron-list [items]=\"data\" as=\"item\">\n  <template>\n    <div>\n      Name: {{item.value}}\n    </div>\n  </template>\n</iron-list>\n```\nIs *not* possible. Here is some more information: https://github.com/PolymerElements/iron-list/issues/291#issuecomment-251354454\n\n=== Best practice\nBest practice at the moment is to wrap `<iron-list>` with its template in another Polymer element, that is registered outside Angular templates. For example, create my-list.html:\n\n``` html\n<link rel=\"import\" href=\"bower_components/polymer/polymer.html\">\n<link rel=\"import\" href=\"bower_components/iron-list/iron-list.html\">\n\n<dom-module id=\"my-list\">\n  <template>\n    <iron-list items=\"[[items]]\" as=\"item\">\n      <template>\n        <div>\n          Name: [[item.name]]\n        </div>\n      </template>\n    </iron-list>\n  </template>\n\n  <script>\n    Polymer({\n      is: \"my-list\",\n      properties: {\n        items: Array\n      }\n    });\n  </script>\n</dom-module>\n```\n\nThen import it in index.html, just like any other Polymer element:\n\n``` html\n...\n  <head>\n    ...\n    <link rel=\"import\" href=\"my-list.html\">\n  </head>\n...\n```\n\nThen you can use the `<my-list>` element in declarations (`PolymerElement('my-list')`), as well as in Angular templates. The `<iron-list>` template was already defined in `<my-list>`, therefore we don't have it in Angular templates:\n\n``` html\n<my-list [items]=\"data\"></my-list>\n```\n\nIt requires a bit of work, though: you have to manually bypass all the properties and methods you use in `<iron-list>` through `<my-list>`. In the example above, only the `items` property is bypassed.\n\n== Forms\nAs `PolymerElement('x-element')` looks for elements named `<x-element>` it doesn't work with Polymer elements that have been extended from native elements like `<form is=\"iron-form\">`.\nFor the future, extending native elements will be [dropped in Polymer 2.0](https://github.com/Polymer/polymer/blob/2.0-preview/README.md#v1-custom-elements) so there will be an actual `<iron-form>` element released at some point.\n\n=== Best practice\n\nAs a solution in this case you'll have to use Angular form component instead. Another alternative is creating a custom Polymer element that wraps the `<form is=\"iron-form\">`. Same concept like for `iron-lists` in this document.\n\nHere is an approach on how to solve the problem with an angular form:\n```\n<form [formGroup]=\"registerForm\" (ngSubmit)=\"onSubmit()\">\n    <div class=\"form-group\">\n        <paper-input\n                label=\"Username\"\n                type=\"text\"\n                id=\"username\"\n                class=\"form-control\"\n                formControlName=\"username\"\n                name=\"username\"\n                auto-validate [(errorMessage)]=\"usernameErrorMessage\"></paper-input>\n    </div>\n    <div class=\"form-group\">\n        <paper-input\n                label=\"E-Mail\"\n                type=\"email\"\n                id=\"email\"\n                class=\"form-control\"\n                formControlName=\"email\"\n                name=\"email\"\n                autocomplete=\"on\"\n                required auto-validate [(errorMessage)]=\"emailErrorMessage\"></paper-input>\n    </div>\n\n    <paper-button\n            type=\"submit\" raised\n            [disabled]=\"!registerForm.valid\"\n            (click)=\"onSubmit()\">\n        Register User\n    </paper-button>\n</form>\n```\n\nAnd the typescript file:\n```\nimport {Component, OnInit} from '@angular/core';\nimport {FormGroup, FormControl, Validators} from '@angular/forms';\n\n@Component({\n    selector: 'register',\n    templateUrl: './register.component.html'\n})\nexport class RegisterComponent implements OnInit {\n    private registerForm: FormGroup;\n\n    private usernameErrorMessage: string;\n    private emailErrorMessage: string;\n\n    constructor() {\n            this.usernameErrorMessage = '';\n            this.emailErrorMessage = '';\n    }\n\n    ngOnInit() {\n        this.registerForm = new FormGroup({\n            username: new FormControl(null, [Validators.required, Validators.minLength(2)]),\n            email: new FormControl(null, [\n                Validators.required,\n                Validators.pattern('[a-z0-9!#$%&\\'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&\\'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?')\n            ])\n        });\n    }\n\n    onSubmit() {\n        console.log(this.registerForm.value.username);\n        console.log(this.registerForm.value.email);\n    }\n}\n```\n"
  },
  {
    "path": "docs/ng-cli-webpack.adoc",
    "content": "---\ntitle: Using in Angular CLI Webpack\norder: 3\nlayout: page\n---\n\n:linkattrs:\n[[vaadin-angular2-polymer.ng2cli]]\n= Using Polymer Elements in Angular CLI Webpack Applications\n\n[[vaadin-angular2-polymer.ng2cliwebpack.introduction]]\n== Introduction\n\nhttps://github.com/angular/angular-cli[Angular CLI] is a command line tool for Angular 2. It is not only a scaffolding tool for creating and modifying a project, but also for other actions like building, running, debugging, and testing the project.\n\nIn this document we will describe all the modifications you have to make to your Angular CLI project to use Polymer elements.\n\n[[vaadin-angular2-polymer.ng2cliwebpack.preparation]]\n== Preparation\n\nWe assume that you already have installed in your system the Angular CLI package and the `ng` command\nis available in your PATH. Otherwise run the following command:\n\n[subs=\"normal\"]\n----\n[prompt]#$# [command]#npm# install -g @angular/cli\n----\n\nThen, create a new Angular 2 project.\n\n[subs=\"normal\"]\n----\n[prompt]#$# [command]#ng# new [replaceable]#my-project#\n----\n\nCheck that everything works by compiling, testing, and running your new project:\n\n[subs=\"normal\"]\n----\n[prompt]#$# [command]#cd# [replaceable]#my-project#\n[prompt]#$# [command]#ng# build\n[prompt]#$# [command]#ng# test\n[prompt]#$# [command]#ng# serve\n----\n\nWhen the development server is running you can test the application at http://localhost:4200[http://localhost:4200, role=\"external\", window=\"_blank\"].\nPress kbd:[Ctrl+C] to stop the server.\n\n[[vaadin-angular2-polymer.ng2cliwebpack.dependencies]]\n== Adding Polymer Elements Dependencies\n\nPolymer uses the http://bower.io/[Bower] package manager. Hence, you first  have to install and initialize Bower before continuing:\n\n[subs=\"normal\"]\n----\n[prompt]#$# [command]#npm# install bower -g\n[prompt]#$# [command]#bower# init\n----\n\nBy default, Bower installs dependencies to the [filename]#bower_components# folder. But Angular CLI expects static stuff to be in the [filename]#src/assets# directory.\nThus, create the [filename]#.bowerrc# file in the root directory, with the following content:\n\n[source,json]\n.&#46;bowerrc\n----\n{\n  \"directory\" : \"src/assets/bower_components\"\n}\n----\n\nNow, you can install all the Polymer elements that you need in your application.\n\nFor instance, to install all the elements in the https://elements.polymer-project.org/browse?package=paper-elements[Polymer Paper] collection,\nand the [elementname]#https://vaadin.com/elements/-/element/vaadin-combo-box[vaadin-combo-box]# element, run the following:\n\n[subs=\"normal\"]\n----\n[prompt]#$# [command]#bower# install --save [replaceable]#paper-elements vaadin-combo-box#\n----\n\n[TIP]\n====\nAdd the following line to the [filename]#.gitignore# file to prevent the Bower dependencies from being tracked by Git in future:\n\n[source]\n----\nsrc/assets/bower_components\n----\n====\n\nNext we will modify the application index HTML file to load the web components polyfill, and to import the Polymer elements.\nOpen the [filename]#src/index.html# file and append the following lines to the [elementname]#head# section:\n\n[source,html]\n.src/index.html head additions\n----\n<head>\n  ...\n\n  <script src=\"assets/bower_components/webcomponentsjs/webcomponents.min.js\"></script>\n  <script>\n    window.Polymer = {\n      dom: 'shadow'\n    };\n  </script>\n  <link rel=\"import\" href=\"assets/bower_components/paper-styles/color.html\">\n  <link rel=\"import\" href=\"assets/bower_components/paper-styles/typography.html\">\n  <link rel=\"import\" href=\"assets/bower_components/vaadin-combo-box/vaadin-combo-box.html\">\n  <link rel=\"import\" href=\"assets/bower_components/paper-input/paper-input.html\">\n</head>\n----\n\nIn Angular CLI Webpack projects, the main application file is automatically bundled and appended to the end of the [elementname]#body# section of the [filename]#index.html# file.\nIt means that the Angular application is imported and bootstrapped synchronously.\nMeanwhile, Polymer elements are loaded from HTML Imports processed asynchronously in browsers that do not have a native support.\n\nWe have to wait for the Polymer elements to be loaded and registered before running the application code.\nTherefore, we have to postpone the Angular application import until the [eventname]#WebComponentsReady# event is dispatched.\nCreate a new file [filename]#src/main-polymer.ts# with the following loader script:\n\n[source,typescript]\n.src/main-polymer.ts\n----\ndocument.addEventListener('WebComponentsReady', () => {\n  require('./main.ts');\n});\n----\n\nChange the main entry point of the application to load the new loader script.\nEdit the [filename]#angular-cli.json# file in the project root and replace the line `\"main\": \"main.ts\",` with  `\"main\": \"main-polymer.ts\",`.\n\n////\n// TODO: `$ ng set` could be used for editing the config, but it is broken nowadays.\nReplace the editing instructions above with the following paragraph after this PR is merged: https://github.com/angular/angular-cli/pull/1800\n\nRun the following command to set the new [filename]#src/main-polymer.ts# file as the application entry point:\n\n[subs=\"normal\"]\n----\n[prompt]#$# [command]#ng# set apps.0.main main-polymer.ts\n----\n////\n\nNow you can run `ng serve`, open the application in your browser, and everything should work with no errors in the console.\n\n[TIP]\nThe [filename]#webcomponents.js# polyfill is not necessary for browsers that fully implement the Web Components Spec like Chrome.\n\n[TIP]\n====\nOptionally, you can move the [filename]#webcomponents.min.js# from the application [filename]#index.html# to the [filename]#angular-cli.json# configuration file.\n\n[source, json]\n.angular-cli.json\n----\n{\n  \"scripts\":[\n    \"assets/bower_components/webcomponentsjs/webcomponents.min.js\"\n  ]\n}\n----\n====\n\n[[vaadin-angular2-polymer.ng2cliwebpack.directive]]\n== Adding The PolymerElement Package\n\nFor using Polymer elements in the Angular 2 application, we need to import the [classname]#PolymerElement#\ndirective from https://github.com/vaadin/angular2-polymer[@vaadin/angular2-polymer]. Thus we need to install the dependency by typing:\n\n[subs=\"normal\"]\n----\n[prompt]#$# [command]#npm# install --save @vaadin/angular2-polymer\n----\n\n\n[[vaadin-angular2-polymer.ng2cliwebpack.using]]\n== Using Polymer Elements\n\nNow that everything is set, we can add any Polymer elements to our application using their element names in templates,\nand the [classname]#PolymerElement# directive in code.\nFor example, modify the [filename]#src/app/app.component.html# to have the following code:\n\n[source,html]\n.src/app/app.component.html\n----\n<h1>{{title}}</h1>\n<vaadin-combo-box [label]=\"myLabel\" [(value)]=\"myValue\" [items]=\"myItems\"></vaadin-combo-box>\n<paper-input [(value)]=\"myValue\"></paper-input>\n----\n\nIn the [filename]#src/app/app.component.ts# file, define the properties bound in the template and specify the initial values:\n\n[source,typescript]\n.src/app/app.component.ts\n----\nimport { Component } from '@angular/core';\n\n@Component({\n  selector: 'app-root',\n  templateUrl: 'app.component.html',\n  styleUrls: ['app.component.css'],\n})\nexport class AppComponent {\n  title = 'app works!';\n  myLabel = 'Select a number';\n  myValue = '4';\n  myItems = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];\n}\n----\n\nThen import and add the [classname]#PolymerElement# directives and the [classname]#CUSTOM_ELEMENTS_SCHEMA# to the [classname]#AppModule#.\nOpen the [filename]#src/app/app.module.ts# file and replace the contents with the following code:\n\n[source,typescript]\n.src/app/app.module.ts\n----\nimport { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { HttpModule } from '@angular/http';\nimport { PolymerModule, PolymerElement } from '@vaadin/angular2-polymer';\n\nimport { AppComponent } from './app.component';\n\n@NgModule({\n  declarations: [\n    AppComponent,\n    PolymerElement('vaadin-combo-box'),\n    PolymerElement('paper-input')\n  ],\n  imports: [\n    PolymerModule,\n    FormsModule,\n    HttpModule\n  ],\n  providers: [],\n  entryComponents: [AppComponent],\n  bootstrap: [AppComponent],\n  schemas: [CUSTOM_ELEMENTS_SCHEMA]\n})\nexport class AppModule { }\n----\n\nFinally, you can use Polymer custom CSS properties and custom CSS mixins in the [filename]#app.component.css#\nfile for the scoped styles, and in the [filename]#index.html# file for the global ones.\nIn the following example we use mixins and properties defined in the Paper [elementname]#color# and [elementname]#typography# elements.\n\n[source,html]\n.src/index.html\n----\n<head>\n  ...\n  <style is=\"custom-style\">\n    body {\n      @apply(--paper-font-body1);\n    }\n  </style>\n</head>\n----\n\n[source,css]\n.src/app/app.component.css\n----\npaper-input,\nvaadin-combo-box {\n  background: var(--paper-grey-200);\n  padding: 8px;\n}\n----\n\n[[vaadin-angular2-polymer.ng2cliwebpack.testing]]\n== Testing\n\nAngular CLI projects come with https://karma-runner.github.io[Karma] tests.\n\nSince tests are run against the testing module defined in the [filename]#app.component.spec.ts#, instead of\nthe one defined in the [filename]#app.module.ts#, you need to import the [classname]#CUSTOM_ELEMENTS_SCHEMA#\nin the test file.\n\n[source,typescript]\n.src/app/app.component.spec.ts\n----\nimport { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';\n...\n\ndescribe('App: NgApp', () => {\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      declarations: [\n        AppComponent,\n      ],\n      schemas: [CUSTOM_ELEMENTS_SCHEMA]\n    });\n  });\n  ...\n});\n----\n\nThen, you can test elements API as usual. For example:\n\n[source,typescript]\n.src/app/app.component.spec.ts\n----\n...\n\nit('vaadin-combo-box and paper-input should have an initial value of 4', async(() => {\n  let fixture = TestBed.createComponent(AppComponent);\n  fixture.detectChanges();\n  let compiled = fixture.debugElement.nativeElement;\n  let combobox = compiled.querySelector('vaadin-combo-box');\n  let input = compiled.querySelector('paper-input');\n  expect(combobox.value).toEqual('4');\n  expect(input.value).toEqual('4');\n}));\n----\n"
  },
  {
    "path": "docs/overview.adoc",
    "content": "---\ntitle: Overview\norder: 1\nlayout: page\n---\n\n[[vaadin-angular2-polymer.overview]]\n= Angular 2 Integration\n\nThe `angular2-polymer` is a directive factory that aims at bridging the gaps between using link:https://www.polymer-project.org[Polymer] based Web Components in link:https://angular.io/[Angular 2] applications.\n\nIt scrapes the Polymer element API in order to define Angular 2 `outputs` and `inputs`, to apply the `ngControl` and the `ngForm` directives, and to observe DOM changes updating the element's DOM tree appropriately.\n\nSince Vaadin Elements are built using Polymer, you need the [literal]#https://github.com/vaadin/angular2-polymer[@vaadin/angular2-polymer]# directive to enable seamless usage within Angular 2 applications.\n\n== Quick Start\n\n. Install the `angular2-polymer` package and the Polymer element you want to use.\n+\n[source,subs=\"normal\"]\n----\n[prompt]#$# [command]#npm# install @vaadin/angular2-polymer\n[prompt]#$# [command]#bower# install [replaceable]#element-name#\n----\n\n.  Load the Web Components polyfill for browsers that don’t have native support for the Web Components standards, and configure Polymer to use Shadow DOM. Then you can import the elements you want to use.\n+\n[source,html,subs=\"normal\"]\n.index.html\n----\n<script src=\"bower_components/webcomponentsjs/webcomponents.min.js\"></script>\n<script>\n  window.Polymer = {\n    dom: 'shadow'\n  };\n</script>\n<link rel=\"import\" href=\"bower_components/[replaceable]#element-name#/[replaceable]#element-name#.html\">\n----\n+\nYou also need to wait for the \"WebComponentsReady\" event before bootstrapping the Angular 2 app. The event is fired after all of the web components have finished registering and are ready to be used.\n+\n[source,html,subs=\"normal\"]\n.index.html\n----\n<script>\n  document.addEventListener('WebComponentsReady', function() {\n    System.import('app').catch(function(err){ console.error(err); });\n  });\n</script>\n----\n. Import the Angular 2 directives and use them in your code.\n+\n[source,typescript,subs=\"normal\"]\n.app/app.module.ts\n----\nimport { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';\nimport { PolymerModule, PolymerElement } from '@vaadin/angular2-polymer';\nimport { AppComponent } from './app.component';\n\n@NgModule({\n  imports: +++[+++ PolymerModule +++]+++,\n  declarations: +++[+++\n    AppComponent,\n    PolymerElement('[replaceable]#element-name#')\n  +++]+++,\n  bootstrap: +++[+++ AppComponent +++]+++,\n  schemas: +++[+++ CUSTOM_ELEMENTS_SCHEMA +++]+++\n})\nexport class AppModule { }\n----\n+\n[source,typescript,subs=\"normal\"]\n.app/app.component.ts\n----\nimport { Component } from '@angular2/core';\n\n@Component({\n  selector: 'app-component',\n  template: +++`<+++[replaceable]#element-name#></[replaceable]#element-name#>+++`+++\n})\nexport class AppComponent { }\n----\n\nNote, that we also added the [classname]#CUSTOM_ELEMENTS_SCHEMA# to the [classname]#AppModule#. This is required to enable usage of non-standard properties on custom elements in the Angular component templates.\n\n== In case you use Angular 2.1 or 2.0\nYou can replace the `app.module.ts` code with the following. Use the old `BrowserModule`\n[source,typescript,subs=\"normal\"]\n.app/app.module.ts\n----\nimport { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';\nimport { BrowserModule } from '@angular/platform-browser';\nimport { PolymerElement } from '@vaadin/angular2-polymer';\nimport { AppComponent } from './app.component';\n\n@NgModule({\n  imports: +++[+++ BrowserModule +++]+++,\n  declarations: +++[+++\n    AppComponent,\n    PolymerElement('[replaceable]#element-name#')\n  +++]+++,\n  bootstrap: +++[+++ AppComponent +++]+++,\n  schemas: +++[+++ CUSTOM_ELEMENTS_SCHEMA +++]+++\n})\nexport class AppModule { }\n----\n\nlink:https://github.com/platosha/angular-polymer/blob/master/docs/tutorial-index.adoc[See the tutorial] for complete instructions how to set up your Angular 2 application to work with Polymer elements."
  },
  {
    "path": "docs/tutorial/creating-project.adoc",
    "content": "[[vaadin-angular2-polymer.tutorial.creating-project]]\n== Creating Project\n\nWe begin by creating a new project based on the source code from the Angular 2 QuickStart project. You can either clone it from the GitHub repository or extract it from a ZIP package, as described next.\n\n[NOTE]\n====\nIf you are not yet familiar with Angular 2, please go through the https://angular.io/docs/ts/latest/quickstart.html[Angular 2 QuickStart] tutorial, which explains every step of starting a new Angular 2 application from scratch.\n====\n\n=== Starting from the QuickStart Repository\n\nClone the https://github.com/angular/quickstart[Angular 2 QuickStart repository] into the tutorial project folder:\n\n[subs=\"normal\"]\n----\n[prompt]#$# [command]#git# clone https://github.com/angular/quickstart [replaceable]#my-project#\n[prompt]#$# [command]#cd# [replaceable]#my-project#\n----\n\nWe are not going to contribute to the quickstart repository itself, so the original repository data is not needed. Remove the [filename]#.git# repository data folder.\n\n=== Starting from the QuickStart ZIP Package\n\nAlternatively, instead of using Git to clone the QuickStart repository, you can download and extract the https://github.com/angular/quickstart/archive/master.zip[QuickStart zip package].\n\n=== Remove the AppComponent Tests\n\nThe QuickStart respository contains tests for the [classname]#AppComponent# class. Unfortunately, some changes that will be done to [classname]#AppComponent# in this tutorial would break the compilation of these tests.\n\nPlease remove the [filename]#app/app.component.spec.ts# file to prevent compilation errors later in this tutorial.\n\n[NOTE]\n.Testing in Angular 2\n====\nTesting is out of the scope of this tutorial.\n\nSee the https://angular.io/docs/ts/latest/guide/testing.html[Testing chapter] in the Angular 2 Developer Guide for more information on the topic.\n====\n\n=== Installing npm Packages and Starting the Development Server\n\nInstall npm dependencies:\n\n[subs=\"normal\"]\n----\n[prompt]#$# [command]#npm# install\n----\n\nAt this point, you should be able to compile the TypeScript source code and launch the development server. You can start the server to check that everything is fine:\n\n[subs=\"normal\"]\n----\n[prompt]#$# [command]#npm# start\n----\n\nPress kbd:[Ctrl+C] to stop the development server.\n\n[TIP]\n====\nSee the Angular 2 https://github.com/angular/quickstart/blob/master/README.md[QuickStart README] for more information about creating a new project and other useful [command]#npm# commands.\n====\n\n"
  },
  {
    "path": "docs/tutorial/dependencies.adoc",
    "content": "[[vaadin-angular2-polymer.tutorial.dependencies]]\n== Adding and Installing Dependencies\n\nAfter the previous step, we have an empty Angular 2 application source with all the Angular dependencies installed. In this step, we are going to add the Polymer library and some elements as dependencies of our application, and install them.\n\nVaadin Elements and other Polymer elements are mainly distributed through http://bower.io/[Bower]. We are going to use Bower to declare these dependencies and install them.\n\n=== Adding Bower Dependencies\n\n[IMPORTANT]\n====\nYou should install Bower before we start using it. Use [command]#npm# to install Bower with this command:\n\n[subs=\"normal\"]\n----\n[prompt]#$# [command]#npm# install -g bower\n----\n====\n\nCreate the [filename]#bower.json# file in your project root with the following contents:\n\n[source,json,subs=\"verbatim,quotes,macros\"]\n.[filename]#bower.json#\n----\n{\n  \"name\": \"[replaceable]#my-project#\",\n  \"description\": \"\",\n  \"main\": \"\",\n  \"authors\": +[+\n    \"[replaceable]#Your Name#\"\n  +]+,\n  \"license\": \"ISC\",\n  \"homepage\": \"\",\n  \"private\": true,\n  \"ignore\": [\n    \"**/.*\",\n    \"node_modules\",\n    \"bower_components\",\n    \"test\"\n  ],\n  \"dependencies\": {\n    \"polymer\": \"Polymer/polymer#^1.4.0\",\n    \"iron-flex-layout\": \"PolymerElements/iron-flex-layout#^1.3.1\",\n    \"iron-icons\": \"PolymerElements/iron-icons#^1.1.3\",\n    \"app-layout\": \"PolymerElements/app-layout#^0.9.0\",\n    \"paper-styles\": \"PolymerElements/paper-styles#^1.1.4\",\n    \"paper-icon-button\": \"PolymerElements/paper-icon-button#^1.1.1\",\n    \"paper-input\": \"PolymerElements/paper-input#^1.1.11\",\n    \"vaadin-grid\": \"Vaadin/vaadin-grid#^1.1.0\",\n    \"vaadin-date-picker\": \"Vaadin/vaadin-date-picker#^1.1.0\"\n  }\n}\n----\n\nThe [filename]#bower.json# file declares all Bower dependencies for our application. Now install them with the following command:\n\n[subs=\"normal\"]\n----\n[prompt]#$# [command]#bower# install\n----\n\nAfter that, you should have a [filename]#bower_components# directory in your project root, with all elements declared in the [filename]#bower.json# file, and their requirements. List the contents of the [filename]#bower_components# directory to verify that it contains the following subdirectories:\n\n.Contents of the [filename]#bower_components# Directory\n----\napp-layout\nfont-roboto\niron-a11y-announcer\niron-a11y-keys-behavior\niron-autogrow-textarea\niron-behaviors\niron-checked-element-behavior\niron-dropdown\niron-fit-behavior\niron-flex-layout\niron-form-element-behavior\niron-icon\niron-icons\niron-iconset-svg\niron-input\niron-media-query\niron-meta\niron-overlay-behavior\niron-resizable-behavior\niron-scroll-target-behavior\niron-selector\niron-validatable-behavior\nneon-animation\npaper-behaviors\npaper-button\npaper-icon-button\npaper-input\npaper-material\npaper-ripple\npaper-styles\npolymer\nvaadin-date-picker\nvaadin-grid\nweb-animations-js\nwebcomponentsjs\n----\n\n[TIP]\n.Ignore the Bower Dependencies in a Version Control System\n====\nIt is usually a good practice to exclude external dependencies from a version control system. In this tip, we assume that you plan to use Git, though the same principle applies to any version control system.\n\nThe Angular 2 QuickStart project already contains a [filename]#.gitignore# file, that will exclude the [filename]#node_modules# directory with the npm dependencies.\n\nYou can add the following line to the [filename]#.gitignore# file to prevent the Bower dependencies from being tracked by Git in future:\n\n[source]\n----\nbower_components\n----\n====\n\n=== The npm Dependency\n\nAlongside with Bower dependencies, we also need to add one npm dependency to the project. The `@vaadin/angular2-polymer` package adds support for Polymer elements in Angular 2 component templates. Run the following command to install the package and save the dependency in [filename]#package.json# at the same time:\n\n[subs=\"normal\"]\n----\n[prompt]#$# [command]#npm# install @vaadin/angular2-polymer --save\n----\n\n"
  },
  {
    "path": "docs/tutorial/hero-editor.adoc",
    "content": "[[vaadin-angular2-polymer.tutorial.hero-editor]]\n== Hero Editor and Routing\n\nPreviously we added the heroes list in our application. In this step, we are going to add the editing feature. After that, the user should be able to navigate to the hero details by clicking a row in the heroes list, edit the details, and get back to the list with the back button in the toolbar.\n\n[NOTE]\n.Some Parts are Explained in the Tour of Heroes\n====\nThis step partly follows the Angular 2 Tour of Heroes Tutorial. Therefore, we skip explaining the parts of the code that are similar both in this tutorial and in the Tour of Heroes, such as the routing requirements and configuration.\n\nSee https://angular.io/docs/ts/latest/tutorial/[Tour of Heroes] for a detailed explaination of the similar parts.\n====\n\n=== Add the Hero Get Method to the Service\n\nLet us add a [methodname]#getHero(id: number)# method to the [classname]#HeroService#. It can be used to retrive a single hero in our application components. Open the [filename]#app/hero.service.ts# file and change its contents to the following code:\n\n[source,typescript]\n.[filename]#app/hero.service.ts#\n----\nimport { Injectable } from '@angular/core';\n\nimport { Hero } from './hero';\nimport { HEROES } from './mock-heroes';\n\n@Injectable()\nexport class HeroService {\n  getHeroes() {\n    return Promise.resolve(HEROES);\n  }\n\n  getHero(id: number) {\n    return Promise.resolve(HEROES).then(\n      heroes => heroes.filter(hero => hero.id === id)[0]\n    );\n  }\n}\n----\n\n=== Add the Hero Editor Component\n\nCreate a file named [filename]#app/hero-detail.component.ts# and put the following lines in it:\n\n[source,typescript]\n.[filename]#app/hero-detail.component.ts#\n----\nimport { Component, OnInit } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\nimport { Subscription } from 'rxjs/Subscription';\n\nimport { Hero } from './hero';\nimport { HeroService } from './hero.service';\n\n@Component({\n  selector: 'my-hero-detail',\n  template: `\n    <div *ngIf=\"hero\">\n      <paper-input label=\"Name\" [(value)]=\"hero.name\"></paper-input>\n      <vaadin-date-picker label=\"Birthday\" [(value)]=\"hero.birthday\"></vaadin-date-picker>\n    </div>\n  `,\n  styles: [`\n    :host {\n      display: block;\n      padding: 16px;\n    }\n  `]\n})\nexport class HeroDetailComponent implements OnInit {\n  hero: Hero;\n  private _routeParamsSubscription: Subscription;\n\n  constructor(\n    private _route: ActivatedRoute,\n    private _heroService: HeroService\n  ) { }\n\n  ngOnInit() {\n    this._routeParamsSubscription = this._route.params.subscribe(params => {\n      let id = +params['id']; // (+) converts string 'id' to a number\n      this._heroService.getHero(id).then(hero => this.hero = hero);\n    });\n  }\n\n  ngOnDestroy() {\n    this._routeParamsSubscription.unsubscribe();\n  }\n}\n----\n\nSo, here we have just created [classname]#HeroDetailComponent#, the heroes editor for our application. It uses [elementname]#paper-input# bound to the [propertyname]#hero.name# and [vaadinelement]#vaadin-date-picker# bound to the [propertyname]#hero.birthday# property through two-way data binding in both cases (that is, with the `[(value)]` syntax).\n\n[classname]#HeroDetailComponent# gets the hero ID from the [classname]#ActivatedRoute# params and calls [methodname]#getHero(id: number)# method from [classname]#HeroService# with the hero ID argument to retrive the hero object. After the retrieval, the hero object is assigned to the [propertyname]#hero# property of [classname]#HeroDetailComponent#.\n\nSince we use two-way binding, the [propertyname]#hero.name# and the [propertyname]#hero.birthday# sub-property values are automatically displayed in the corresponding elements. When the user edits these values in the elements, the sub-properties of the [propertyname]#hero# property are updated automatically.\n\n[IMPORTANT]\n.Use ngIf When Loading Content\n====\nThe hero object is retrived asynchronously after the component initialization. At this time when the retrieval starts, the component template is already rendered, but the [propertyname]#hero# is not loaded yet, so we can not use [propertyname]#hero.name# and [propertyname]#hero.birthday# sub-properties. Using them at this time would result in errors.\n\nThat is why we wrap the [elementname]#paper-input# and the [vaadinelement]#vaadin-date-picker# elements with `<div *ngIf=\"hero\"></div>` in the component template. The `ngIf` structural directive not only hides the content, but also stops the hidden part of the template from being evaluated and rendered. This effectively prevents errors of accessing non-existant sub-properties during the loading.\n====\n\nUnlike with Vaadin Grid in the heroes list, we do not want our editor contents to touch the edges of the browser window. It is nice to have some spacing around them. For that reason, we add `display: block;` and `padding: 16px;` rules in the styles section of our component metadata.\n\n=== Add Routing\n\nThe Angular 2 Component Router uses `history.pushState` API for navigation. This requires us to declare the base `href` for the main document. Add this line to the [filename]#index.html# file in the project root just after the [elementname]#head# opening tag:\n\n[source,html]\n.[filename]#index.html#\n----\n...\n<head>\n  <base href=\"/\">\n  ...\n</head>\n...\n----\n\nNext we create a router configuration file. Add [filename]#app/app.routing.ts# with the following contents:\n\n[source,typescript]\n.[filename]#app/app.routing.ts#\n----\nimport { Routes, RouterModule } from '@angular/router';\n\nimport { HeroesComponent } from './heroes.component';\nimport { HeroDetailComponent } from './hero-detail.component';\n\nconst appRoutes: Routes = [\n  {\n    path: '',\n    redirectTo: '/heroes',\n    pathMatch: 'full',\n  },\n  {\n    path: 'heroes',\n    children: [\n      {\n        path: '',\n        component: HeroesComponent,\n        data: {\n          title: 'All heroes',\n          root: true\n        }\n      },\n      {\n        path: ':id',\n        component: HeroDetailComponent,\n        data: {\n          title: 'Hero detail'\n        }\n      }\n    ]\n  }\n];\n\nexport const appRoutingProviders: any[] = [\n\n];\n\nexport const routing = RouterModule.forRoot(appRoutes);\n----\n\nThe routes list starts with the default route, which corresponds to the empty path. This route is used when no path is specified, and in our configuration, it redirects users to the `/heroes` path to open the heroes list by default.\n\nAfter that in our routing configuration, there are two routes grouped as children under the `/heroes` path: one route is for the heroes list ([classname]#HeroesComponent#) and another is for the hero detail editor ([classname]#HeroDetailComponent#). Note, that the second route path features the `:id` parameter. It is received inside [classname]#HeroDetailComponent# and used there to retrive the hero object, as described above in this step.\n\nNext, add a router outlet, the back button, and the navigation reaction to the [classname]#AppComponent#. Edit [filename]#app/app.component.ts# to contain the code below:\n\n[source,typescript]\n.[filename]#app/app.component.ts#\n----\nimport { Component, OnInit } from '@angular/core';\nimport { ActivatedRoute, Router, NavigationEnd } from '@angular/router';\nimport { Subscription } from 'rxjs/Subscription';\n\n@Component({\n  selector: 'my-app',\n  template: `\n    <app-header-layout has-scrolling-region>\n      <app-header fixed>\n        <app-toolbar [class.raised]=\"isInChildView\">\n          <paper-icon-button icon=\"arrow-back\" *ngIf=\"isInChildView\" (click)=\"goBack()\"></paper-icon-button>\n          <div title spacer>{{title}}</div>\n        </app-toolbar>\n      </app-header>\n      <router-outlet></router-outlet>\n    </app-header-layout>\n  `,\n  styles: [`\n    app-toolbar {\n      background: var(--primary-color);\n      color: var(--dark-theme-text-color);\n    }\n\n    app-toolbar.raised {\n      @apply(--shadow-elevation-4dp);\n    }\n\n    paper-icon-button {\n      position: absolute;\n      top: 12px;\n      left: 8px;\n    }\n  `]\n})\nexport class AppComponent implements OnInit {\n  title = '';\n  isInChildView = false;\n  private _routerSubscription: Subscription;\n\n  constructor(private _route: ActivatedRoute,\n              private _router: Router) { }\n\n  ngOnInit() {\n    this._routerSubscription = this._router.events.subscribe(event => {\n      if (event instanceof NavigationEnd) {\n        let route = this._route.snapshot;\n        while (route.firstChild) {\n          route = route.firstChild;\n        }\n        this.title = route.data['title'];\n        this.isInChildView = !route.data['root'];\n      }\n    });\n  }\n\n  ngOnDestroy() {\n    this._routerSubscription.unsubscribe();\n  }\n\n  goBack() {\n    this._router.navigate(['/heroes']);\n  }\n}\n----\n\nThen we need to update the [classname]#AppModule#, to import and enable the hero detail editor and the routing configuration. Change the [filename]#app/app.module.ts# file contents as follows:\n\n[source,TypeScript]\n.[filename]#app/app.module.ts#\n----\nimport { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';\nimport { PolymerModule, PolymerElement } from '@vaadin/angular2-polymer';\n\nimport { AppComponent }  from './app.component';\nimport { HeroService } from './hero.service';\nimport { HeroesComponent } from './heroes.component';\nimport { HeroDetailComponent } from './hero-detail.component';\nimport { routing, appRoutingProviders } from './app.routing';\n\n@NgModule({\n  imports: [\n    PolymerModule,\n    routing\n  ],\n  declarations: [\n    AppComponent,\n    PolymerElement('app-header-layout'),\n    PolymerElement('app-header'),\n    PolymerElement('app-toolbar'),\n    PolymerElement('paper-icon-button'),\n    HeroesComponent,\n    PolymerElement('vaadin-grid'),\n    HeroDetailComponent,\n    PolymerElement('paper-input'),\n    PolymerElement('vaadin-date-picker')\n  ],\n  providers: [\n    HeroService,\n    appRoutingProviders\n  ],\n  bootstrap: [ AppComponent ],\n  schemas: [ CUSTOM_ELEMENTS_SCHEMA ]\n})\nexport class AppModule { }\n----\n\n=== Navigation to the Hero Details\n\nThe last feature to implement in this step is navigation from the heroes list to the hero details. Open [filename]#app/heroes.component.ts# and change it to contain the following code:\n\n[source,typescript]\n.[filename]#app/heroes.component.ts#\n----\nimport { Component, OnInit } from '@angular/core';\nimport { Router } from '@angular/router';\n\nimport { Hero } from './hero';\nimport { HeroService } from './hero.service';\n\n@Component({\n  selector: 'my-heroes',\n  template: `\n    <vaadin-grid [items]=\"heroes\" (selected-items-changed)=\"onSelectedItemsChanged($event)\">\n      <table>\n        <colgroup>\n          <col name=\"id\">\n          <col name=\"name\">\n          <col name=\"birthday\">\n        </colgroup>\n      </table>\n    </vaadin-grid>\n  `,\n  styles: [`\n    vaadin-grid {\n      height: 100%;\n    }\n  `]\n})\nexport class HeroesComponent implements OnInit {\n  heroes: Hero[];\n\n  constructor(\n    private _router: Router,\n    private _heroService: HeroService\n  ) { }\n\n  getHeroes() {\n    this._heroService.getHeroes().then(heroes => this.heroes = heroes);\n  }\n\n  ngOnInit() {\n    this.getHeroes();\n  }\n\n  onSelect(hero: Hero) {\n    this._router.navigate(['/heroes', hero.id]);\n  }\n\n  onSelectedItemsChanged(event: any) {\n    let selectedIndex: number = event.target.selection.selected()[0];\n    if (selectedIndex !== undefined) {\n      this.onSelect(this.heroes[selectedIndex]);\n    }\n  }\n}\n----\n\nNow when the user clicks a row inside the heroes list, [vaadinelement]#vaadin-grid# fires [eventname]#selected-items-changed# event. We bound the event to the [methodname]#onSelectedItemsChanged(event: any)# method of the [classname]#HeroesComponent#. In the listener method, we read the selected item index, find the selected [propertyname]#heroes# array item, and call [methodname]#onSelect(hero: Hero)#, which uses [classname]#Router# to navigate to the hero detail editor for the selected hero.\n\n=== Try It Out\n\nAll the changes for this step are done. Now launch your application again and try how the navigation works.\n\nAfter opening the application, click the first row in the heroes list. You should see the details view like in the following screenshot:\n\n[[figure.vaadin-angular2-polymer.tutorial.hero-detail]]\n.The hero detail view\nimage::img/hero-details.png[width=\"320\"]\n\nClick the back icon in the toolbar to navigate back to the heroes list. If you made any changes in the hero detail editor, they should be shown in the heroes list right away.\n\n=== Nice Touches in the AppComponent\n\nIn the folllowing, we go through and explain all the UX-related changes that were made to the [classname]#AppComponent# class earlier.\n\n==== Dynamic Toolbar Title\n\nWe added the [propertyname]#title# property to the [classname]#AppComponent# and bound it to the text content of `<div title spacer></div>` inside the toolbar in the template.\n\nInstead of a static title, the title is now updated dynamically. We subscribed to the [classname]#Router# events in [classname]#AppComponent# and used route data in the navigation event callback to get the title value specified for the current route. Each time after user opens the application or navigates inside, the [classname]#Router# [eventname]#NavigationEnd# event is dispatched, so that the [propertyname]#title# property will be updated.\n\n==== The Back Icon in the Toolbar\n\nWe added [elementname]#paper-icon-button# to have a back icon inside the [elementname]#app-toolbar# in the template. The icon has a click event binding, which calls the [methodname]#goBack()# method of the [classname]#AppComponent# class. In the method, we invoke the [methodname]#navigate# method of the [classname]#Router# to navigate back to the heroes list from the hero details.\n\nWhen the heroes list is shown, the back icon is useless, so we need to hide it. To achieve that, we added [propertyname]#isInChildView# property to [classname]#AppComponent#, which is updated from the route data in the navigation event callback. In the template, we added `*ngIf=\"isInChildView\"` for the [elementname]#paper-icon-button#.\n\nWe also added a few positioning style rules for the [elementname]#paper-icon-button#.\n\n==== Dynamic Toolbar Shadow\n\nTo make the toolbar look better, we made the application toolbar to have a shadow that is shown only for the hero detail view, but not for the heroes list view. For this purpose, we bound the `raised` class of the [elementname]#app-toolbar# to [propertyname]#isInChildView# property and added a style rule which applies the shadow mixin from [elementname]#paper-styles# to the [elementname]#app-toolbar# when it has the `raised` class.\n\n"
  },
  {
    "path": "docs/tutorial/introduction.adoc",
    "content": "[[vaadin-angular2-polymer.tutorial.introduction]]\n== Introduction\n\nThis tutorial explains how to use Polymer elements in Angular 2 applications with the help of the [literal]`https://github.com/vaadin/angular2-polymer[@vaadin/angular2-polymer]` directives.\n\nFor this purpose, we show how to create a staff management application similar to the https://angular.io/docs/ts/latest/tutorial/[Tour of Heroes] example. But unlike in the Angular 2 Tour of Heroes, instead of implementing the UI elements in place, we will use the ready-made UI elements that are built on top of the Web Components technology stack. The resulting application will have a nice-looking mobile-first Material designed UI.\n\nThe https://github.com/vaadin/angular2-polymer-quickstart[resulting application source] is published on GitHub.\n\n=== The Start Point\n\nThis tutorial is based on the https://angular.io/docs/ts/latest/quickstart.html[5 min QuickStart] for Angular 2 and the https://angular.io/docs/ts/latest/tutorial/[Angular 2 Tour of Heroes]. We start from the QuickStart application source.\n\nIf you are not yet familiar with Angular 2, we advice you to first walk through the Angular 2 QuickStart and the Tour of Heroes. In this tutorial, we skip the explanations that are already given in the Angular 2 tutorials.\n\n=== The Goal\n\nIn our heroes management application, there will be two UI screens. The first screen, as illustrated in <<figure.vaadin-angular2-polymer.tutorial.result-heroes-list>>, uses https://vaadin.com/elements/-/element/vaadin-grid[Vaadin Grid] to show a list of all the heroes.\n\n[[figure.vaadin-angular2-polymer.tutorial.result-heroes-list]]\n.The first screen with the list of heroes\nimage::img/heroes-list-default.png[width=\"320\"]\n\nBy clicking on a grid row, the user can open the hero details editor screen. It is made using [elementname]#paper-input# and [vaadinelement]#vaadin-date-picker#:\n\n[[figure.vaadin-angular2-polymer.tutorial.result-hero-detail]]\n.The second screen with the hero details view\nimage::img/hero-details.png[width=\"320\"]\n\nBoth screens have a context-sensitive toolbar at the top, containing the title and the optional back icon button.\n\n"
  },
  {
    "path": "docs/tutorial/layout.adoc",
    "content": "[[vaadin-angular2-polymer.tutorial.layout]]\n== Building the Application Layout with Paper Elements\n\nAfter the previous step, we have some Polymer elements imported in the [filename]#index.html# file of our application. In this step, we are going to use them to create an application layout with a toolbar in [classname]#AppComponent#.\n\n=== Updating SystemJS Configuration\n\nFor using Polymer elements in our Angular components, we need to import the [classname]#PolymerElement# directives from `@vaadin/angular2-polymer`. Therefore, we need to make the module loader (SystemJS, in our case) aware of how to load the `@vaadin/angular2-polymer` package.\n\nAngular 2 TypeScript QuickStart contains the SystemJS configuration in the [filename]#systemjs.config.js# file in the project root. Please edit this file and add a mapping for the `@vaadin` scope and the `@vaadin/angular2-polymer` package there as follows:\n\n[source,javascript]\n.[filename]#systemjs.config.js#\n----\n/**\n * System configuration for Angular 2 samples\n * Adjust as necessary for your application needs.\n */\n(function(global) {\n  System.config({\n    paths: {\n      // paths serve as alias\n      'npm:': 'node_modules/'\n    },\n    // map tells the System loader where to look for things\n    map: {\n      // our app is within the app folder\n      app: 'app',\n\n      // angular bundles\n      '@angular/core': 'npm:@angular/core/bundles/core.umd.js',\n      '@angular/common': 'npm:@angular/common/bundles/common.umd.js',\n      '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',\n      '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',\n      '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',\n      '@angular/http': 'npm:@angular/http/bundles/http.umd.js',\n      '@angular/router': 'npm:@angular/router/bundles/router.umd.js',\n      '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',\n\n      // other libraries\n      'rxjs':                       'npm:rxjs',\n      'angular2-in-memory-web-api': 'npm:angular2-in-memory-web-api',\n      '@vaadin/angular2-polymer':   'npm:@vaadin/angular2-polymer'\n    },\n    // packages tells the System loader how to load when no filename and/or no extension\n    packages: {\n      app: {\n        main: './main.js',\n        defaultExtension: 'js'\n      },\n      rxjs: {\n        defaultExtension: 'js'\n      },\n      'angular2-in-memory-web-api': {\n        main: './index.js',\n        defaultExtension: 'js'\n      },\n      '@vaadin/angular2-polymer': {\n        main: './index.js',\n        defaultExtension: 'js'\n      }\n    }\n  });\n})(this);\n----\n\n=== Extending AppModule with Polymer Elements\n\nNow we import the [classname]#PolymerElement# directives and attach them to the [classname]#AppModule#, in order to allow using the listed Polymer elements in this Angular module. Edit [filename]#app/app.module.ts#, append the [classname]#PolymerElement# directives to the [propertyname]#declarations# list, and add the [classname]#CUSTOM_ELEMENTS_SCHEMA#, as follows:\n\n[source,typescript]\n.[filename]#app/app.module.ts#\n----\nimport { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';\nimport { PolymerModule, PolymerElement } from '@vaadin/angular2-polymer';\n\nimport { AppComponent }  from './app.component';\n\n@NgModule({\n  imports: [ PolymerModule ],\n  declarations: [\n    AppComponent,\n    PolymerElement('app-header-layout'),\n    PolymerElement('app-header'),\n    PolymerElement('app-toolbar')\n  ],\n  bootstrap: [ AppComponent ],\n  schemas: [ CUSTOM_ELEMENTS_SCHEMA ]\n})\nexport class AppModule { }\n----\n\n=== AppComponent Changes\n\nOpen [filename]#app/app.component.ts# and replace the contents with the following code:\n\n[source,typescript]\n.[filename]#app/app.component.ts#\n----\nimport { Component } from '@angular/core';\n\n@Component({\n  selector: 'my-app',\n  template: `\n    <app-header-layout has-scrolling-region>\n      <app-header fixed>\n        <app-toolbar>\n          <div title spacer>All heroes</div>\n        </app-toolbar>\n      </app-header>\n      <div>My application content</div>\n    </app-header-layout>\n  `,\n  styles: [`\n    app-toolbar {\n      background: var(--primary-color);\n      color: var(--dark-theme-text-color);\n    }\n  `]\n})\nexport class AppComponent { }\n----\n\nSave the changes and launch the development server to see the results in your browser. After loading, your application should look as follows:\n\n[[figure.vaadin-angular2-polymer.tutorial.app-layout]]\n.The empty application layout\nimage::img/app-layout.png[width=\"320\"]\n\nNow your application has a layout made by using the [elementname]#app-header-layout#, [elementname]#app-header#, and [elementname]#app-toolbar# elements.\n\n=== Elements Used in This Step\n\n[elementname]#app-header-layout#:: The application layout that consists of the [elementname]#app-header# element and the main contents. In our case, it adds a scrollable container for the application contents as well.\n\n[elementname]#app-header#:: Acts as a header in the application layout. The header is fixed in our application.\n\n[elementname]#app-toolbar#:: Provides a toolbar wrapper.\n\n[NOTE]\n.The [elementname]#app-layout# Elements are Design-Agnostic\n====\nPolymer elements from the [elementname]#app-layout# set, including [elementname]#app-toolbar# that we use, are design-agnostic. They do not have Material Design look by default. We need to adjust [elementname]#app-toolbar# styles a bit.\n\nTherefore, we added color rules for the [elementname]#app-toolbar# in the styles of the [classname]#AppComponent#. We reuse the color values of default theme from [elementname]#paper-styles#.\n\nApart from the colors, it inherits the font family declared for the body. We have already declared our font settings for the body in the [filename]#index.html# file earlier during this step.\n====\n\n[IMPORTANT]\n.The [classname]#PolymerElement# Directives\n====\nIn order to enable all features of Polymer elements used inside your Angular component templates, remember to import [classname]#PolymerElement# in the module file and add `PolymerElement('element-name')` line for each Polymer element that you use to the [propertyname]#declarations# array of your Angular module metadata.\n====\n\n"
  },
  {
    "path": "docs/tutorial/list-heroes.adoc",
    "content": "[[vaadin-angular2-polymer.tutorial.list-heroes]]\n== List Heroes with Vaadin Grid\n\nIn the previous step, we added the application layout with [elementname]#app-layout# elements. Next, we are going add actual application content. Our plan is to use Vaadin Grid to list Heroes.\n\n[NOTE]\n.Some Parts are Explained in the Tour of Heroes\n====\nThis step partly follows the Angular 2 Tour of Heroes Tutorial. Therefore, we skip explaining the parts of the code that are similar in both this tutorial and the Tour of Heroes, such as the [classname]#Hero# class and the [classname]#HeroService#.\n\nSee https://angular.io/docs/ts/latest/tutorial/[Tour of Heroes] for a detailed explaination of such similar parts.\n====\n\n=== Hero Class\n\nLet us start by creating the [classname]#Hero# class. Create a [filename]#app/hero.ts# file with the following contents:\n\n[source,typescript]\n.[filename]#app/hero.ts#\n----\nexport class Hero {\n  id: number;\n  name: string;\n  birthday: string; // Using strings for simplicity\n}\n----\n\nUnlike in Angular 2 Tour of Heroes, in our application we store and expose the birthday of each hero for the user. Here we add the `birthday: string;` property to our [classname]#Hero# class.\n\n[NOTE]\n.Using Strings to Store Dates\n====\nWhy are we using the [classname]#string# type and not [classname]#Date# to store dates? There are two reasons:\n\n. The built-in JavaScript [classname]#Date# type is always stored as a timestamp, so it always contains the exact time information. This is not only redundant, but also harder to use than a plain string in case of storing just a date. It requires extra care about the correct time and timezone when storing the value and displaying it to the user; otherwise we might get incorrect dates because of timezone mismatches.\n\n. [vaadinelement]#vaadin-date-picker#, as well as native HTML5 `<input type=\"date\">`, gives the date value as an ISO-formatted [classname]#string#. To preserve the simplicity in our application, we also store dates as strings, avoiding conversions.\n====\n\n=== Mock Heroes Data\n\nCreate a [filename]#app/mock-heroes.ts# file with some heroes data:\n\n[source,typescript]\n.[filename]#app/mock-heroes.ts#\n----\nimport { Hero } from './hero';\n\nexport var HEROES: Hero[] = [\n  { \"id\": 11,  \"name\": \"Mr. Nice\",   \"birthday\": \"1980-01-11\" },\n  { \"id\": 12,  \"name\": \"Narco\",      \"birthday\": \"1980-01-12\" },\n  { \"id\": 13,  \"name\": \"Bombasto\",   \"birthday\": \"1980-01-13\" },\n  { \"id\": 14,  \"name\": \"Celeritas\",  \"birthday\": \"1980-01-14\" },\n  { \"id\": 15,  \"name\": \"Magneta\",    \"birthday\": \"1980-01-15\" },\n  { \"id\": 16,  \"name\": \"RubberMan\",  \"birthday\": \"1980-01-16\" },\n  { \"id\": 17,  \"name\": \"Dynama\",     \"birthday\": \"1980-01-17\" },\n  { \"id\": 18,  \"name\": \"Dr IQ\",      \"birthday\": \"1980-01-18\" },\n  { \"id\": 19,  \"name\": \"Magma\",      \"birthday\": \"1980-01-19\" },\n  { \"id\": 20,  \"name\": \"Tornado\",    \"birthday\": \"1980-01-20\" }\n];\n----\n\n=== The Hero Service\n\nWe also need a [classname]#HeroService# to be able to retrive the heroes list in our Angular application. Create a [filename]#app/hero.service.ts# file:\n\n[source,typescript]\n.[filename]#app/hero.service.ts#\n----\nimport { Injectable } from '@angular/core';\n\nimport { Hero } from './hero';\nimport { HEROES } from './mock-heroes';\n\n@Injectable()\nexport class HeroService {\n  getHeroes() {\n    return Promise.resolve(HEROES);\n  }\n}\n----\n\n=== Heroes List Component\n\nAdd the heroes list component file [filename]#app/heroes.component.ts# with the following code:\n\n[source,typescript]\n.[filename]#app/heroes.component.ts#\n----\nimport { Component, OnInit } from '@angular/core';\n\nimport { Hero } from './hero';\nimport { HeroService } from './hero.service';\n\n@Component({\n  selector: 'my-heroes',\n  template: `\n    <vaadin-grid [items]=\"heroes\">\n      <table>\n        <colgroup>\n          <col name=\"id\">\n          <col name=\"name\">\n          <col name=\"birthday\">\n        </colgroup>\n      </table>\n    </vaadin-grid>\n  `,\n  styles: [`\n    vaadin-grid {\n      height: 100%;\n    }\n  `]\n})\nexport class HeroesComponent implements OnInit {\n  heroes: Hero[];\n\n  constructor(private _heroService: HeroService) { }\n\n  getHeroes() {\n    this._heroService.getHeroes().then(heroes => this.heroes = heroes);\n  }\n\n  ngOnInit() {\n    this.getHeroes();\n  }\n}\n----\n\nHere in the [classname]#HeroesComponent#, we have the [vaadinelement]#vaadin-grid# element in the template. In the styles, we have a `height: 100%;` rule for the [vaadinelement]#vaadin-grid# element. In the template, there are three columns inside the [vaadinelement]#vaadin-grid#, specified with their corresponding item property names.\n\nAlso in the template, the [propertyname]#items# property of the [vaadinelement]#vaadin-grid# is bound to the [propertyname]#heroes# array property of [classname]#HeroesComponent#. At the same time, we import and use [classname]#HeroService# to get the list of heroes and assign the [propertyname]#heroes# property. Data binding of the Angular component takes care of updating the [propertyname]#items# property of [vaadinelement]#vaadin-grid# with the list of heroes for us.\n\n=== Displaying Heroes List\n\nNext, we need to edit the [filename]#app/app.component.ts# file to display the heroes list in the [classname]#AppComponent# template. Replace `<div>My application content</div>` with `<my-heroes></my-heroes>`, as in the following code:\n\n[source,typescript]\n.[filename]#app/app.component.ts#\n----\nimport { Component } from '@angular/core';\n\n@Component({\n  selector: 'my-app',\n  template: `\n    <app-header-layout has-scrolling-region>\n      <app-header fixed>\n        <app-toolbar>\n          <div title spacer>All heroes</div>\n        </app-toolbar>\n      </app-header>\n      <my-heroes></my-heroes>\n    </app-header-layout>\n  `,\n  styles: [`\n    app-toolbar {\n      background: var(--primary-color);\n      color: var(--dark-theme-text-color);\n    }\n  `]\n})\nexport class AppComponent { }\n----\n\n=== Updating AppModule\n\nFinally in this step, we update the [classname]#AppModule#. Change the contents of [filename]#app/app.module.ts# as follows:\n\n[source,typescript]\n.[filename]#app/app.module.ts#\n----\nimport { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';\nimport { PolymerModule, PolymerElement } from '@vaadin/angular2-polymer';\n\nimport { AppComponent }  from './app.component';\nimport { HeroService } from './hero.service';\nimport { HeroesComponent } from './heroes.component';\n\n@NgModule({\n  imports: [ PolymerModule ],\n  declarations: [\n    AppComponent,\n    PolymerElement('app-header-layout'),\n    PolymerElement('app-header'),\n    PolymerElement('app-toolbar'),\n    PolymerElement('paper-icon-button'),\n    HeroesComponent,\n    PolymerElement('vaadin-grid')\n  ],\n  providers: [ HeroService ],\n  bootstrap: [ AppComponent ],\n  schemas: [ CUSTOM_ELEMENTS_SCHEMA ]\n})\nexport class AppModule { }\n----\n\nWe did the following changes in the [filename]#app/app.module.ts# file:\n\n* We imported [classname]#HeroService# and listed it in [propertyname]#providers#\n* We also imported [classname]#HeroesComponent#, and appended it the [propertyname]#declarations#, alongside with the [classname]#PolymerElement# directives for the [vaadinelement]#vaadin-grid# element, which is used in the [classname]#HeroesComponent# template.\n\nNow it is again time to look in the browser window, to see how the heroes list looks in our application. It should look about as in <<figure.vaadin-angular2-polymer.tutorial.heroes-list>>:\n\n[[figure.vaadin-angular2-polymer.tutorial.heroes-list]]\n.The list of heroes\nimage::img/heroes-list.png[width=\"320\"]\n\n"
  },
  {
    "path": "docs/tutorial/polymer.adoc",
    "content": "[[vaadin-angular2-polymer.tutorial.polymer]]\n== Adding Polymer Elements to Our Application\n\nIn the previous step, we downloaded the needed elements to the [filename]#bower_components# directory. Next, we will import these elements in our application.\n\nIn your project root, edit the [filename]#index.html# file and replace the contents with the following lines:\n\n[source,html]\n----\n<!DOCTYPE html>\n<html>\n  <head>\n    <title>Angular 2 with Polymer Elements QuickStart</title>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n\n    <!-- Polyfills -->\n    <script src=\"bower_components/webcomponentsjs/webcomponents.min.js\"></script>\n    <script src=\"node_modules/core-js/client/shim.min.js\"></script>\n\n    <script>\n      window.Polymer = {\n        dom: 'shadow'\n      };\n    </script>\n\n    <!-- JavaScript libraries -->\n    <script src=\"node_modules/zone.js/dist/zone.js\"></script>\n    <script src=\"node_modules/reflect-metadata/Reflect.js\"></script>\n    <script src=\"node_modules/systemjs/dist/system.src.js\"></script>\n\n    <!-- Styles -->\n    <link rel=\"import\" href=\"bower_components/iron-flex-layout/iron-flex-layout.html\">\n    <link rel=\"import\" href=\"bower_components/paper-styles/color.html\">\n    <link rel=\"import\" href=\"bower_components/paper-styles/default-theme.html\">\n    <link rel=\"import\" href=\"bower_components/paper-styles/typography.html\">\n    <link rel=\"import\" href=\"bower_components/paper-styles/shadow.html\">\n    <style is=\"custom-style\">\n      body {\n        @apply(--layout-fullbleed);\n        @apply(--paper-font-body1);\n        background: var(--primary-background-color);\n        color: var(--primary-text-color);\n      }\n    </style>\n\n    <!-- Polymer Elements -->\n    <link rel=\"import\" href=\"bower_components/iron-icons/iron-icons.html\">\n    <link rel=\"import\" href=\"bower_components/app-layout/app-layout.html\">\n    <link rel=\"import\" href=\"bower_components/paper-icon-button/paper-icon-button.html\">\n    <link rel=\"import\" href=\"bower_components/paper-input/paper-input.html\">\n    <link rel=\"import\" href=\"bower_components/vaadin-grid/vaadin-grid.html\">\n    <link rel=\"import\" href=\"bower_components/vaadin-date-picker/vaadin-date-picker.html\">\n\n    <!-- SystemJS Configuration -->\n    <script src=\"systemjs.config.js\"></script>\n    <script>\n      document.addEventListener('WebComponentsReady', function() {\n        System.import('app').catch(function(err){ console.error(err); });\n      });\n    </script>\n  </head>\n\n  <body>\n    <my-app>Loading...</my-app>\n  </body>\n</html>\n----\n\nWe have made the following important changes to the original Angular 2 tutorial file:\n\nThe Doctype Declaration::\nWe added the `<!DOCTYPE html>` declaration in the first line of the HTML file. It switches document to use the Standards mode, as required by the internals of [vaadinelement]#vaadin-grid#.\n\nThe Web Components Polyfill::\nThe technology stack behind Web Components (namely, HTML Imports, Shadow DOM, and Custom Elements) is not yet natively supported in all browsers. Therefore, we added the [filename]#webcomponents.min.js# polyfill.\n\nConfigure Polymer DOM::\nBy default, Polymer uses shady DOM, which is not compatible with Angular. We created the Polymer global settings object and set it to use shadow DOM instead.\n\nImporting Polymer Elements::\nWe added imports of Polymer elements that we are going to use in our application to the head section of the [filename]#index.html# file.\n\nSystemJS App Import Change::\nIn some browsers, HTML Imports are loaded asynchronously, but we need them to be completely loaded before we import our Angular application. Hence we wrapped the `System.import('app')...` call in the listener callback of the [eventname]#WebComponentsReady# event, which is fired by the polyfill after all imports are loaded and elements have been registered.\n+\n[IMPORTANT]\n.Load Order\n====\nThe order in which the Polymer elements and the rest of the Angular application code are loaded does matter. It is required that the Polymer elements are loaded and registered before importing the Angular application. The `@vaadin/angular2-polymer` package strictly depends on that.\n====\n\nStyle Changes::\nPolymer elements come with nice built-in styles in the way of Material Design. Angular 2 also provides style encapsulation mechanisms for our application components.\n+\nTherefore, the global styles are not needed anymore. We removed the external [filename]#styles.css# stylesheet and replaced it with [elementname]#iron-flex-layout# and [elementname]#paper-styles# style mixin imports and an embedded global style rule for the body element.\n+\nThe body style rule is the only global style rule that remains in our application. The body element needs to be styled to take the full height of the browser viewport, and also to specify default font styles, line height, background, and text colors.\n+\n[TIP]\n====\nInstead of figuring out the exact rules and values for the body style, we import and reuse CSS mixins and CSS custom properties declared in [elementname]#iron-flex-layout# and [elementname]#paper-styles#.\n====\n+\n[IMPORTANT]\n====\nWhen using custom CSS mixins and custom CSS properties in your main document styles, you need to wrap your styles inside a `<style is=\"custom-style\"></style>` tag.\n\nSee the https://www.polymer-project.org/1.0/docs/devguide/styling.html[Styling section of the Polymer Developer Guide] for more information on styling Polymer elements and the document, custom CSS mixins and properties usage and limitations.\n====\n\nDelete the [filename]#styles.css# file from your project directory since it is no longer in use.\n\n[NOTE]\n.Duplicated Imports\n====\nThe HTML imports we have in the [filename]#index.html# file also import any possible dependencies. Imports having the same dependencies result in multiple imports of the same file. In such case, browsers prevent fetching the same file multiple times by checking the file location.\n\nSee http://w3c.github.io/webcomponents/spec/imports/#fetching-import[Fetching Import section of the HTML Imports Spec] for more detailed information about the fetching algorithm.\n====\n"
  },
  {
    "path": "docs/tutorial/wrap-up.adoc",
    "content": "[[vaadin-angular2-polymer.tutorial.wrap-up]]\n== Wrap Up\n\nYou have now finished all the tutorial steps and know how to use all the powers of Polymer elements in your Angular 2 applications.\n\nYou can see the https://github.com/vaadin/angular2-polymer-quickstart[resulting application source] on GitHub.\n\n=== Further Steps\n\nThere are several ways to improve the application you created in this tutorial. For example, you might want to add an explicit [guibutton]#Save# button to the hero detail editor and make the user able to intentionally submit or discard their changes. To do that, you can use the `ngForm` directive. See the https://angular.io/docs/ts/latest/guide/forms.html[Forms Chapter] in the Angular 2 Basics guide for the detailed instructions.\n\nIn the tutorial, we did not consider the topic of storing your application data. For simplicity, our application uses mock in-memory data and relies on data binding to make temporary changes, which are not saved anywhere. You might want to move the heroes data to a server and add some HTTP API calls in your application. See the Angular 2 https://angular.io/docs/ts/latest/guide/server-communication.html[Http Client] documentation to know how to do that.\n\nRead the https://www.polymer-project.org/1.0/[Polymer Project] website to know about other features that Polymer provides you with. There is also the https://www.polymer-project.org/1.0/start/[Getting Started] guide, where you can learn how to create your own elements and apps based on Polymer.\n\nDon’t forget to find out abouth other elements that you can use for building your applications from the https://vaadin.com/elements[Vaadin Elements] page and the https://elements.polymer-project.org/[Polymer Catalog].\n\n"
  },
  {
    "path": "docs/tutorial-index.adoc",
    "content": "---\ntitle: Tutorial\norder: 2\nlayout: page\nsubnav_auto_list_numbers: true\nsubnav:\n  - title: Introduction\n    href: '#vaadin-angular2-polymer.tutorial.creating-project'\n  - title: Creating Project\n    href: '#vaadin-angular2-polymer.tutorial.creating-project'\n  - title: Adding and Installing Dependencies\n    href: '#vaadin-angular2-polymer.tutorial.dependencies'\n  - title: Adding Polymer Elements to Our Application\n    href: '#vaadin-angular2-polymer.tutorial.polymer'\n  - title: Building the Application Layout with Paper Elements\n    href: '#vaadin-angular2-polymer.tutorial.layout'\n  - title: List Heroes with Vaadin Grid\n    href: '#vaadin-angular2-polymer.tutorial.list-heroes'\n  - title: Hero Editor and Routing\n    href: '#vaadin-angular2-polymer.tutorial.hero-editor'\n  - title: Wrap Up\n    href: '#vaadin-angular2-polymer.tutorial.wrap-up'\n---\n\n[[vaadin-angular2-polymer.tutorial]]\n= Angular 2 with Polymer Elements Tutorial\n:linkattrs:\n:experimental:\n:sectnums:\n:imagesdir: tutorial\n\ninclude::tutorial/introduction.adoc[]\n\ninclude::tutorial/creating-project.adoc[]\n\ninclude::tutorial/dependencies.adoc[]\n\ninclude::tutorial/polymer.adoc[]\n\ninclude::tutorial/layout.adoc[]\n\ninclude::tutorial/list-heroes.adoc[]\n\ninclude::tutorial/hero-editor.adoc[]\n\ninclude::tutorial/wrap-up.adoc[]\n\n"
  },
  {
    "path": "index.spec.ts",
    "content": "import './src/polymer-element.spec';\nimport './src/polymer-module.spec';\n"
  },
  {
    "path": "index.ts",
    "content": "export {PolymerElement} from './src/polymer-element';\nexport {PolymerModule} from './src/polymer-module';\n"
  },
  {
    "path": "karma.conf.js",
    "content": "// Karma configuration\n// Generated on Fri Mar 10 2017 15:33:36 GMT+0200 (EET)\n\nmodule.exports = function(config) {\n  config.set({\n\n    // base path that will be used to resolve all patterns (eg. files, exclude)\n    basePath: '',\n\n\n    // frameworks to use\n    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter\n    frameworks: ['jasmine'],\n\n\n    customLaunchers: {\n      ChromeHeadless: {\n        base: 'Chrome',\n        flags: [\n          '--no-sandbox',\n          // See https://chromium.googlesource.com/chromium/src/+/lkgr/headless/README.md\n          '--headless',\n          '--disable-gpu',\n          // Without a remote debugging port, Google Chrome exits immediately.\n          ' --remote-debugging-port=9222'\n        ]\n      }\n    },\n\n\n    // list of files / patterns to load in the browser\n    files: [\n      'bower_components/webcomponentsjs/webcomponents-lite.min.js',\n      'src/test-element.html',\n\n      'node_modules/systemjs/dist/system.src.js',\n      'node_modules/core-js/client/shim.js',\n      'node_modules/zone.js/dist/zone.js',\n      'node_modules/zone.js/dist/long-stack-trace-zone.js',\n      'node_modules/zone.js/dist/proxy.js',\n      'node_modules/zone.js/dist/sync-test.js',\n      'node_modules/zone.js/dist/jasmine-patch.js',\n      'node_modules/zone.js/dist/async-test.js',\n      'node_modules/zone.js/dist/fake-async-test.js',\n\n      'system.config.js',\n\n      { pattern: 'node_modules/**/*.js', included: false, watched: false },\n      { pattern: 'bower_components/**/*.+(html|css|js)', included: false, watched: false },\n      { pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false },\n      { pattern: 'node_modules/rxjs/**/*.js.map', included: false, watched: false },\n      { pattern: '**/*.js', included: false, watched: true },\n\n      // Serve the sources for debugging\n      { pattern: '**/*.ts', included: false, watched: false, served: true }\n    ],\n\n\n    // list of files to exclude\n    exclude: [\n    ],\n\n\n    // preprocess matching files before serving them to the browser\n    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor\n    preprocessors: {\n    },\n\n\n    // test results reporter to use\n    // possible values: 'dots', 'progress'\n    // available reporters: https://npmjs.org/browse/keyword/karma-reporter\n    reporters: ['progress'],\n\n\n    // web server port\n    port: 9876,\n\n\n    // enable / disable colors in the output (reporters and logs)\n    colors: true,\n\n\n    // level of logging\n    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG\n    logLevel: config.LOG_INFO,\n\n\n    // enable / disable watching file and executing tests whenever any file changes\n    autoWatch: true,\n\n\n    // start these browsers\n    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher\n    browsers: ['Chrome'],\n\n\n    // Continuous Integration mode\n    // if true, Karma captures browsers, runs the tests and exits\n    singleRun: false,\n\n    // Concurrency level\n    // how many browser should be started simultaneous\n    concurrency: Infinity\n  })\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"angular-polymer\",\n  \"version\": \"1.1.0\",\n  \"description\": \"Angular 2 support for Polymer elements\",\n  \"repository\": \"https://github.com/platosha/angular-polymer.git\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"bower\": \"bower\",\n    \"test\": \"tsc && npm run karma -- start --single-run --browsers ChromeHeadless\",\n    \"test:w\": \"tsc && concurrently \\\"npm run tsc:w\\\" \\\"npm run karma start\\\"\",\n    \"karma\": \"karma\",\n    \"tsc\": \"tsc\",\n    \"tsc:w\": \"tsc -w\",\n    \"prepublish\": \"tsc\",\n    \"lint\": \"tslint './**/*.ts' --exclude './node_modules/**'\",\n    \"fix-lint\": \"tslint './**/*.ts' --exclude './node_modules/**' --fix\"\n  },\n  \"typescript\": {\n    \"definition\": \"index.d.ts\"\n  },\n  \"author\": \"Vaadin Ltd\",\n  \"license\": \"Apache-2.0\",\n  \"peerDependencies\": {\n    \"@angular/common\": \"^2.0.0\",\n    \"@angular/core\": \"^2.0.0\",\n    \"@angular/forms\": \"^2.0.0\",\n    \"@angular/platform-browser\": \"^2.0.0\",\n    \"rxjs\": \"^5.0.0\",\n    \"zone.js\": \"^0.7.2\"\n  },\n  \"devDependencies\": {\n    \"@angular/compiler\": \"^2.0.0\",\n    \"@angular/platform-browser-dynamic\": \"^2.0.0\",\n    \"@types/core-js\": \"^0.9.34\",\n    \"@types/jasmine\": \"^2.5.36\",\n    \"@types/node\": \"^6.0.46\",\n    \"@types/selenium-webdriver\": \"^2.53.33\",\n    \"bower\": \"latest\",\n    \"concurrently\": \"^2.2.0\",\n    \"core-js\": \"^2.4.1\",\n    \"jasmine-core\": \"^2.4.1\",\n    \"karma\": \"^1.5.0\",\n    \"karma-chrome-launcher\": \"^2.0.0\",\n    \"karma-jasmine\": \"^1.1.0\",\n    \"live-server\": \"1.0.0\",\n    \"reflect-metadata\": \"^0.1.3\",\n    \"systemjs\": \"^0.19.27\",\n    \"tslint\": \"^4.4.2\",\n    \"typescript\": \"^2.1.6\"\n  }\n}\n"
  },
  {
    "path": "src/polymer-element.spec.ts",
    "content": "import {\n    async,\n    TestBed,\n    ComponentFixture\n} from '@angular/core/testing';\nimport {PolymerElement} from './polymer-element';\nimport {Component, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';\nimport {ReactiveFormsModule, FormGroup, FormControl} from '@angular/forms';\n\nconst Polymer: any = (<any>window).Polymer;\n\ndescribe('PolymerElement', () => {\n\n    beforeEach(async(() => {\n        TestBed.configureTestingModule({\n            imports: [\n                ReactiveFormsModule\n            ],\n            declarations: [\n                TestComponent,\n                TestComponentForm,\n                TestComponentCheckboxForm,\n                PolymerElement('test-element'),\n                PolymerElement('paper-checkbox')\n            ],\n            schemas: [CUSTOM_ELEMENTS_SCHEMA]\n        });\n        TestBed.compileComponents();\n    }));\n\n    let testElement: any;\n    let testComponent: TestComponent;\n    let fixture: ComponentFixture<any>;\n\n    function createTestComponent(type: any) {\n        fixture = TestBed.createComponent(type);\n        testElement = fixture.debugElement.query((el) => el.name === 'test-element').nativeElement;\n        testComponent = fixture.componentInstance;\n    }\n\n    it('is defined', () => {\n        expect(PolymerElement).toBeDefined();\n    });\n\n    it('is function', () => {\n        expect(typeof PolymerElement).toBe('function');\n    });\n\n    describe('Developer experience', () => {\n\n        it('should throw an error for non-registered elements', () => {\n            try {\n                PolymerElement('non-registered');\n            } catch (error) {\n                expect(error.message).toContain('element \"non-registered\" has not been registered');\n            }\n        });\n\n    });\n\n    describe('Two-way data binding', () => {\n\n        beforeEach(() => {\n            createTestComponent(TestComponent);\n        });\n\n        it('should have initial bound value', () => {\n            fixture.detectChanges();\n            expect(testElement.value).toEqual('foo');\n        });\n\n        it('should change value on bound value change', () => {\n            testComponent.value = 'bar';\n            fixture.detectChanges();\n            expect(testElement.value).toEqual('bar');\n        });\n\n        it('should change bound value on value change', () => {\n            testElement.value = 'bar';\n            expect(testComponent.value).toEqual('bar');\n        });\n\n        it('should reflect change to a nested value (object)', () => {\n            testComponent.nestedObject.value = 'foo';\n            fixture.detectChanges();\n            let nested = Polymer.dom(testElement.root).querySelector('#nested');\n            expect(nested.getAttribute('nested-object-value')).toEqual('foo');\n        });\n\n        it('should reflect change to a nested value (array)', () => {\n            testComponent.arrayObject.push('foo');\n            fixture.detectChanges();\n            let nested = Polymer.dom(testElement.root).querySelector('#nested');\n            expect(nested.getAttribute('array-object-value')).toEqual('foo');\n        });\n\n    });\n\n    describe('Form field', () => {\n\n        let form: any;\n\n        function formTests(): void {\n\n            describe('Initial state', () => {\n\n                it('should be initially pristine', () => {\n                    expect(testElement.classList.contains('ng-pristine')).toEqual(true);\n                });\n\n                it('should be initially untouched', () => {\n                    expect(testElement.classList.contains('ng-untouched')).toEqual(true);\n                });\n\n                it('should be invalid', () => {\n                    expect(testElement.classList.contains('ng-invalid')).toEqual(true);\n                });\n\n                it('should be an invalid form', () => {\n                    expect(form.valid).toEqual(false);\n                });\n\n                it('should not reflect invalid state to element initially', () => {\n                    expect(testElement.invalid).toBeFalsy();\n                });\n\n            });\n\n            describe('after value has changed', () => {\n\n                beforeEach(() => {\n                    testElement.value = 'qux';\n                    fixture.detectChanges();\n                });\n\n                it('should be dirty on value change', () => {\n                    expect(testElement.classList.contains('ng-dirty')).toEqual(true);\n                });\n\n                it('should be a valid form', () => {\n                    expect(form.valid).toEqual(true);\n                });\n\n                it('should have correct value', () => {\n                    expect(form.value.value).toEqual('qux');\n                });\n\n                it('should be valid', () => {\n                    expect(testElement.classList.contains('ng-valid')).toEqual(true);\n                });\n\n                it('should reflect invalid state to testElement when value changed', () => {\n                    testElement.value = '';\n                    fixture.detectChanges();\n                    expect(testElement.invalid).toEqual(true);\n                });\n\n            });\n\n        }\n\n        describe('Forms API', () => {\n\n            beforeEach(() => {\n                createTestComponent(TestComponentForm);\n                form = new FormGroup({value: new FormControl()});\n                fixture.debugElement.componentInstance.form = form;\n                fixture.detectChanges();\n            });\n\n            formTests();\n        });\n\n    });\n\n\n    describe('Checked Element inside Form', () => {\n\n        let form: FormGroup;\n        let checkedElement: any;\n\n        describe('initially false', () => {\n            beforeEach(() => {\n                createTestComponent(TestComponentCheckboxForm);\n                form = new FormGroup({value: new FormControl(false)});\n                fixture.debugElement.componentInstance.form = form;\n                fixture.detectChanges();\n                checkedElement = fixture.debugElement.query((el) => el.name === 'paper-checkbox').nativeElement;\n            });\n\n            it('should set default value', () => {\n                expect(checkedElement.checked).toEqual(false);\n            });\n\n            it('should set form value', () => {\n                checkedElement.checked = true;\n                expect(form.value.value).toEqual(true);\n            });\n        });\n\n        describe('initially true', () => {\n            beforeEach(() => {\n                createTestComponent(TestComponentCheckboxForm);\n                form = new FormGroup({value: new FormControl(true)});\n                fixture.debugElement.componentInstance.form = form;\n                fixture.detectChanges();\n                checkedElement = fixture.debugElement.query((el) => el.name === 'paper-checkbox').nativeElement;\n            });\n\n            it('should set default value', () => {\n                expect(checkedElement.checked).toEqual(true);\n            });\n\n            it('should set form value', () => {\n                checkedElement.checked = false;\n                expect(form.value.value).toEqual(false);\n            });\n        });\n    });\n});\n\n\n@Component({\n    template: `<test-element [(value)]=\"value\" [(nestedObject)]=\"nestedObject\" [(arrayObject)]=\"arrayObject\"></test-element>`\n})\nclass TestComponent {\n    value = 'foo';\n    nestedObject = {value: undefined};\n    arrayObject = [];\n    barVisible = false;\n}\n\n@Component({\n    template: `\n    <form [formGroup]=\"form\">\n      <test-element formControlName=\"value\" required></test-element>\n    </form>`\n})\nclass TestComponentForm {\n    value = 'foo';\n}\n\n@Component({\n    // test-element added to make the global test setup not crash.\n    template: `\n    <form [formGroup]=\"form\">\n      <paper-checkbox formControlName=\"value\"></paper-checkbox>\n    </form>\n    <test-element></test-element>`\n})\nclass TestComponentCheckboxForm {\n}\n"
  },
  {
    "path": "src/polymer-element.ts",
    "content": "import {\n    Injector,\n    Directive,\n    ElementRef,\n    EventEmitter,\n    forwardRef,\n    Renderer,\n    NgZone,\n    KeyValueDiffers,\n    IterableDiffers,\n    DefaultIterableDiffer\n} from '@angular/core';\nimport {FormControlName, NG_VALUE_ACCESSOR} from '@angular/forms';\n\nconst Polymer: any = (<any>window).Polymer;\n\n\nexport function PolymerElement(name: string): any[] {\n    const propertiesWithNotify: Array<any> = [];\n    const arrayAndObjectProperties: Array<any> = [];\n\n    const proto: any = Object.getPrototypeOf(document.createElement(name));\n    if (proto.is !== name) {\n        throw new Error(`The Polymer element \"${name}\" has not been registered. Please check that the element is imported correctly.`);\n    }\n    const isFormElement: boolean = Polymer && Polymer.IronFormElementBehavior && proto.behaviors.indexOf(Polymer.IronFormElementBehavior) > -1;\n    const isCheckedElement: boolean = Polymer && Polymer.IronCheckedElementBehaviorImpl && proto.behaviors.indexOf(Polymer.IronCheckedElementBehaviorImpl) > -1;\n    proto.behaviors.forEach((behavior: any) => configureProperties(behavior.properties));\n    configureProperties(proto.properties);\n\n    function configureProperties(properties: any) {\n        if (properties) {\n            Object.getOwnPropertyNames(properties)\n                .filter(name => name.indexOf('_') !== 0)\n                .forEach(name => configureProperty(name, properties));\n        }\n    }\n\n    function configureProperty(name: string, properties: any) {\n        let info = properties[name];\n        if (typeof info === 'function') {\n            info = {\n                type: info\n            };\n        }\n\n        if (info.type && !info.readOnly && (info.type === Object || info.type === Array)) {\n            arrayAndObjectProperties.push(name);\n        }\n\n        if (info && info.notify) {\n            propertiesWithNotify.push(name);\n        }\n    }\n\n    const eventNameForProperty = (property: string) => `${property}Change`;\n\n    const changeEventsAdapterDirective = Directive({\n        selector: name,\n        outputs: propertiesWithNotify.map(eventNameForProperty),\n        host: propertiesWithNotify.reduce((hostBindings, property) => {\n            hostBindings[`(${Polymer.CaseMap.camelToDashCase(property)}-changed)`] = `_emitChangeEvent('${property}', $event);`;\n            return hostBindings;\n        }, {})\n    }).Class({\n        constructor: function () {\n            propertiesWithNotify\n                .forEach(property => this[eventNameForProperty(property)] = new EventEmitter<any>(false));\n        },\n\n        _emitChangeEvent(property: string, event: any) {\n            // Event is a notification for a sub-property when `path` exists and the\n            // event.detail.value holds a value for a sub-property.\n\n            // For sub-property changes we don't need to explicitly emit events,\n            // since all interested parties are bound to the same object and Angular\n            // takes care of updating sub-property bindings on changes.\n            if (!event.detail.path) {\n                this[eventNameForProperty(property)].emit(event.detail.value);\n            }\n        }\n    });\n\n    const validationDirective = Directive({\n        selector: name\n    }).Class({\n        constructor: [ElementRef, Injector, function (el: ElementRef, injector: Injector) {\n            this._element = el.nativeElement;\n            this._injector = injector;\n        }],\n\n        ngDoCheck: function () {\n            const control = this._injector.get(FormControlName, null);\n\n            if (control) {\n                this._element.invalid = !control.pristine && !control.valid;\n            }\n        }\n    });\n\n    const formElementDirective: any = Directive({\n        selector: name,\n        providers: [\n            {\n                provide: NG_VALUE_ACCESSOR,\n                useExisting: forwardRef(() => formElementDirective),\n                multi: true\n            }\n        ],\n        host: (isCheckedElement ? {'(checkedChange)': 'onValueChanged($event)'} : {'(valueChange)': 'onValueChanged($event)'})\n    }).Class({\n        constructor: [Renderer, ElementRef, function (renderer: Renderer, el: ElementRef) {\n            this._renderer = renderer;\n            this._element = el.nativeElement;\n            this._element.addEventListener('blur', () => this.onTouched(), true);\n        }],\n\n        onChange: (_: any) => {\n        },\n        onTouched: () => {\n        },\n\n        writeValue: function (value: any): void {\n            this._renderer.setElementProperty(this._element, (isCheckedElement ? 'checked' : 'value'), value);\n        },\n\n        registerOnChange: function (fn: (_: any) => void): void {\n            this.onChange = fn;\n        },\n        registerOnTouched: function (fn: () => void): void {\n            this.onTouched = fn;\n        },\n\n        onValueChanged: function (value: any) {\n            this.onChange(value);\n        }\n    });\n\n    const notifyForDiffersDirective = Directive({\n        selector: name,\n        inputs: arrayAndObjectProperties,\n        host: arrayAndObjectProperties.reduce((hostBindings, property) => {\n            hostBindings[`(${Polymer.CaseMap.camelToDashCase(property)}-changed)`] = `_setValueFromElement('${property}', $event);`;\n            return hostBindings;\n        }, {})\n\n    }).Class({\n\n        constructor: [ElementRef, IterableDiffers, KeyValueDiffers, function (el: ElementRef, iterableDiffers: IterableDiffers, keyValueDiffers: KeyValueDiffers) {\n            this._element = el.nativeElement;\n            this._iterableDiffers = iterableDiffers;\n            this._keyValueDiffers = keyValueDiffers;\n            this._differs = {};\n            this._arrayDiffs = {};\n        }],\n\n        ngOnInit() {\n            let elm = (<any>this)._element;\n            // In case the element has a default value and the directive doesn't have any value set for a property,\n            // we need to make sure the element value is set to the directive.\n            arrayAndObjectProperties.filter(property => elm[property] && !this[property])\n                .forEach(property => {\n                    this[property] = elm[property];\n                });\n        },\n\n        _setValueFromElement(property: string, event: Event) {\n            // Properties in this directive need to be kept synced manually with the element properties.\n            // Don't use event.detail.value here because it might contain changes for a sub-property.\n            let target: any = event.target;\n            if (this[property] !== target[property]) {\n                this[property] = target[property];\n                (<any>this)._differs[property] = this._createDiffer(this[property]);\n            }\n        },\n\n        _createDiffer(value: string) {\n            let differ = Array.isArray(value) ? (<any>this)._iterableDiffers.find(value).create(null) : (<any>this)._keyValueDiffers.find(value || {}).create(null);\n\n            // initial diff with the current value to make sure the differ is synced\n            // and doesn't report any outdated changes on the next ngDoCheck call.\n            differ.diff(value);\n\n            return differ;\n        },\n\n        _handleArrayDiffs(property: string, diff: any) {\n            if (diff) {\n                diff.forEachRemovedItem((item: any) => this._notifyArray(property, item.previousIndex));\n                diff.forEachAddedItem((item: any) => this._notifyArray(property, item.currentIndex));\n                diff.forEachMovedItem((item: any) => this._notifyArray(property, item.currentIndex));\n            }\n        },\n\n        _handleObjectDiffs(property: string, diff: any) {\n            if (diff) {\n                let notify = (item: any) => this._notifyPath(property + '.' + item.key, item.currentValue);\n                diff.forEachRemovedItem(notify);\n                diff.forEachAddedItem(notify);\n                diff.forEachChangedItem(notify);\n            }\n        },\n\n        _notifyArray(property: string, index: number) {\n            this._notifyPath(property + '.' + index, this[property][index]);\n        },\n\n        _notifyPath(path: string, value: any) {\n            (<any>this)._element.notifyPath(path, value);\n        },\n\n        ngDoCheck() {\n            arrayAndObjectProperties.forEach(property => {\n                let elm = (<any>this)._element;\n                let _differs = (<any>this)._differs;\n                if (elm[property] !== this[property]) {\n                    elm[property] = this[property];\n                    _differs[property] = this._createDiffer(this[property]);\n                } else if (_differs[property]) {\n\n                    // TODO: these differs won't pickup any changes in need properties like items[0].foo\n                    let diff = _differs[property].diff(this[property]);\n                    if (diff instanceof DefaultIterableDiffer) {\n                        this._handleArrayDiffs(property, diff);\n                    } else {\n                        this._handleObjectDiffs(property, diff);\n                    }\n                }\n            });\n        }\n    });\n\n    const reloadConfigurationDirective = Directive({\n        selector: name\n    }).Class({\n        constructor: [ElementRef, NgZone, function (el: ElementRef, zone: NgZone) {\n            el.nativeElement.async(() => {\n                if (el.nativeElement.isInitialized()) {\n                    // Reload outside of Angular to prevent unnecessary ngDoCheck calls\n                    zone.runOutsideAngular(() => {\n                        el.nativeElement.reloadConfiguration();\n                    });\n                }\n            });\n        }],\n    });\n\n    let directives = [changeEventsAdapterDirective, notifyForDiffersDirective];\n\n    if (isFormElement) {\n        directives.push(formElementDirective);\n        directives.push(validationDirective);\n    }\n\n    // If the element has isInitialized and reloadConfiguration methods (e.g., Charts)\n    if (typeof proto.isInitialized === 'function' &&\n        typeof proto.reloadConfiguration === 'function') {\n        directives.push(reloadConfigurationDirective);\n    }\n\n    return directives;\n}\n"
  },
  {
    "path": "src/polymer-module.spec.ts",
    "content": "import './renderer/polymer-renderer.spec';\n\nimport {RootRenderer} from '@angular/core';\nimport {NgModuleResolver} from '@angular/compiler';\nimport {PolymerRootRenderer} from './renderer/polymer-renderer';\n\nimport {POLYMER_RENDER_PROVIDERS, PolymerModule} from './polymer-module';\n\ndescribe('POLYMER_RENDER_PROVIDERS', () => {\n    it('contains PolymerRootRenderer', () => {\n        expect(POLYMER_RENDER_PROVIDERS).toContain(PolymerRootRenderer);\n    });\n\n    it('provides RootRenderer with PolymerRootRenderer', () => {\n        const item: any = POLYMER_RENDER_PROVIDERS.find((d: any) => d.provide === RootRenderer);\n        expect(item.useExisting).toBe(PolymerRootRenderer);\n    });\n});\n\ndescribe('PolymerModule', () => {\n    let resolver: NgModuleResolver;\n\n    beforeEach(() => {\n        resolver = new NgModuleResolver();\n    });\n\n    it('is NgModule', () => {\n        expect(resolver.isNgModule(PolymerModule)).toBe(true);\n    });\n\n    it('has POLYMER_RENDER_PROVIDERS', () => {\n        const metadata = resolver.resolve(PolymerModule);\n        expect(metadata.providers).toContain(POLYMER_RENDER_PROVIDERS);\n    });\n});\n"
  },
  {
    "path": "src/polymer-module.ts",
    "content": "import {NgModule, Provider, RootRenderer} from '@angular/core';\nimport {BrowserModule} from '@angular/platform-browser';\n\nimport {SharedCustomStylesHost} from './renderer/shared-custom-styles-host';\nimport {PolymerRootRenderer} from './renderer/polymer-renderer';\n\nexport const POLYMER_RENDER_PROVIDERS: Provider[] = [\n    SharedCustomStylesHost,\n    PolymerRootRenderer,\n    {provide: RootRenderer, useExisting: PolymerRootRenderer}\n];\n\n@NgModule({\n    exports: [BrowserModule],\n    providers: [POLYMER_RENDER_PROVIDERS]\n})\nexport class PolymerModule {\n}\n"
  },
  {
    "path": "src/renderer/polymer-renderer.spec.ts",
    "content": "import {async, TestBed, ComponentFixture} from '@angular/core/testing';\nimport {Component, Renderer, RootRenderer, CUSTOM_ELEMENTS_SCHEMA, ViewEncapsulation} from '@angular/core';\n\nimport {PolymerModule} from '../polymer-module';\nimport {DefaultPolymerRenderer, EmulatedEncapsulationPolymerRenderer, ShadowDomPolymerRenderer, PolymerRootRenderer} from './polymer-renderer';\n\nconst Polymer: any = (<any>window).Polymer;\n\n@Component({\n    template: `<test-element [(value)]=\"value\" [(nestedObject)]=\"nestedObject\" [(arrayObject)]=\"arrayObject\" boolean-value></test-element>`\n})\nclass RendererTestComponent {\n    constructor(public renderer: Renderer,\n                public rootRenderer: RootRenderer) {\n    }\n\n    value = 'foo';\n    nestedObject = {value: undefined};\n    arrayObject = [];\n    barVisible = false;\n}\n\n@Component({\n    template: `<p>encapsulation: none</p>`,\n    styles: [`p { order: 1; }`],\n    encapsulation: ViewEncapsulation.None\n})\nclass StyleEncapsulationNoneComponent {}\n\n@Component({\n    template: `<p>encapsulation: native</p>`,\n    styles: [`p { order: 2; }`],\n    encapsulation: ViewEncapsulation.Native\n})\nclass StyleEncapsulationNativeComponent {}\n\n@Component({\n    template: `<p>encapsulation: emulated</p>`,\n    styles: [`p { order: 3; }`],\n    encapsulation: ViewEncapsulation.Emulated\n})\nclass StyleEncapsulationEmulatedComponent {}\n\ndescribe('DefaultPolymerRenderer', () => {\n    beforeEach(async(() => {\n        TestBed.configureTestingModule({\n            imports: [PolymerModule],\n            declarations: [\n                RendererTestComponent,\n                StyleEncapsulationNoneComponent\n            ],\n            schemas: [CUSTOM_ELEMENTS_SCHEMA]\n        });\n        TestBed.compileComponents();\n    }));\n\n    let testElement: Element;\n    let testDomApi: any;\n    let renderer: DefaultPolymerRenderer;\n    let rootRenderer: PolymerRootRenderer;\n\n    beforeEach(() => {\n        const fixture = TestBed.createComponent(RendererTestComponent);\n        const testComponent = fixture.componentInstance;\n        testElement = fixture.nativeElement.firstElementChild;\n        renderer = <DefaultPolymerRenderer> testComponent.renderer;\n        testDomApi = Polymer.dom(testElement);\n        rootRenderer = <PolymerRootRenderer> testComponent.rootRenderer;\n    });\n\n    it('is in use', () => {\n        expect(renderer instanceof DefaultPolymerRenderer).toBe(true);\n    });\n\n    describe('selectRootElement method', () => {\n        let expectedRoot: Element;\n\n        beforeEach(() => {\n            expectedRoot = document.createElement('div');\n            expectedRoot.classList.add('test-root'); // should be selected as root\n            document.body.appendChild(expectedRoot);\n        });\n\n        afterEach(() => {\n            document.body.removeChild(expectedRoot);\n        });\n\n        it('respects shadow DOM boundaries', () => {\n            (<any> testElement).$.nested.classList.add('test-root'); // should not be selected as root\n\n            const testRoot = renderer.selectRootElement('.test-root');\n\n            expect(testRoot).toBe(expectedRoot);\n        });\n\n        it('clears previous content using Polymer.dom API', () => {\n            const spy = jasmine.createSpy('textContentSetterSpy');\n            const domApi: any = Polymer.dom(expectedRoot);\n            Object.defineProperty(domApi, 'textContent', {set: spy});\n\n            renderer.selectRootElement('.test-root');\n\n            expect(spy).toHaveBeenCalledWith('');\n        });\n    });\n\n    describe('tree manipulation', () => {\n        beforeEach(() => {\n            spyOn(testDomApi, 'appendChild').and.callThrough();\n            spyOn(testDomApi, 'insertBefore').and.callThrough();\n            spyOn(testDomApi, 'removeChild').and.callThrough();\n        });\n\n        it('implements createElement method', () => {\n            const el = renderer.createElement(testElement, 'foo-element');\n\n            expect(el instanceof Element).toBe(true);\n            expect(el.localName).toBe('foo-element');\n            expect(testDomApi.appendChild).toHaveBeenCalledWith(el);\n        });\n\n        it('implements createViewRoot method', () => {\n            const viewRoot = renderer.createViewRoot(testElement);\n            expect(viewRoot).toBe(testElement);\n        });\n\n        it('implements createTemplateAnchor method', () => {\n            const anchor = renderer.createTemplateAnchor(testElement);\n\n            expect(anchor instanceof Node).toBe(true);\n            expect(testDomApi.appendChild).toHaveBeenCalledWith(anchor);\n        });\n\n        it('implements createText method', () => {\n            const node = renderer.createText(testElement, 'foo');\n\n            expect(node instanceof Node).toBe(true);\n            expect(node.textContent).toBe('foo');\n            expect(testDomApi.appendChild).toHaveBeenCalledWith(node);\n        });\n\n        it('implements projectNodes method', () => {\n            const nodeFoo = document.createTextNode('foo');\n            const nodeBar = document.createTextNode('bar');\n\n            renderer.projectNodes(testElement, [nodeFoo, nodeBar]);\n\n            expect(Polymer.dom(nodeFoo).parentNode).toBe(testElement);\n            expect(Polymer.dom(nodeBar).parentNode).toBe(testElement);\n            expect(testDomApi.appendChild).toHaveBeenCalledWith(nodeFoo);\n            expect(testDomApi.appendChild).toHaveBeenCalledWith(nodeBar);\n        });\n\n        it('implements attachViewAfter method, target node is last child case', () => {\n            const nodeFoo = document.createTextNode('foo');\n            Polymer.dom(testElement).appendChild(nodeFoo);\n\n            const viewRootBaz = document.createTextNode('baz');\n            const viewRootQux = document.createTextNode('qux');\n\n            renderer.attachViewAfter(nodeFoo, [viewRootBaz, viewRootQux]);\n\n            expect(Polymer.dom(viewRootBaz).parentNode).toBe(testElement);\n            expect(Polymer.dom(viewRootQux).parentNode).toBe(testElement);\n            expect(testDomApi.appendChild).toHaveBeenCalledWith(viewRootBaz);\n            expect(testDomApi.appendChild).toHaveBeenCalledWith(viewRootQux);\n        });\n\n        it('implements attachViewAfter method, target node is non-last child case', () => {\n            const nodeFoo = document.createTextNode('foo');\n            const nodeBar = document.createTextNode('bar');\n            Polymer.dom(testElement).appendChild(nodeFoo);\n            Polymer.dom(testElement).appendChild(nodeBar);\n\n            const viewRootBaz = document.createTextNode('baz');\n            const viewRootQux = document.createTextNode('qux');\n\n            renderer.attachViewAfter(nodeFoo, [viewRootBaz, viewRootQux]);\n\n            expect(Polymer.dom(viewRootBaz).parentNode).toBe(testElement);\n            expect(Polymer.dom(viewRootQux).parentNode).toBe(testElement);\n            expect(testDomApi.insertBefore).toHaveBeenCalledWith(viewRootBaz, nodeBar);\n            expect(testDomApi.insertBefore).toHaveBeenCalledWith(viewRootQux, nodeBar);\n        });\n\n        it('implements detachView method', () => {\n            const nodeFoo = document.createTextNode('foo');\n            Polymer.dom(testElement).appendChild(nodeFoo);\n            const viewRootBaz = document.createTextNode('baz');\n            const viewRootQux = document.createTextNode('qux');\n            renderer.attachViewAfter(nodeFoo, [viewRootBaz, viewRootQux]);\n\n            renderer.detachView([viewRootBaz, viewRootQux]);\n\n            expect(Polymer.dom(viewRootBaz).parentNode).toBe(null);\n            expect(Polymer.dom(viewRootQux).parentNode).toBe(null);\n            expect(testDomApi.removeChild).toHaveBeenCalledWith(viewRootBaz);\n            expect(testDomApi.removeChild).toHaveBeenCalledWith(viewRootQux);\n        });\n    });\n\n    describe('listen', () => {\n        const callbacks = {\n            returnTrue: () => true,\n            returnFalse: () => false\n        };\n\n        let fakeClickEvent: CustomEvent;\n\n        beforeEach(() => {\n            spyOn(callbacks, 'returnTrue').and.callThrough();\n            spyOn(callbacks, 'returnFalse').and.callThrough();\n\n            fakeClickEvent = new CustomEvent('click', {\n                bubbles: true,\n                cancelable: true\n            });\n            spyOn(fakeClickEvent, 'preventDefault').and.callThrough();\n        });\n\n        it('implements listen method, with default action', () => {\n            renderer.listen(testElement, 'click', callbacks.returnTrue);\n\n            testElement.dispatchEvent(fakeClickEvent);\n            expect(callbacks.returnTrue).toHaveBeenCalledWith(fakeClickEvent);\n            expect(fakeClickEvent.returnValue).not.toBe(false);\n            expect(fakeClickEvent.preventDefault).not.toHaveBeenCalled();\n        });\n\n        it('implements listen method, without default action', () => {\n            renderer.listen(testElement, 'click', callbacks.returnFalse);\n\n            testElement.dispatchEvent(fakeClickEvent);\n            expect(callbacks.returnFalse).toHaveBeenCalledWith(fakeClickEvent);\n            expect(fakeClickEvent.returnValue).toBe(false);\n            expect(fakeClickEvent.preventDefault).toHaveBeenCalled();\n        });\n\n        it('implements listenGlobal method, with default action', () => {\n            renderer.listenGlobal('window', 'click', callbacks.returnTrue);\n\n            testElement.dispatchEvent(fakeClickEvent);\n            expect(callbacks.returnTrue).toHaveBeenCalledWith(fakeClickEvent);\n            expect(fakeClickEvent.returnValue).not.toBe(false);\n            expect(fakeClickEvent.preventDefault).not.toHaveBeenCalled();\n        });\n\n        it('implements listenGlobal method, without default action', () => {\n            renderer.listenGlobal('window', 'click', callbacks.returnFalse);\n\n            testElement.dispatchEvent(fakeClickEvent);\n            expect(callbacks.returnFalse).toHaveBeenCalledWith(fakeClickEvent);\n            expect(fakeClickEvent.returnValue).toBe(false);\n            expect(fakeClickEvent.preventDefault).toHaveBeenCalled();\n        });\n    });\n\n    it('implements setElementProperty method', () => {\n        renderer.setElementProperty(testElement, 'foo', 'bar');\n        expect(testElement['foo']).toBe('bar');\n    });\n\n    it('implements setElementAttribute method', () => {\n        spyOn(testDomApi, 'setAttribute');\n        spyOn(testDomApi, 'removeAttribute');\n\n        renderer.setElementAttribute(testElement, 'foo', 'bar');\n        renderer.setElementAttribute(testElement, 'baz', '');\n        renderer.setElementAttribute(testElement, 'qux', null);\n\n        expect(testDomApi.setAttribute).toHaveBeenCalledWith('foo', 'bar');\n        expect(testDomApi.setAttribute).toHaveBeenCalledWith('baz', '');\n        expect(testDomApi.removeAttribute).toHaveBeenCalledWith('qux');\n    });\n\n    it('implements setBindingDebugInfo method', () => {\n        spyOn(testDomApi, 'setAttribute');\n        spyOn(testDomApi, 'removeAttribute');\n\n        renderer.setBindingDebugInfo(testElement, 'foo', 'bar');\n        renderer.setBindingDebugInfo(testElement, 'baz', '');\n        renderer.setBindingDebugInfo(testElement, 'qux', null);\n\n        expect(testDomApi.setAttribute).toHaveBeenCalledWith('foo', 'bar');\n        expect(testDomApi.setAttribute).toHaveBeenCalledWith('baz', '');\n        expect(testDomApi.removeAttribute).toHaveBeenCalledWith('qux');\n    });\n\n    it('implements setElementClass method', () => {\n        spyOn(testDomApi.classList, 'add');\n        spyOn(testDomApi.classList, 'remove');\n\n        renderer.setElementClass(testElement, 'foo', true);\n        renderer.setElementClass(testElement, 'bar', false);\n\n        expect(testDomApi.classList.add).toHaveBeenCalledWith('foo');\n        expect(testDomApi.classList.remove).toHaveBeenCalledWith('bar');\n    });\n\n    it('implements setElementStyle method', () => {\n        const testHtmlElement = testElement as HTMLElement;\n        spyOn(testHtmlElement.style, 'setProperty');\n        spyOn(testHtmlElement.style, 'removeProperty');\n\n        renderer.setElementStyle(testHtmlElement, '--foo', 'none');\n        renderer.setElementStyle(testHtmlElement, '--bar', '');\n\n        expect(testHtmlElement.style.setProperty).toHaveBeenCalledWith('--foo', 'none');\n        expect(testHtmlElement.style.removeProperty).toHaveBeenCalledWith('--bar');\n    });\n\n    it('implements invokeElementMethod method', () => {\n        spyOn(testElement, (<any> 'click'));\n        const callArgs = [1, 'foo'];\n\n        renderer.invokeElementMethod(testElement, 'click', callArgs);\n\n        const calls = testElement['click'].calls.all();\n        expect(calls.length).toBe(1);\n        expect(calls[0].object).toBe(testElement);\n        expect(calls[0].args).toEqual(callArgs);\n        expect(calls[0].returnValue).toBeUndefined;\n    });\n\n    it('implements setText method', () => {\n        const textNode = renderer.createText(testElement, '');\n        renderer.setText(textNode, 'foo');\n        expect(textNode.nodeValue).toBe('foo');\n    });\n\n    it('implements animate method', () => {\n        spyOn(rootRenderer.animationDriver, 'animate');\n\n        const animateArgs = [\n            testElement,\n            {}, // startingStyles: any\n            [], // keyframes: any[]\n            0,  // duration: number\n            0,  // delay: number\n            '', // easing: string\n            []  // previousPlayers: AnimationPlayer[]\n        ];\n\n        renderer.animate.apply(renderer, animateArgs);\n\n        expect(\n            (<any>rootRenderer.animationDriver.animate).calls.mostRecent().args\n        ).toEqual(animateArgs);\n    });\n\n    describe('PolymerRootRenderer', () => {\n        it('is injectable', () => {\n            expect(rootRenderer instanceof PolymerRootRenderer).toBe(true);\n        });\n    });\n\n    describe('setElementAttribute', () => {\n        it('supports boolean attributes with no value', () => {\n            expect((<any> testElement).booleanValue).toBe(true);\n        });\n    });\n\n    describe('setElementProperty', () => {\n        it('updates the value of angular component and polymer component', () => {\n            (<any> testElement).value = 'Should change';\n            expect((<any> testElement).value).toBe('Should change');\n        });\n    });\n\n    it('applies component styles', () => {\n        const fixture = TestBed.createComponent(StyleEncapsulationNoneComponent);\n        const testElement = fixture.nativeElement.firstElementChild;\n        expect(window.getComputedStyle(testElement).order).toBe('1');\n    });\n});\n\ndescribe('ShadowDomPolymerRenderer', () => {\n    beforeEach(async(() => {\n        TestBed.configureTestingModule({\n            imports: [PolymerModule],\n            declarations: [\n                StyleEncapsulationNativeComponent\n            ],\n            schemas: [CUSTOM_ELEMENTS_SCHEMA]\n        });\n        TestBed.compileComponents();\n    }));\n\n    let testElement: Element;\n\n    beforeEach(() => {\n        const fixture = TestBed.createComponent(StyleEncapsulationNativeComponent);\n        testElement = fixture.nativeElement.shadowRoot.querySelector('p');\n    });\n\n    it('applies component styles', () => {\n        expect(window.getComputedStyle(testElement).order).toBe('2');\n    });\n\n    it('encapsulates component styles', () => {\n        const p = document.createElement('p');\n        document.body.appendChild(p);\n        expect(window.getComputedStyle(p).order).not.toBe('2');\n    });\n});\n\ndescribe('EmulatedEncapsulationPolymerRenderer', () => {\n    beforeEach(async(() => {\n        TestBed.configureTestingModule({\n            imports: [PolymerModule],\n            declarations: [\n                StyleEncapsulationEmulatedComponent\n            ],\n            schemas: [CUSTOM_ELEMENTS_SCHEMA]\n        });\n        TestBed.compileComponents();\n    }));\n\n    let testElement: Element;\n\n    beforeEach(() => {\n        const fixture = TestBed.createComponent(StyleEncapsulationEmulatedComponent);\n        testElement = fixture.nativeElement.firstElementChild;\n    });\n\n    it('applies component styles', () => {\n        expect(window.getComputedStyle(testElement).order).toBe('3');\n    });\n\n    it('encapsulates component styles', () => {\n        const p = document.createElement('p');\n        document.body.appendChild(p);\n        expect(window.getComputedStyle(p).order).not.toBe('3');\n        document.body.removeChild(p);\n    });\n});\n"
  },
  {
    "path": "src/renderer/polymer-renderer.ts",
    "content": "import {APP_ID, Injectable, Inject, Renderer, RootRenderer, RenderComponentType, AnimationPlayer, ViewEncapsulation} from '@angular/core';\nimport {EventManager, AnimationDriver, DOCUMENT} from '@angular/platform-browser';\nimport {SharedCustomStylesHost} from './shared-custom-styles-host';\n\nconst Polymer: any = (<any>window).Polymer;\n\nconst COMPONENT_REGEX = /%COMP%/g;\nconst COMPONENT_VARIABLE = '%COMP%';\nconst HOST_ATTR = `_nghost-${COMPONENT_VARIABLE}`;\nconst CONTENT_ATTR = `_ngcontent-${COMPONENT_VARIABLE}`;\n\nfunction flattenStyles(\n        styleShimId: string,\n        styles: Array<any|any[]>,\n        target: string[]): string[] {\n    for (let i = 0; i < styles.length; i++) {\n        let style = styles[i];\n        if (Array.isArray(style)) {\n            flattenStyles(styleShimId, style, target);\n        } else {\n            style = style.replace(COMPONENT_REGEX, styleShimId);\n            target.push(style);\n        }\n    }\n    return target;\n}\n\nfunction decoratePreventDefault(handler: Function) {\n    return (event: any) => {\n        const allowDefault = handler(event);\n        if (allowDefault === false) {\n            event.preventDefault();\n            event.returnValue = false;\n        }\n    };\n}\n\n/**\n * The polymer renderer takes care of supporting angular > 2.2 shady DOM\n *\n * The problem:\n * Starting from v2.2, Angular uses direct DOM rendering in browser. BrowserDomAdapter is not invoked by Renderer.\n * Therefore, changing the default BrowserDomAdapter to PolymerDomAdapter trick is not helpful anymore.\n * The issue breaks setting Light DOM for Polymer elements in Shady DOM mode of Polymer v1.0.\n *\n * The solution:\n * Instead of PolymerDomAdapter, we created the PolymerRenderer by implementing the Renderer interface.\n * The PolymerRenderer calls Polymer.dom APIs instead of DOM methods. In order to make Angular use the PolymerRenderer,\n * we need to define and export custom platforms, i.e., platformPolymer and platformPolymerDynamic.\n * In practice, developers will have to switch the imports in their main.ts files to use our custom Polymer platforms\n * instead of the default platformBrowser and platformBrowserDynamic.\n *\n * DefaultPolymerRenderer used for ViewEncapsulation.None, other style incapsulation modes are implemented in subclasses.\n */\nexport class DefaultPolymerRenderer implements Renderer {\n    constructor(\n            private _eventManager: EventManager,\n            private _animationDriver: AnimationDriver\n    ) { }\n\n    selectRootElement(selectorOrElement: string|Element): Element {\n        let el: Element;\n        if (typeof selectorOrElement === 'string') {\n            el = Polymer.dom(document).querySelector(selectorOrElement);\n            if (!el) {\n                throw new Error(`Root element for selector \"${selectorOrElement}\" was not found`);\n            }\n        } else {\n            el = selectorOrElement;\n        }\n        Polymer.dom(el).textContent = '';\n        return el;\n    }\n\n    createElement(parent: Element|DocumentFragment, name: string): Element {\n        const el: Element = document.createElement(name);\n        if (parent) {\n            Polymer.dom(parent).appendChild(el);\n        }\n        return el;\n    }\n\n    createViewRoot(hostElement: Element): Element|DocumentFragment {\n        return hostElement;\n    }\n\n    createTemplateAnchor(parent: Element|DocumentFragment): Element {\n        const anchor = document.createElement('template-anchor');\n        anchor.setAttribute('hidden', 'hidden');\n        if (parent) {\n            Polymer.dom(parent).appendChild(anchor);\n        }\n        return anchor;\n    }\n\n    createText(parent: Element|DocumentFragment, value: string): Text {\n        const node = document.createTextNode(value);\n        if (parent) {\n            Polymer.dom(parent).appendChild(node);\n        }\n        return node;\n    }\n\n    projectNodes(parent: Element|DocumentFragment, nodes: Node[]) {\n        if (!parent) return;\n        const parentDomApi: any = Polymer.dom(parent);\n        for (let i = 0; i < nodes.length; i++) {\n            parentDomApi.appendChild(nodes[i]);\n        }\n    }\n\n    attachViewAfter(node: Node, viewRootNodes: Node[]) {\n        const parent: Element = Polymer.dom(node).parentNode;\n        if (!parent || viewRootNodes.length === 0) return;\n        const parentDomApi = Polymer.dom(parent);\n        const nextSibling: Node = Polymer.dom(node).nextSibling;\n        if (nextSibling) {\n            for (let i = 0; i < viewRootNodes.length; i++) {\n                parentDomApi.insertBefore(viewRootNodes[i], nextSibling);\n            }\n        } else {\n            for (let i = 0; i < viewRootNodes.length; i++) {\n                parentDomApi.appendChild(viewRootNodes[i]);\n            }\n        }\n    }\n\n    detachView(viewRootNodes: Node[]) {\n        for (let i = 0; i < viewRootNodes.length; i++) {\n            const node: Node = viewRootNodes[i];\n            const parent: Element = Polymer.dom(node).parentNode;\n            if (parent) {\n                Polymer.dom(parent).removeChild(node);\n            }\n        }\n    }\n\n    destroyView(hostElement: Element|DocumentFragment, viewAllNodes: Node[]) {\n    }\n\n    listen(renderElement: any, name: string, callback: Function): Function {\n        return this._eventManager.addEventListener(\n            renderElement,\n            name,\n            decoratePreventDefault(callback)\n        );\n    }\n\n    listenGlobal(target: string, name: string, callback: Function): Function {\n        return this._eventManager.addGlobalEventListener(\n            target,\n            name,\n            decoratePreventDefault(callback)\n        );\n    }\n\n    setElementProperty(renderElement: Element|DocumentFragment, propertyName: string, propertyValue: any): void {\n        (renderElement as any)[propertyName] = propertyValue;\n    }\n\n    setElementAttribute(renderElement: Element|DocumentFragment, attributeName: string, attributeValue: string): void {\n        if (attributeValue != null) {\n            Polymer.dom(renderElement).setAttribute(attributeName, attributeValue);\n        } else {\n            Polymer.dom(renderElement).removeAttribute(attributeName);\n        }\n    }\n\n    setBindingDebugInfo(renderElement: Element, propertyName: string, propertyValue: string): void {\n        this.setElementAttribute(renderElement, propertyName, propertyValue);\n    }\n\n    setElementClass(renderElement: Element, className: string, isAdd: boolean) {\n        if (isAdd) {\n            Polymer.dom(renderElement).classList.add(className);\n        } else {\n            Polymer.dom(renderElement).classList.remove(className);\n        }\n    }\n\n    setElementStyle(renderElement: HTMLElement, styleName: string, styleValue: string): void {\n        if (styleValue) {\n            renderElement.style.setProperty(styleName, styleValue);\n        } else {\n            renderElement.style.removeProperty(styleName);\n        }\n    }\n\n    invokeElementMethod(renderElement: Element, methodName: string, args: any[]) {\n        (renderElement as any)[methodName].apply(renderElement, args);\n    }\n\n    setText(renderNode: Text, text: string): void {\n        renderNode.nodeValue = text;\n    }\n\n    animate(element: any,\n            startingStyles: any,\n            keyframes: any[],\n            duration: number,\n            delay: number,\n            easing: string,\n            previousPlayers: AnimationPlayer[] = []): AnimationPlayer {\n        if (!element.domHost && document.body.contains(element)) {\n            return this._animationDriver.animate(element, startingStyles, keyframes, duration, delay, easing, previousPlayers);\n        }\n    }\n}\n\n/**\n * Polymer renderer for ViewEncapsulation.Emulated styles encapsulation mode (defaultmode)\n */\nexport class EmulatedEncapsulationPolymerRenderer extends DefaultPolymerRenderer {\n    private _contentAttr: string;\n    private _hostAttr: string;\n\n    constructor(\n            eventManager: EventManager,\n            animationDriver: AnimationDriver,\n            sharedCustomStylesHost: SharedCustomStylesHost,\n            componentType: RenderComponentType,\n            styleShimId: string\n    ) {\n        super(eventManager, animationDriver);\n        const styles = flattenStyles(styleShimId, componentType.styles, []);\n        sharedCustomStylesHost.addStyles(styles);\n        this._contentAttr = CONTENT_ATTR.replace(COMPONENT_REGEX, styleShimId);\n        this._hostAttr  = HOST_ATTR.replace(COMPONENT_REGEX, styleShimId);\n    }\n\n    createViewRoot(hostElement: Element): Element|DocumentFragment {\n        super.setElementAttribute(hostElement, this._hostAttr, '');\n        return hostElement;\n    }\n\n    createElement(parent: Element|DocumentFragment, name: string): Element {\n        const el: Element = super.createElement(parent, name);\n        super.setElementAttribute(el, this._contentAttr, '');\n        return el;\n    }\n}\n\n/**\n * Polymer renderer for ViewEncapsulation.Native styles encapsulation mode\n */\nexport class ShadowDomPolymerRenderer extends DefaultPolymerRenderer {\n    private _shadowRoot: DocumentFragment;\n    private _styles: string[];\n\n    constructor(\n            eventManager: EventManager,\n            animationDriver: AnimationDriver,\n            private sharedCustomStylesHost: SharedCustomStylesHost,\n            componentType: RenderComponentType,\n            styleShimId: string\n    ) {\n        super(eventManager, animationDriver);\n        this._styles = flattenStyles(styleShimId, componentType.styles, []);\n    }\n\n    createViewRoot(hostElement: Element): Element|DocumentFragment {\n        super.createViewRoot(hostElement);\n        this._shadowRoot = <DocumentFragment> (hostElement as any).createShadowRoot();\n        this.sharedCustomStylesHost.addHost(this._shadowRoot);\n        this._styles.forEach(style => {\n            const styleEl: Element = document.createElement('style');\n            styleEl.textContent = style;\n            this._shadowRoot.appendChild(styleEl);\n        });\n        return this._shadowRoot;\n    }\n\n    destroyView(hostElement: Element|DocumentFragment, viewAllNodes: Node[]) {\n        this.sharedCustomStylesHost.removeHost(this._shadowRoot);\n    }\n}\n\n@Injectable()\nexport class PolymerRootRenderer implements RootRenderer {\n    protected registeredComponents: Map<string, Renderer> = new Map<string, Renderer>();\n    private defaultRenderer: Renderer;\n\n    constructor(\n            @Inject(DOCUMENT) public document: any,\n            public eventManager: EventManager,\n            public sharedCustomStylesHost: SharedCustomStylesHost,\n            public animationDriver: AnimationDriver,\n            @Inject(APP_ID) public appId: string\n    ) {\n        this.defaultRenderer = new DefaultPolymerRenderer(eventManager, animationDriver);\n    }\n\n    renderComponent(componentType: RenderComponentType): Renderer {\n        const styleShimId = `${this.appId}-${componentType.id}`;\n        switch (componentType.encapsulation) {\n            case ViewEncapsulation.Emulated: {\n                let renderer = this.registeredComponents.get(componentType.id);\n                if (!renderer) {\n                    renderer = new EmulatedEncapsulationPolymerRenderer(\n                            this.eventManager,\n                            this.animationDriver,\n                            this.sharedCustomStylesHost,\n                            componentType,\n                            styleShimId\n                    );\n                    this.registeredComponents.set(componentType.id, renderer);\n                }\n                return renderer;\n            }\n            case ViewEncapsulation.Native: {\n                return new ShadowDomPolymerRenderer(\n                        this.eventManager,\n                        this.animationDriver,\n                        this.sharedCustomStylesHost,\n                        componentType,\n                        styleShimId\n                );\n            }\n            default: {\n                if (!this.registeredComponents.has(componentType.id)) {\n                    const styles = flattenStyles(styleShimId, componentType.styles, []);\n                    this.sharedCustomStylesHost.addStyles(styles);\n                    this.registeredComponents.set(componentType.id, this.defaultRenderer);\n                }\n                return this.defaultRenderer;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/renderer/shared-custom-styles-host.ts",
    "content": "import {Inject, Injectable, OnDestroy} from '@angular/core';\nimport {DOCUMENT} from '@angular/platform-browser';\n\nconst Polymer: any = (<any>window).Polymer;\n\n@Injectable()\nexport class SharedCustomStylesHost implements OnDestroy {\n    private _stylesSet = new Set<string>();\n    private _hostNodes = new Set<Node>();\n    private _customStyleNodes = new Set<Node>();\n\n    constructor(@Inject(DOCUMENT) private _doc: any) {\n        this._hostNodes.add(_doc.head);\n    }\n\n    addStyles(styles: string[]): void {\n        styles.forEach(style => {\n            if (!this._stylesSet.has(style)) {\n                this._stylesSet.add(style);\n                this._hostNodes.forEach(hostNode => {\n                    this._addStyleToHost(style, hostNode);\n                });\n            }\n        });\n    }\n\n    private _addStyleToHost(style: string, host: Node): void {\n        const customStyleEl = <Element>(<any>this._doc).createElement('style', 'custom-style');\n        customStyleEl.textContent = style;\n        Polymer.dom(host).appendChild(customStyleEl);\n        Polymer.dom.flush();\n        Polymer.updateStyles();\n        this._customStyleNodes.add(customStyleEl);\n    }\n\n    addHost(hostNode: Node): void {\n        this._stylesSet.forEach(style => this._addStyleToHost(style, hostNode));\n        this._hostNodes.add(hostNode);\n    }\n\n    removeHost(hostNode: Node): void {\n        this._hostNodes.delete(hostNode);\n    }\n\n    ngOnDestroy(): void {\n        this._customStyleNodes.forEach(styleNode => Polymer.dom(Polymer.dom(styleNode).parentNode).removeChild(styleNode));\n    }\n\n    getAllStyles(): string[] {\n        return Array.from(this._stylesSet);\n    }\n}\n"
  },
  {
    "path": "src/test-element.html",
    "content": "<link rel=\"import\" href=\"../bower_components/polymer/polymer.html\">\n<link rel=\"import\" href=\"../bower_components/iron-form-element-behavior/iron-form-element-behavior.html\">\n<link rel=\"import\" href=\"../bower_components/paper-checkbox/paper-checkbox.html\">\n\n<dom-module id=\"test-element\">\n    <template>\n        <div id=\"nested\" nested-object-value$=[[nestedObject.value]] array-object-value$=[[arrayObject.0]]></div>\n        <content id=\"selected\" select=\".selected\"></content>\n        <content id=\"all\"></content>\n    </template>\n</dom-module>\n\n<script>\n    Polymer({\n        is: 'test-element',\n\n        behaviors: [\n            Polymer.IronFormElementBehavior\n        ],\n\n        properties: {\n            value: {\n                value: '',\n                notify: true\n            },\n\n            booleanValue: {\n                type: Boolean\n            },\n\n            nestedObject: {\n                value: {\n                    value: ''\n                }\n            },\n\n            arrayObject: {\n                value: []\n            }\n        }\n    });\n</script>\n"
  },
  {
    "path": "system.config.js",
    "content": "System.config({\n    baseURL: '/base',\n    paths: {\n        'npm:': 'node_modules/'\n    },\n    map: {\n        '@angular/common': 'npm:@angular/common/bundles/common.umd.js',\n        '@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js',\n        '@angular/core': 'npm:@angular/core/bundles/core.umd.js',\n        '@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js',\n        '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',\n        '@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js',\n        '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',\n        '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',\n        '@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js',\n        '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',\n        '@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js',\n        'rxjs': 'npm:rxjs',\n    },\n    packages: {\n        '': {defaultExtension: 'js'},\n        rxjs: {defaultExtension: 'js'}\n    }\n});\n\n(function() {\n    var originalKarmaLoaded = window.__karma__.loaded.bind(window.__karma__);\n    window.__karma__.loaded = function() {};\n\n    document.addEventListener('WebComponentsReady', function () {\n        System.import('index.spec')\n            .then(function () {\n                return Promise.all([\n                    System.import('@angular/core/testing'),\n                    System.import('@angular/platform-browser-dynamic/testing')\n                ]).then(function (providers) {\n                    var testing = providers[0];\n                    var testingBrowser = providers[1];\n\n                    testing.TestBed.initTestEnvironment(\n                        testingBrowser.BrowserDynamicTestingModule,\n                        testingBrowser.platformBrowserDynamicTesting());\n                });\n            })\n            .then(originalKarmaLoaded)\n            .catch(console.error.bind(console));\n    });\n})();\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"declaration\": true,\n    \"target\": \"es5\",\n    \"module\": \"commonjs\",\n    \"moduleResolution\": \"node\",\n    \"inlineSourceMap\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"removeComments\": false,\n    \"noImplicitAny\": false,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"typeRoots\": [\n      \"./node_modules/@types/\"\n    ],\n    \"lib\": [\n      \"es6\",\n      \"dom\"\n    ]\n  },\n  \"exclude\": [\n    \"bower_components\",\n    \"node_modules\"\n  ]\n}\n"
  },
  {
    "path": "tslint.json",
    "content": "{\n    \"jsRules\": {\n        \"class-name\": true,\n        \"comment-format\": [\n            true,\n            \"check-space\"\n        ],\n        \"indent\": [\n            true,\n            \"spaces\"\n        ],\n        \"no-duplicate-variable\": true,\n        \"no-eval\": true,\n        \"no-trailing-whitespace\": true,\n        \"no-unsafe-finally\": true,\n        \"one-line\": [\n            true,\n            \"check-open-brace\",\n            \"check-whitespace\"\n        ],\n        \"quotemark\": [\n            true,\n            \"single\"\n        ],\n        \"semicolon\": [\n            true,\n            \"always\"\n        ],\n        \"triple-equals\": [\n            true,\n            \"allow-null-check\"\n        ],\n        \"variable-name\": [\n            true,\n            \"ban-keywords\"\n        ],\n        \"whitespace\": [\n            true,\n            \"check-branch\",\n            \"check-decl\",\n            \"check-operator\",\n            \"check-separator\",\n            \"check-type\"\n        ]\n    },\n    \"rules\": {\n        \"class-name\": true,\n        \"comment-format\": [\n            true,\n            \"check-space\"\n        ],\n        \"indent\": [\n            true,\n            \"spaces\"\n        ],\n        \"no-eval\": true,\n        \"no-internal-module\": true,\n        \"no-trailing-whitespace\": true,\n        \"no-unsafe-finally\": true,\n        \"no-var-keyword\": true,\n        \"one-line\": [\n            true,\n            \"check-open-brace\",\n            \"check-whitespace\"\n        ],\n        \"quotemark\": [\n            true,\n            \"single\"\n        ],\n        \"semicolon\": [\n            true,\n            \"always\"\n        ],\n        \"triple-equals\": [\n            true,\n            \"allow-null-check\"\n        ],\n        \"typedef-whitespace\": [\n            true,\n            {\n                \"call-signature\": \"nospace\",\n                \"index-signature\": \"nospace\",\n                \"parameter\": \"nospace\",\n                \"property-declaration\": \"nospace\",\n                \"variable-declaration\": \"nospace\"\n            }\n        ],\n        \"variable-name\": [\n            true,\n            \"ban-keywords\"\n        ],\n        \"whitespace\": [\n            true,\n            \"check-branch\",\n            \"check-decl\",\n            \"check-operator\",\n            \"check-separator\",\n            \"check-type\"\n        ],\n        \"no-console\": [\n            true,\n            \"log\",\n            \"error\"\n        ]\n    }\n}\n"
  }
]