Merge "CheckMergeability: Do not fail with 500 ISE on NoMergeBaseException"
diff --git a/.bazelproject b/.bazelproject
index e14c108..a7f5450 100644
--- a/.bazelproject
+++ b/.bazelproject
@@ -22,3 +22,12 @@
 
 build_flags:
   --javacopt=-g
+
+additional_languages:
+  javascript
+  typescript
+
+ts_config_rules:
+  //tools/node_tools/node_modules_licenses:tsconfig_editor
+  //tools/node_tools/polygerrit_app_preprocessor:preprocessor_tsconfig.json
+  //polygerrit-ui/app/node_modules_licenses:tsconfig_editor
diff --git a/.bazelversion b/.bazelversion
index 227cea2..7ec1d6d 100644
--- a/.bazelversion
+++ b/.bazelversion
@@ -1 +1 @@
-2.0.0
+2.1.0
diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 0000000..6d9c8f3
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,2 @@
+**/node_modules
+**/rollup.config.js
diff --git a/.gitmodules b/.gitmodules
index 9f67e77..e5eef1e 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -56,3 +56,8 @@
 	path = plugins/webhooks
 	url = ../plugins/webhooks
 	branch = .
+
+[submodule "polymer-bridges"]
+	path = polymer-bridges
+	url = ../polymer-bridges
+	branch = .
diff --git a/Documentation/BUILD b/Documentation/BUILD
index 52ab7a8..11d3efa 100644
--- a/Documentation/BUILD
+++ b/Documentation/BUILD
@@ -42,6 +42,9 @@
 
 license_map(
     name = "licenses",
+    json_maps = [
+        "//polygerrit-ui/app/node_modules_licenses:polygerrit-licenses.json",
+    ],
     opts = ["--asciidoctor"],
     targets = [
         "//polygerrit-ui/app:polygerrit_ui",
@@ -51,6 +54,9 @@
 
 license_map(
     name = "js_licenses",
+    json_maps = [
+        "//polygerrit-ui/app/node_modules_licenses:polygerrit-licenses.json",
+    ],
     targets = [
         "//polygerrit-ui/app:polygerrit_ui",
     ],
diff --git a/Documentation/config-accounts.txt b/Documentation/config-accounts.txt
index b1ce1ce..b4a5cef 100644
--- a/Documentation/config-accounts.txt
+++ b/Documentation/config-accounts.txt
@@ -7,10 +7,10 @@
 link:note-db.html[NoteDb].
 
 The account data consists of a sequence number (account ID), account
-properties (full name, preferred email, registration date, status,
-inactive flag), preferences (general, diff and edit preferences),
-project watches, SSH keys, external IDs, starred changes and reviewed
-flags.
+properties (full name, display name, preferred email, registration
+date, status, inactive flag), preferences (general, diff and edit
+preferences), project watches, SSH keys, external IDs, starred changes
+and reviewed flags.
 
 Most account data is stored in a special link:#all-users[All-Users]
 repository, which has one branch per user. Within the user branch there
@@ -155,6 +155,7 @@
 ----
 [account]
   fullName = John Doe
+  displayName = John
   preferredEmail = john.doe@example.com
   status = OOO
   active = false
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 82cb3f9..eea0cc3 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -1589,13 +1589,14 @@
 
 [[container.javaOptions]]container.javaOptions::
 +
-Additional options to pass along to the Java runtime.  If multiple
-values are configured, they are passed in order on the command line,
-separated by spaces.  These options are appended onto 'JAVA_OPTIONS'.
-
+Additional options to pass along to the Java runtime. May be specified
+multiple times to configure multiple values. If multiple values are
+configured, they are passed in order on the command line, separated by
+spaces.  These options are appended onto 'JAVA_OPTIONS'.
++
 For example, it is possible to overwrite Gerrit's default log4j
 configuration:
-
++
 ----
   javaOptions = -Dlog4j.configuration=file:///home/gerrit/site/etc/log4j.properties
 ----
diff --git a/Documentation/dev-bazel.txt b/Documentation/dev-bazel.txt
index 037c859..103ae0a 100644
--- a/Documentation/dev-bazel.txt
+++ b/Documentation/dev-bazel.txt
@@ -376,6 +376,21 @@
 Note that Bazel currently does not show
 link:https://github.com/bazelbuild/bazel/issues/3476[the skipped tests,role=external,window=_blank].
 
+[[debug]]
+=== Index Query Tests
+
+The `DEBUG` log level can optionally be enabled for the index query tests. That log level applies to
+both Elasticsearch and Lucene tests.
+
+In Eclipse, set `-Ddebug=true` as a VM argument under the Run Configuration's `Arguments` tab.
+
+With `bazel`, here is an example for the Lucene `account` test:
+
+----
+bazel test --jvmopt='-Ddebug=true' \
+javatests/com/google/gerrit/server/query/account:lucene_query_test
+----
+
 == Dependencies
 
 Dependency JARs are normally downloaded as needed, but you can
@@ -514,10 +529,11 @@
   package=some-npm-package
   version=1.2.3
 
-  npm install -g license-checker && \
+  # Note - yarn must be installed before running the following commands
+  yarn global add license-checker && \
   rm -rf /tmp/$package-$version && mkdir -p /tmp/$package-$version && \
   cd /tmp/$package-$version && \
-  npm install $package@$version && \
+  yarn add $package@$version && \
   license-checker | grep licenses: | sort -u
 ----
 
@@ -540,41 +556,44 @@
 If you see anything that looks like a native library or binary, then we can't
 use the bundle.
 
-If everything looks good, create the bundle, and note the SHA-1:
-[source,bash]
+If everything looks good, install the package with the following command:
+[source, bash]
 ----
-  $gerrit_repo/tools/js/npm_pack.py $package $version && \
-  sha1sum $package-$version.tgz
+# Add to ui_npm. Other packages.json can be updated in the same way
+cd $gerrit_repo/polygerrit-ui/app
+bazel run @nodejs//:yarn add $package
 ----
 
-This creates a file named `$package-$version.tgz` in your working directory.
+Update the `polygerrit-ui/app/node_modules_licenses/licenses.ts` file. You should add licenses
+for the package itself and for all transitive depndencies. If you forgot to add a license, the
+`Documentation:check_licenses` test will fail.
 
-Any project maintainer can upload this file to the
-link:https://console.cloud.google.com/storage/browser/gerrit-maven/npm-packages[storage
-bucket,role=external,window=_blank].
+After the update, commit all changes to the repository (including `yarn.lock`).
 
-Finally, add the new binary to the build process:
-----
-  # WORKSPACE
-  npm_binary(
-      name = "some-npm-package",
-      repository = GERRIT,
-  )
+[NOTE]
+====
+If a npm package has transitive dependencies (or just several files) with a not allowed
+license and you can't avoid use it in release, then you can add this package.
+For example some packages contain demo-code with a different license. Another example - optional
+dependencies, which are not needed to build polygerrit, but they are installed together with
+the package anyway.
 
-  # lib/js/npm.bzl
-  NPM_VERSIONS = {
-    ...
-    "some-npm-package": "1.2.3",
-  }
+In this case you should exclude all files and/or transitive dependencies with a not allowed license.
+Adding such package requires additional updates:
 
-  NPM_SHA1S = {
-    ...
-    "some-npm-package": "<sha1>",
-  }
-----
+- Add dependencies (or files) to the license.ts with an appropriate license marked with
+`allowed: false`.
 
-To use the binary from the Bazel build, you need to use the `run_npm_binary.py`
-wrapper script. For an example, see the use of `crisper` in `tools/bzl/js.bzl`.
+- update package.json postinstall script to remove all non-allowed files (if you don't
+update postinstall script, `Documentation:check_licenses` test will fail.)
+====
+
+=== Update NPM Binaries
+To update a NPM binary the same actions as for a new one must be done (check licenses,
+update `licenses.ts` file, etc...). The only difference is a command to install a package: instead
+of `bazel run @nodejs//:yarn add $package` you should run the `bazel run @nodejs//:yarn upgrade ...`
+command with correct arguments. You can find the list of arguments in the
+link:https://classic.yarnpkg.com/en/docs/cli/upgrade/[yarn upgrade doc,role=external,window=_blank].
 
 
 
diff --git a/Documentation/dev-design-docs.txt b/Documentation/dev-design-docs.txt
index 888b7dc..e658910 100644
--- a/Documentation/dev-design-docs.txt
+++ b/Documentation/dev-design-docs.txt
@@ -59,8 +59,9 @@
 * All possible solutions are fairly discussed with their pros and cons,
   and treated equally until a conclusion is made.
 * Unrelated issues (judged by the design doc owner) that are identified
-  during discussions are extracted into new design docs (initially
-  consisting only of an `index.md` and a `use-cases.md` file).
+  during discussions may be extracted into new design docs (initially
+  consisting only of an `index.md` and a `use-cases.md` file). Doing so
+  is optional yet can be done by either the design owner or reviewers.
 * Changes making iterative improvements can be submitted frequently
   (e.g. additional uses-cases can be added later, solutions can be
   submitted without describing implementation details, etc.).
@@ -97,7 +98,9 @@
 == Design doc review
 
 Everyone in the link:dev-roles.html[Gerrit community] is welcome to
-take part in the design review and comment on the design.
+take part in the design review and comment on the design. As such, every
+design reviewer is expected to respect the community
+link:https://www.gerritcodereview.com/codeofconduct.html[Code of Conduct,role=external,window=_blank].
 
 Positive `Code-Review` votes on changes that add/modify design docs are
 sticky. This means any `Code-Review+1` and `Code-Review+2` vote is
@@ -107,7 +110,14 @@
 change manually.
 
 Ideas for alternative solutions should be uploaded as a change that
-describes the solution (see link:#collaboration[above]).
+describes the solution (see link:#collaboration[above]). This should be
+done as early as possible during the review process, so that related
+comment threads stop there and do not clutter the current review. It is up
+to the alternative reviews to then host their related comments.
+
+Verification should be based on the generated `jekyll` site using the
+local `docker`, rather than via the rendering in `gitiles` (via
+`gerrit-review`).
 
 Changes which make a conclusion on a design (changes that add/change
 the `conclusion.md` file, see link:#structure[Design Doc Structure])
diff --git a/Documentation/dev-e2e-tests.txt b/Documentation/dev-e2e-tests.txt
index 628a0ec..9a62f01 100644
--- a/Documentation/dev-e2e-tests.txt
+++ b/Documentation/dev-e2e-tests.txt
@@ -106,12 +106,14 @@
 
 Valid commands are:
 
+* `clone`
 * `fetch`
 * `pull`
 * `push`
-* `clone`
 
-The example above assumes that the `loadtest-repo` project exists in the Gerrit under test.
+The example above assumes that the `loadtest-repo` project exists in the Gerrit under test. The
+`HTTP Credentials` or password obtained from test user's `Settings` (in Gerrit) may be required, in
+`src/test/resources/application.conf`, depending on the above commands used.
 
 == How to run tests
 
diff --git a/Documentation/dev-eclipse.txt b/Documentation/dev-eclipse.txt
index 5f69cd3..9596a55 100644
--- a/Documentation/dev-eclipse.txt
+++ b/Documentation/dev-eclipse.txt
@@ -81,6 +81,13 @@
 
 == Testing
 
+=== PolyGerrit UI is served by `server.go` process. To launch it,
+run this command:
+
+----
+  $ bazel run polygerrit-ui:devserver
+----
+
 === Running the Daemon
 
 Duplicate the existing launch configuration:
diff --git a/Documentation/js_licenses.txt b/Documentation/js_licenses.txt
index c2bdfbb3..bd26190 100644
--- a/Documentation/js_licenses.txt
+++ b/Documentation/js_licenses.txt
@@ -3,7 +3,6 @@
 Apache2.0
 
 * fonts:robotofonts
-* polymer_externs:polymer_closure
 
 [[Apache2_0_license]]
 ----
@@ -213,105 +212,10 @@
 ----
 
 
-[[ba-linkify]]
-ba-linkify
-
-* js:ba-linkify
-
-[[ba-linkify_license]]
-----
-Copyright (c) 2009 "Cowboy" Ben Alman
-
-Permission is hereby granted, free of charge, to any person
-obtaining a copy of this software and associated documentation
-files (the "Software"), to deal in the Software without
-restriction, including without limitation the rights to use,
-copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following
-conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.
-
-----
-
-
-[[es6-promise]]
-es6-promise
-
-* js:es6-promise
-
-[[es6-promise_license]]
-----
-Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
-----
-
-
-[[fetch]]
-fetch
-
-* js:fetch
-
-[[fetch_license]]
-----
-Copyright (c) 2014-2016 GitHub, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-----
-
-
 [[highlightjs]]
 highlightjs
 
 * js:highlightjs
-* js:highlightjs_files
 
 [[highlightjs_license]]
 ----
@@ -339,113 +243,89 @@
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-----
-
-
-[[moment]]
-moment
-
-* js:moment
-
-[[moment_license]]
-----
-Copyright (c) 2011-2016 Tim Wood, Iskren Chernev, Moment.js contributors
-
-Permission is hereby granted, free of charge, to any person
-obtaining a copy of this software and associated documentation
-files (the "Software"), to deal in the Software without
-restriction, including without limitation the rights to use,
-copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following
-conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.
 
 ----
 
 
-[[page_js]]
-page.js
+[[isarray]]
+isarray
 
-* js:page
+* isarray
 
-[[page_js_license]]
+[[isarray_license]]
 ----
-(The MIT License)
+(MIT)
 
-Copyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca>
+Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>;
 
 Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the 'Software'), to deal in
+this software and associated documentation files (the "Software"), to deal in
 the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-the Software, and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
 
 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.
 
-THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
 
 ----
 
 
-[[polymer]]
-polymer
+[[es6-promise]]
+es6-promise
 
-* js:font-roboto-local
-* js:iron-a11y-announcer
-* js:iron-a11y-keys-behavior
-* js:iron-autogrow-textarea
-* js:iron-behaviors
-* js:iron-checked-element-behavior
-* js:iron-dropdown
-* js:iron-fit-behavior
-* js:iron-flex-layout
-* js:iron-form-element-behavior
-* js:iron-icon
-* js:iron-iconset-svg
-* js:iron-input
-* js:iron-menu-behavior
-* js:iron-meta
-* js:iron-overlay-behavior
-* js:iron-resizable-behavior
-* js:iron-selector
-* js:iron-validatable-behavior
-* js:neon-animation
-* js:paper-behaviors
-* js:paper-button
-* js:paper-icon-button
-* js:paper-input
-* js:paper-item
-* js:paper-listbox
-* js:paper-ripple
-* js:paper-styles
-* js:paper-tabs
-* js:paper-toggle-button
-* js:polymer
-* js:polymer-resin
-* js:webcomponentsjs
+* es6-promise
 
-[[polymer_license]]
+[[es6-promise_license]]
 ----
-Copyright (c) 2014 The Polymer Authors. All rights reserved.
+Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+----
+
+
+[[Polymer-2018]]
+Polymer-2018
+
+* @webcomponents/webcomponentsjs
+* polymer-bridges
+* polymer-resin
+
+[[Polymer-2018_license]]
+----
+Copyright (c) 2018 The Polymer Project Authors. All rights reserved.
+
+This code may only be used under the BSD style license found at
+http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
+http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
+found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
+part of the polymer project is also subject to an additional IP rights grant
+found at http://polymer.github.io/PATENTS.txt
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are
@@ -476,33 +356,796 @@
 ----
 
 
-[[shadycss]]
-shadycss
+[[font-roboto-local-fonts-robotomono]]
+font-roboto-local-fonts-robotomono
 
-* js:shadycss
+* @polymer/font-roboto-local - only the following file(s):
+** fonts/robotomono/LICENSE.txt
+** fonts/robotomono/METADATA.json
+** fonts/robotomono/RobotoMono-Bold.ttf
+** fonts/robotomono/RobotoMono-BoldItalic.ttf
+** fonts/robotomono/RobotoMono-Italic.ttf
+** fonts/robotomono/RobotoMono-Light.ttf
+** fonts/robotomono/RobotoMono-LightItalic.ttf
+** fonts/robotomono/RobotoMono-Medium.ttf
+** fonts/robotomono/RobotoMono-MediumItalic.ttf
+** fonts/robotomono/RobotoMono-Regular.ttf
+** fonts/robotomono/RobotoMono-Thin.ttf
+** fonts/robotomono/RobotoMono-ThinItalic.ttf
 
-[[shadycss_license]]
+[[font-roboto-local-fonts-robotomono_license]]
 ----
-# License
 
-Everything in this repo is BSD style license unless otherwise specified.
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
 
-Copyright (c) 2015 The Polymer Authors. All rights reserved.
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 
-Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+   1. Definitions.
 
-* Redistributions of source code must retain the above copyright
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+----
+
+
+[[Polymer-2014]]
+Polymer-2014
+
+* @polymer/paper-ripple
+* @polymer/paper-styles
+
+[[Polymer-2014_license]]
+----
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+
+This code may only be used under the BSD style license found at
+http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
+http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
+found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
+part of the polymer project is also subject to an additional IP rights grant
+found at http://polymer.github.io/PATENTS.txt
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
 notice, this list of conditions and the following disclaimer.
-* Redistributions in binary form must reproduce the above
+   * Redistributions in binary form must reproduce the above
 copyright notice, this list of conditions and the following disclaimer
 in the documentation and/or other materials provided with the
 distribution.
-* Neither the name of Google Inc. nor the names of its
+   * Neither the name of Google Inc. nor the names of its
 contributors may be used to endorse or promote products derived from
 this software without specific prior written permission.
 
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+----
+
+
+[[Polymer-2015]]
+Polymer-2015
+
+* @polymer/font-roboto
+* @polymer/font-roboto-local - only the following file(s):
+** README.md
+** bower.json
+** demo/index.d.ts
+** demo/index.html
+** fonts/roboto/DESCRIPTION.en_us.html
+** fonts/robotomono/DESCRIPTION.en_us.html
+** generate-style.js
+** manifest.json
+** package.json
+** roboto.js
+** update-fonts.sh
+* @polymer/iron-a11y-announcer
+* @polymer/iron-a11y-keys-behavior
+* @polymer/iron-autogrow-textarea
+* @polymer/iron-behaviors
+* @polymer/iron-checked-element-behavior
+* @polymer/iron-dropdown
+* @polymer/iron-fit-behavior
+* @polymer/iron-flex-layout
+* @polymer/iron-form-element-behavior
+* @polymer/iron-icon
+* @polymer/iron-iconset-svg
+* @polymer/iron-input
+* @polymer/iron-menu-behavior
+* @polymer/iron-meta
+* @polymer/iron-overlay-behavior
+* @polymer/iron-resizable-behavior
+* @polymer/iron-selector
+* @polymer/iron-validatable-behavior
+* @polymer/neon-animation
+* @polymer/paper-behaviors
+* @polymer/paper-button
+* @polymer/paper-dialog
+* @polymer/paper-dialog-behavior
+* @polymer/paper-dialog-scrollable
+* @polymer/paper-icon-button
+* @polymer/paper-input
+* @polymer/paper-item
+* @polymer/paper-listbox
+* @polymer/paper-tabs
+* @polymer/paper-toggle-button
+
+[[Polymer-2015_license]]
+----
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+
+This code may only be used under the BSD style license found at
+http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
+http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
+found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
+part of the polymer project is also subject to an additional IP rights grant
+found at http://polymer.github.io/PATENTS.txt
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----
+
+
+[[ba-linkify]]
+ba-linkify
+
+* ba-linkify
+
+[[ba-linkify_license]]
+----
+Copyright (c) 2009 "Cowboy" Ben Alman
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+----
+
+
+[[whatwg-fetch]]
+whatwg-fetch
+
+* whatwg-fetch
+
+[[whatwg-fetch_license]]
+----
+Copyright (c) 2014-2016 GitHub, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+----
+
+
+[[moment]]
+moment
+
+* moment
+
+[[moment_license]]
+----
+Copyright (c) JS Foundation and other contributors
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+----
+
+
+[[font-roboto-local-fonts-roboto]]
+font-roboto-local-fonts-roboto
+
+* @polymer/font-roboto-local - only the following file(s):
+** fonts/roboto/COPYRIGHT.txt
+** fonts/roboto/LICENSE.txt
+** fonts/roboto/METADATA.json
+** fonts/roboto/Roboto-Black.ttf
+** fonts/roboto/Roboto-BlackItalic.ttf
+** fonts/roboto/Roboto-Bold.ttf
+** fonts/roboto/Roboto-BoldItalic.ttf
+** fonts/roboto/Roboto-Italic.ttf
+** fonts/roboto/Roboto-Light.ttf
+** fonts/roboto/Roboto-LightItalic.ttf
+** fonts/roboto/Roboto-Medium.ttf
+** fonts/roboto/Roboto-MediumItalic.ttf
+** fonts/roboto/Roboto-Regular.ttf
+** fonts/roboto/Roboto-Thin.ttf
+** fonts/roboto/Roboto-ThinItalic.ttf
+
+[[font-roboto-local-fonts-roboto_license]]
+----
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+----
+
+
+[[Polymer-2017]]
+Polymer-2017
+
+* @polymer/polymer
+* @webcomponents/shadycss
+
+[[Polymer-2017_license]]
+----
+Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
+
+This code may only be used under the BSD style license found at
+http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
+http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
+found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
+part of the polymer project is also subject to an additional IP rights grant
+found at http://polymer.github.io/PATENTS.txt
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----
+
+
+[[path-to-regexp]]
+path-to-regexp
+
+* path-to-regexp
+
+[[path-to-regexp_license]]
+----
+The MIT License (MIT)
+
+Copyright (c) 2014 Blake Embrey (hello@blakeembrey.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+----
+
+
+[[page]]
+page
+
+* page
+
+[[page_license]]
+----
+(The MIT License)
+
+Copyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 ----
 
diff --git a/Documentation/licenses.txt b/Documentation/licenses.txt
index f63c1b4..db2cd7d 100644
--- a/Documentation/licenses.txt
+++ b/Documentation/licenses.txt
@@ -86,7 +86,6 @@
 * openid:consumer
 * openid:nekohtml
 * openid:xerces
-* polymer_externs:polymer_closure
 * blame-cache
 * caffeine
 * caffeine-guava
@@ -1079,39 +1078,6 @@
 ----
 
 
-[[ba-linkify]]
-ba-linkify
-
-* js:ba-linkify
-
-[[ba-linkify_license]]
-----
-Copyright (c) 2009 "Cowboy" Ben Alman
-
-Permission is hereby granted, free of charge, to any person
-obtaining a copy of this software and associated documentation
-files (the "Software"), to deal in the Software without
-restriction, including without limitation the rights to use,
-copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following
-conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.
-
-----
-
-
 [[bouncycastle]]
 bouncycastle
 
@@ -1162,67 +1128,6 @@
 ----
 
 
-[[es6-promise]]
-es6-promise
-
-* js:es6-promise
-
-[[es6-promise_license]]
-----
-Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
-----
-
-
-[[fetch]]
-fetch
-
-* js:fetch
-
-[[fetch_license]]
-----
-Copyright (c) 2014-2016 GitHub, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-----
-
-
 [[flexmark]]
 flexmark
 
@@ -2009,7 +1914,6 @@
 highlightjs
 
 * js:highlightjs
-* js:highlightjs_files
 
 [[highlightjs_license]]
 ----
@@ -2037,6 +1941,7 @@
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 ----
 
 
@@ -2555,39 +2460,6 @@
 ----
 
 
-[[moment]]
-moment
-
-* js:moment
-
-[[moment_license]]
-----
-Copyright (c) 2011-2016 Tim Wood, Iskren Chernev, Moment.js contributors
-
-Permission is hereby granted, free of charge, to any person
-obtaining a copy of this software and associated documentation
-files (the "Software"), to deal in the Software without
-restriction, including without limitation the rights to use,
-copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following
-conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.
-
-----
-
-
 [[ow2]]
 ow2
 
@@ -2632,107 +2504,6 @@
 ----
 
 
-[[page_js]]
-page.js
-
-* js:page
-
-[[page_js_license]]
-----
-(The MIT License)
-
-Copyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca>
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the 'Software'), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-the Software, and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-----
-
-
-[[polymer]]
-polymer
-
-* js:font-roboto-local
-* js:iron-a11y-announcer
-* js:iron-a11y-keys-behavior
-* js:iron-autogrow-textarea
-* js:iron-behaviors
-* js:iron-checked-element-behavior
-* js:iron-dropdown
-* js:iron-fit-behavior
-* js:iron-flex-layout
-* js:iron-form-element-behavior
-* js:iron-icon
-* js:iron-iconset-svg
-* js:iron-input
-* js:iron-menu-behavior
-* js:iron-meta
-* js:iron-overlay-behavior
-* js:iron-resizable-behavior
-* js:iron-selector
-* js:iron-validatable-behavior
-* js:neon-animation
-* js:paper-behaviors
-* js:paper-button
-* js:paper-icon-button
-* js:paper-input
-* js:paper-item
-* js:paper-listbox
-* js:paper-ripple
-* js:paper-styles
-* js:paper-tabs
-* js:paper-toggle-button
-* js:polymer
-* js:polymer-resin
-* js:webcomponentsjs
-
-[[polymer_license]]
-----
-Copyright (c) 2014 The Polymer Authors. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-   * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
-   * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
-   * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----
-
-
 [[prologcafe]]
 prologcafe
 
@@ -3384,37 +3155,6 @@
 ----
 
 
-[[shadycss]]
-shadycss
-
-* js:shadycss
-
-[[shadycss_license]]
-----
-# License
-
-Everything in this repo is BSD style license unless otherwise specified.
-
-Copyright (c) 2015 The Polymer Authors. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
-* Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
-* Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-----
-
-
 [[slf4j]]
 slf4j
 
@@ -3463,6 +3203,909 @@
 ----
 
 
+[[isarray]]
+isarray
+
+* isarray
+
+[[isarray_license]]
+----
+(MIT)
+
+Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>;
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+----
+
+
+[[es6-promise]]
+es6-promise
+
+* es6-promise
+
+[[es6-promise_license]]
+----
+Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+----
+
+
+[[Polymer-2018]]
+Polymer-2018
+
+* @webcomponents/webcomponentsjs
+* polymer-bridges
+* polymer-resin
+
+[[Polymer-2018_license]]
+----
+Copyright (c) 2018 The Polymer Project Authors. All rights reserved.
+
+This code may only be used under the BSD style license found at
+http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
+http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
+found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
+part of the polymer project is also subject to an additional IP rights grant
+found at http://polymer.github.io/PATENTS.txt
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----
+
+
+[[font-roboto-local-fonts-robotomono]]
+font-roboto-local-fonts-robotomono
+
+* @polymer/font-roboto-local - only the following file(s):
+** fonts/robotomono/LICENSE.txt
+** fonts/robotomono/METADATA.json
+** fonts/robotomono/RobotoMono-Bold.ttf
+** fonts/robotomono/RobotoMono-BoldItalic.ttf
+** fonts/robotomono/RobotoMono-Italic.ttf
+** fonts/robotomono/RobotoMono-Light.ttf
+** fonts/robotomono/RobotoMono-LightItalic.ttf
+** fonts/robotomono/RobotoMono-Medium.ttf
+** fonts/robotomono/RobotoMono-MediumItalic.ttf
+** fonts/robotomono/RobotoMono-Regular.ttf
+** fonts/robotomono/RobotoMono-Thin.ttf
+** fonts/robotomono/RobotoMono-ThinItalic.ttf
+
+[[font-roboto-local-fonts-robotomono_license]]
+----
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+----
+
+
+[[Polymer-2014]]
+Polymer-2014
+
+* @polymer/paper-ripple
+* @polymer/paper-styles
+
+[[Polymer-2014_license]]
+----
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+
+This code may only be used under the BSD style license found at
+http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
+http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
+found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
+part of the polymer project is also subject to an additional IP rights grant
+found at http://polymer.github.io/PATENTS.txt
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----
+
+
+[[Polymer-2015]]
+Polymer-2015
+
+* @polymer/font-roboto
+* @polymer/font-roboto-local - only the following file(s):
+** README.md
+** bower.json
+** demo/index.d.ts
+** demo/index.html
+** fonts/roboto/DESCRIPTION.en_us.html
+** fonts/robotomono/DESCRIPTION.en_us.html
+** generate-style.js
+** manifest.json
+** package.json
+** roboto.js
+** update-fonts.sh
+* @polymer/iron-a11y-announcer
+* @polymer/iron-a11y-keys-behavior
+* @polymer/iron-autogrow-textarea
+* @polymer/iron-behaviors
+* @polymer/iron-checked-element-behavior
+* @polymer/iron-dropdown
+* @polymer/iron-fit-behavior
+* @polymer/iron-flex-layout
+* @polymer/iron-form-element-behavior
+* @polymer/iron-icon
+* @polymer/iron-iconset-svg
+* @polymer/iron-input
+* @polymer/iron-menu-behavior
+* @polymer/iron-meta
+* @polymer/iron-overlay-behavior
+* @polymer/iron-resizable-behavior
+* @polymer/iron-selector
+* @polymer/iron-validatable-behavior
+* @polymer/neon-animation
+* @polymer/paper-behaviors
+* @polymer/paper-button
+* @polymer/paper-dialog
+* @polymer/paper-dialog-behavior
+* @polymer/paper-dialog-scrollable
+* @polymer/paper-icon-button
+* @polymer/paper-input
+* @polymer/paper-item
+* @polymer/paper-listbox
+* @polymer/paper-tabs
+* @polymer/paper-toggle-button
+
+[[Polymer-2015_license]]
+----
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+
+This code may only be used under the BSD style license found at
+http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
+http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
+found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
+part of the polymer project is also subject to an additional IP rights grant
+found at http://polymer.github.io/PATENTS.txt
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----
+
+
+[[ba-linkify]]
+ba-linkify
+
+* ba-linkify
+
+[[ba-linkify_license]]
+----
+Copyright (c) 2009 "Cowboy" Ben Alman
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+----
+
+
+[[whatwg-fetch]]
+whatwg-fetch
+
+* whatwg-fetch
+
+[[whatwg-fetch_license]]
+----
+Copyright (c) 2014-2016 GitHub, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+----
+
+
+[[moment]]
+moment
+
+* moment
+
+[[moment_license]]
+----
+Copyright (c) JS Foundation and other contributors
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+----
+
+
+[[font-roboto-local-fonts-roboto]]
+font-roboto-local-fonts-roboto
+
+* @polymer/font-roboto-local - only the following file(s):
+** fonts/roboto/COPYRIGHT.txt
+** fonts/roboto/LICENSE.txt
+** fonts/roboto/METADATA.json
+** fonts/roboto/Roboto-Black.ttf
+** fonts/roboto/Roboto-BlackItalic.ttf
+** fonts/roboto/Roboto-Bold.ttf
+** fonts/roboto/Roboto-BoldItalic.ttf
+** fonts/roboto/Roboto-Italic.ttf
+** fonts/roboto/Roboto-Light.ttf
+** fonts/roboto/Roboto-LightItalic.ttf
+** fonts/roboto/Roboto-Medium.ttf
+** fonts/roboto/Roboto-MediumItalic.ttf
+** fonts/roboto/Roboto-Regular.ttf
+** fonts/roboto/Roboto-Thin.ttf
+** fonts/roboto/Roboto-ThinItalic.ttf
+
+[[font-roboto-local-fonts-roboto_license]]
+----
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+----
+
+
+[[Polymer-2017]]
+Polymer-2017
+
+* @polymer/polymer
+* @webcomponents/shadycss
+
+[[Polymer-2017_license]]
+----
+Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
+
+This code may only be used under the BSD style license found at
+http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
+http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
+found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
+part of the polymer project is also subject to an additional IP rights grant
+found at http://polymer.github.io/PATENTS.txt
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----
+
+
+[[path-to-regexp]]
+path-to-regexp
+
+* path-to-regexp
+
+[[path-to-regexp_license]]
+----
+The MIT License (MIT)
+
+Copyright (c) 2014 Blake Embrey (hello@blakeembrey.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+----
+
+
+[[page]]
+page
+
+* page
+
+[[page_license]]
+----
+(The MIT License)
+
+Copyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+----
+
+
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
diff --git a/Documentation/linux-quickstart.txt b/Documentation/linux-quickstart.txt
index aafaf58..29bb409 100644
--- a/Documentation/linux-quickstart.txt
+++ b/Documentation/linux-quickstart.txt
@@ -30,10 +30,10 @@
 . Download the desired Gerrit archive.
 
 To view previous archives, see
-link:https://gerrit-releases.storage.googleapis.com/index.html[Gerrit Code Review: Releases,role=external,window=_blank]. The steps below install Gerrit 3.0.3:
+link:https://gerrit-releases.storage.googleapis.com/index.html[Gerrit Code Review: Releases,role=external,window=_blank]. The steps below install Gerrit 3.1.3:
 
 ....
-wget https://gerrit-releases.storage.googleapis.com/gerrit-3.0.3.war
+wget https://gerrit-releases.storage.googleapis.com/gerrit-3.1.3.war
 ....
 
 NOTE: To build and install Gerrit from the source files, see
diff --git a/Documentation/rest-api-accounts.txt b/Documentation/rest-api-accounts.txt
index bb83d95..28ecc97 100644
--- a/Documentation/rest-api-accounts.txt
+++ b/Documentation/rest-api-accounts.txt
@@ -58,8 +58,8 @@
 
 [[details]]
 --
-* `DETAILS`: Includes full name, preferred email, username, avatars,
-status and state for each account.
+* `DETAILS`: Includes full name, preferred email, username, display
+name, avatars, status and state for each account.
 --
 
 [[all-emails]]
@@ -99,12 +99,14 @@
       "name": "John Doe",
       "email": "john.doe@example.com",
       "username": "john"
+      "display_name": "John D"
     },
     {
       "_account_id": 1001439,
       "name": "John Smith",
       "email": "john.smith@example.com",
       "username": "jsmith"
+      "display_name": "Johnny"
     },
   ]
 ----
@@ -134,6 +136,7 @@
     "name": "John Doe",
     "email": "john.doe@example.com",
     "username": "john"
+    "display_name": "Super John"
   }
 ----
 
@@ -155,6 +158,7 @@
 
   {
     "name": "John Doe",
+    "display_name": "Super John",
     "email": "john.doe@example.com",
     "ssh_key": "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0T...YImydZAw==",
     "http_password": "19D9aIn7zePb",
@@ -208,6 +212,7 @@
     "name": "John Doe",
     "email": "john.doe@example.com",
     "username": "john"
+    "display_name": "Super John"
   }
 ----
 
@@ -401,6 +406,27 @@
 
 As response the new username is returned.
 
+[[set-display-name]]
+=== Set Display Name
+--
+'PUT /accounts/link:#account-id[\{account-id\}]/displayname'
+--
+
+The new display name must be provided in the request body inside
+a link:#display-name-input[DisplayNameInput] entity.
+
+.Request
+----
+  PUT /accounts/self/displayname HTTP/1.0
+  Content-Type: application/json; charset=UTF-8
+
+  {
+    "display_name": "John"
+  }
+----
+
+As response the new display name is returned.
+
 [[get-active]]
 === Get Active
 --
@@ -2228,6 +2254,11 @@
 See option link:rest-api-changes.html#detailed-accounts[
 DETAILED_ACCOUNTS] for change queries +
 and option link:#details[DETAILS] for account queries.
+|`display_name`    |optional|The display name of the user. +
+Only set if detailed account information is requested. +
+See option link:rest-api-changes.html#detailed-accounts[
+DETAILED_ACCOUNTS] for change queries +
+and option link:#details[DETAILS] for account queries.
 |`email`           |optional|
 The email address the user prefers to be contacted through. +
 Only set if detailed account information is requested. +
@@ -2268,6 +2299,7 @@
 |`username`     |optional|
 The user name. If provided, must match the user name from the URL.
 |`name`         |optional|The full name of the user.
+|`display_name` |optional|The display name of the user.
 |`email`        |optional|The email address of the user.
 |`ssh_key`      |optional|The public SSH key of the user.
 |`http_password`|optional|The HTTP password of the user.
@@ -2870,6 +2902,17 @@
 |`username` |The new username of the account.
 |=======================
 
+[[display-name-input]]
+=== DisplayNameInput
+The `DisplayNameInput` entity contains information for setting the
+display name for an account.
+
+[options="header",cols="1,6"]
+|=======================
+|Field Name     |Description
+|`display_name` |The new display name of the account.
+|=======================
+
 [[project-watch-info]]
 === ProjectWatchInfo
 The `WatchedProjectsInfo` entity contains information about a project watch
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index 284eb27..3b243b0 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -6095,6 +6095,13 @@
 If set, the target branch (see  `branch` field) must exist (it is not
 possible to create it automatically by setting the `new_branch` field
 to `true`.
+|`author`             |optional|
+An link:rest-api-accounts.html#account-input[AccountInput] entity
+that will set the author of the commit to create. The author must be
+specified as name/email combination.
+The caller needs "Forge Author" permission when using this field.
+This field does not affect the owner of the change, which will
+continue to use the identity of the caller.
 |`notify`             |optional|
 Notify handling that defines to whom email notifications should be sent
 after the change is created. +
diff --git a/Documentation/rest-api-groups.txt b/Documentation/rest-api-groups.txt
index a99c3bb..5086e19 100644
--- a/Documentation/rest-api-groups.txt
+++ b/Documentation/rest-api-groups.txt
@@ -503,8 +503,9 @@
   }
 ----
 
-If the group creation fails because the name is already in use the
-response is "`409 Conflict`".
+If the group creation fails because the name is already in use, or the
+UUID was specified and the UUID is already in use, the response is
+"`409 Conflict`".
 
 [[get-group-detail]]
 === Get Group Detail
@@ -1591,6 +1592,7 @@
 |Field Name      ||Description
 |`name`          |optional|The name of the group (not encoded). +
 If set, must match the group name in the URL.
+|`uuid`          |optional|The UUID of the group.
 |`description`   |optional|The description of the group.
 |`visible_to_all`|optional|
 Whether the group is visible to all registered users. +
diff --git a/WORKSPACE b/WORKSPACE
index 7c4ee1b..a56dd8a 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -1,4 +1,27 @@
-workspace(name = "gerrit")
+# npm packages are split into different node_modules directories based on their usage.
+# 1. /node_modules (referenced as @npm) - contains packages to run tests, check code, etc...
+#    It is expected that @npm is used ONLY to run tools. No packages from @npm are used by
+#    other code in gerrit.
+# 2. @tools_npm (tools/node_tools/node_modules) - the tools/node_tools folder contains self-written tools
+#    which are run for building and/or testing. The @tools_npm directory contains all the packages needed to
+#    run this tools.
+# 3. @ui_npm (polygerrit-ui/app/node_modules) - packages with source code which are necessary to run polygerrit
+#    and to bundle it. Only code from these packages can be included in the final bundle for polygerrit.
+#    @ui_npm folder must not have devDependencies. All dev dependencies must be placed in @ui_dev_npm
+# 4. @ui_dev_npm (polygerrit-ui/node_modules) - devDependencies for polygerrit. The packages from these
+#    folder can be used for testing, but must not be included in the final bundle.
+# Note: separation between @ui_npm and @ui_dev_npm is necessary because with bazel we can't generate
+#    two managed directories from the same package.json. At the same time we want to avoid accidental
+#    usages of code from devDependencies in polygerrit bundle.
+workspace(
+    name = "gerrit",
+    managed_directories = {
+        "@npm": ["node_modules"],
+        "@ui_npm": ["polygerrit-ui/app/node_modules"],
+        "@ui_dev_npm": ["polygerrit-ui/node_modules"],
+        "@tools_npm": ["tools/node_tools/node_modules"],
+    },
+)
 
 load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
 load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive", "http_file")
@@ -30,6 +53,12 @@
     urls = ["https://github.com/bazelbuild/rules_closure/archive/196a45f0ede2faec11dcc6c60fbc5e7471f4bd58.tar.gz"],
 )
 
+http_archive(
+    name = "build_bazel_rules_nodejs",
+    sha256 = "9473b207f1c5a61b603442cbfeeea8aaf2aa62870673fce2a1c52087f6ff4dc9",
+    urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/1.2.4/rules_nodejs-1.2.4.tar.gz"],
+)
+
 # File is specific to Polymer and copied from the Closure Github -- should be
 # synced any time there are major changes to Polymer.
 # https://github.com/google/closure-compiler/blob/master/contrib/externs/polymer-1.0.js
@@ -1158,13 +1187,44 @@
 bower_archive(
     name = "web-component-tester",
     package = "polymer/web-component-tester",
-    sha1 = "62739cb633fccfddc5eeed98e9e3f69cd0388b5b",
-    version = "6.5.0",
+    sha1 = "d84f6a13bde5f8fd39ee208d43f33925410530d7",
+    version = "6.5.1",
 )
 
-# Bower component transitive dependencies.
-load("//lib/js:bower_archives.bzl", "load_bower_archives")
+load("@build_bazel_rules_nodejs//:index.bzl", "yarn_install")
 
-load_bower_archives()
+yarn_install(
+    name = "npm",
+    package_json = "//:package.json",
+    yarn_lock = "//:yarn.lock",
+)
+
+yarn_install(
+    name = "ui_npm",
+    args = ["--prod"],
+    package_json = "//:polygerrit-ui/app/package.json",
+    yarn_lock = "//:polygerrit-ui/app/yarn.lock",
+)
+
+yarn_install(
+    name = "ui_dev_npm",
+    package_json = "//:polygerrit-ui/package.json",
+    yarn_lock = "//:polygerrit-ui/yarn.lock",
+)
+
+yarn_install(
+    name = "tools_npm",
+    package_json = "//:tools/node_tools/package.json",
+    yarn_lock = "//:tools/node_tools/yarn.lock",
+)
+
+# Install all Bazel dependencies needed for npm packages that supply Bazel rules
+load("@npm//:install_bazel_dependencies.bzl", "install_bazel_dependencies")
+
+install_bazel_dependencies()
+
+load("@npm_bazel_typescript//:index.bzl", "ts_setup_workspace")
+
+ts_setup_workspace()
 
 external_plugin_deps()
diff --git a/java/com/google/gerrit/elasticsearch/ElasticVersion.java b/java/com/google/gerrit/elasticsearch/ElasticVersion.java
index 574a226..6f4ade2 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticVersion.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticVersion.java
@@ -31,7 +31,8 @@
   V7_2("7.2.*"),
   V7_3("7.3.*"),
   V7_4("7.4.*"),
-  V7_5("7.5.*");
+  V7_5("7.5.*"),
+  V7_6("7.6.*");
 
   private final String version;
   private final Pattern pattern;
diff --git a/java/com/google/gerrit/entities/Account.java b/java/com/google/gerrit/entities/Account.java
index b2e0017..fd3df97 100644
--- a/java/com/google/gerrit/entities/Account.java
+++ b/java/com/google/gerrit/entities/Account.java
@@ -129,6 +129,10 @@
   @Nullable
   public abstract String fullName();
 
+  /** Optional display name of the user to be shown in the UI. */
+  @Nullable
+  public abstract String displayName();
+
   /** Email address the user prefers to be contacted through. */
   @Nullable
   public abstract String preferredEmail();
@@ -236,6 +240,11 @@
     public abstract Builder setFullName(String fullName);
 
     @Nullable
+    public abstract String displayName();
+
+    public abstract Builder setDisplayName(String displayName);
+
+    @Nullable
     public abstract String preferredEmail();
 
     public abstract Builder setPreferredEmail(String preferredEmail);
diff --git a/java/com/google/gerrit/extensions/api/accounts/AccountApi.java b/java/com/google/gerrit/extensions/api/accounts/AccountApi.java
index 67d6fd2..6df9889 100644
--- a/java/com/google/gerrit/extensions/api/accounts/AccountApi.java
+++ b/java/com/google/gerrit/extensions/api/accounts/AccountApi.java
@@ -87,6 +87,8 @@
 
   void setStatus(String status) throws RestApiException;
 
+  void setDisplayName(String displayName) throws RestApiException;
+
   List<SshKeyInfo> listSshKeys() throws RestApiException;
 
   SshKeyInfo addSshKey(String key) throws RestApiException;
@@ -269,6 +271,11 @@
     }
 
     @Override
+    public void setDisplayName(String displayName) throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
     public List<SshKeyInfo> listSshKeys() throws RestApiException {
       throw new NotImplementedException();
     }
diff --git a/java/com/google/gerrit/extensions/api/accounts/AccountInput.java b/java/com/google/gerrit/extensions/api/accounts/AccountInput.java
index 259838b..2bcce30 100644
--- a/java/com/google/gerrit/extensions/api/accounts/AccountInput.java
+++ b/java/com/google/gerrit/extensions/api/accounts/AccountInput.java
@@ -20,6 +20,7 @@
 public class AccountInput {
   @DefaultInput public String username;
   public String name;
+  public String displayName;
   public String email;
   public String sshKey;
   public String httpPassword;
diff --git a/java/com/google/gerrit/extensions/api/accounts/DisplayNameInput.java b/java/com/google/gerrit/extensions/api/accounts/DisplayNameInput.java
new file mode 100644
index 0000000..16e7afc
--- /dev/null
+++ b/java/com/google/gerrit/extensions/api/accounts/DisplayNameInput.java
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.extensions.api.accounts;
+
+import com.google.gerrit.extensions.restapi.DefaultInput;
+
+public class DisplayNameInput {
+  public @DefaultInput String displayName;
+
+  public DisplayNameInput(String displayName) {
+    this.displayName = displayName;
+  }
+
+  public DisplayNameInput() {}
+}
diff --git a/java/com/google/gerrit/extensions/api/groups/GroupInput.java b/java/com/google/gerrit/extensions/api/groups/GroupInput.java
index ab38434..30af08f 100644
--- a/java/com/google/gerrit/extensions/api/groups/GroupInput.java
+++ b/java/com/google/gerrit/extensions/api/groups/GroupInput.java
@@ -18,6 +18,7 @@
 
 public class GroupInput {
   public String name;
+  public String uuid;
   public String description;
   public Boolean visibleToAll;
   public String ownerId;
diff --git a/java/com/google/gerrit/extensions/common/AccountInfo.java b/java/com/google/gerrit/extensions/common/AccountInfo.java
index d39d99a..803225e 100644
--- a/java/com/google/gerrit/extensions/common/AccountInfo.java
+++ b/java/com/google/gerrit/extensions/common/AccountInfo.java
@@ -33,6 +33,14 @@
   /** The full name of the user. */
   public String name;
 
+  /**
+   * The display name of the user. This allows users to control how their name is displayed in the
+   * UI. It will likely be unset for most users. Host admins will just choose a default (full name,
+   * user name, first name, ...) for all users, and this account property is just a way to opt out
+   * of the host wide default strategy of choosing the display name.
+   */
+  public String displayName;
+
   /** The preferred email address of the user. */
   public String email;
 
@@ -73,6 +81,7 @@
       AccountInfo accountInfo = (AccountInfo) o;
       return Objects.equals(_accountId, accountInfo._accountId)
           && Objects.equals(name, accountInfo.name)
+          && Objects.equals(displayName, accountInfo.displayName)
           && Objects.equals(email, accountInfo.email)
           && Objects.equals(secondaryEmails, accountInfo.secondaryEmails)
           && Objects.equals(username, accountInfo.username)
@@ -88,6 +97,7 @@
     return MoreObjects.toStringHelper(this)
         .add("id", _accountId)
         .add("name", name)
+        .add("displayname", displayName)
         .add("email", email)
         .add("username", username)
         .toString();
@@ -96,7 +106,15 @@
   @Override
   public int hashCode() {
     return Objects.hash(
-        _accountId, name, email, secondaryEmails, username, avatars, _moreAccounts, status);
+        _accountId,
+        name,
+        displayName,
+        email,
+        secondaryEmails,
+        username,
+        avatars,
+        _moreAccounts,
+        status);
   }
 
   protected AccountInfo() {}
diff --git a/java/com/google/gerrit/extensions/common/ChangeInput.java b/java/com/google/gerrit/extensions/common/ChangeInput.java
index 36dd8f2..1949ff4 100644
--- a/java/com/google/gerrit/extensions/common/ChangeInput.java
+++ b/java/com/google/gerrit/extensions/common/ChangeInput.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.extensions.common;
 
+import com.google.gerrit.extensions.api.accounts.AccountInput;
 import com.google.gerrit.extensions.api.changes.NotifyHandling;
 import com.google.gerrit.extensions.api.changes.NotifyInfo;
 import com.google.gerrit.extensions.api.changes.RecipientType;
@@ -34,6 +35,8 @@
   public Boolean newBranch;
   public MergeInput merge;
 
+  public AccountInput author;
+
   public ChangeInput() {}
 
   /**
diff --git a/java/com/google/gerrit/httpd/init/WebAppInitializer.java b/java/com/google/gerrit/httpd/init/WebAppInitializer.java
index 769396e..05992d4 100644
--- a/java/com/google/gerrit/httpd/init/WebAppInitializer.java
+++ b/java/com/google/gerrit/httpd/init/WebAppInitializer.java
@@ -338,7 +338,7 @@
         new AbstractModule() {
           @Override
           protected void configure() {
-            bind(GerritOptions.class).toInstance(new GerritOptions(false, false, false));
+            bind(GerritOptions.class).toInstance(new GerritOptions(false, false, ""));
             bind(GerritRuntime.class).toInstance(GerritRuntime.DAEMON);
           }
         });
diff --git a/java/com/google/gerrit/httpd/raw/BazelBuild.java b/java/com/google/gerrit/httpd/raw/BazelBuild.java
deleted file mode 100644
index 7677e97..0000000
--- a/java/com/google/gerrit/httpd/raw/BazelBuild.java
+++ /dev/null
@@ -1,160 +0,0 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.httpd.raw;
-
-import static com.google.common.base.MoreObjects.firstNonNull;
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-import com.google.common.base.Joiner;
-import com.google.common.escape.Escaper;
-import com.google.common.flogger.FluentLogger;
-import com.google.common.html.HtmlEscapers;
-import com.google.common.io.ByteStreams;
-import com.google.gerrit.launcher.GerritLauncher;
-import com.google.gerrit.server.util.time.TimeUtil;
-import com.google.gerrit.util.http.CacheHeaders;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InterruptedIOException;
-import java.io.PrintWriter;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Properties;
-import javax.servlet.http.HttpServletResponse;
-import org.eclipse.jgit.util.RawParseUtils;
-
-public class BazelBuild {
-  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
-
-  private final Path sourceRoot;
-
-  public BazelBuild(Path sourceRoot) {
-    this.sourceRoot = sourceRoot;
-  }
-
-  // builds the given label.
-  public void build(Label label) throws IOException, BuildFailureException {
-    ProcessBuilder proc = newBuildProcess(label);
-    proc.directory(sourceRoot.toFile()).redirectErrorStream(true);
-    logger.atInfo().log("building %s", label.fullName());
-    long start = TimeUtil.nowMs();
-    Process rebuild = proc.start();
-    byte[] out;
-    try (InputStream in = rebuild.getInputStream()) {
-      out = ByteStreams.toByteArray(in);
-    } finally {
-      rebuild.getOutputStream().close();
-    }
-
-    int status;
-    try {
-      status = rebuild.waitFor();
-    } catch (InterruptedException e) {
-      String msg = "interrupted waiting for: " + Joiner.on(' ').join(proc.command());
-      logger.atSevere().withCause(e).log(msg);
-      throw new InterruptedIOException(msg);
-    }
-    if (status != 0) {
-      logger.atWarning().log("build failed: %s", new String(out, UTF_8));
-      throw new BuildFailureException(out);
-    }
-
-    long time = TimeUtil.nowMs() - start;
-    logger.atInfo().log("UPDATED    %s in %.3fs", label.fullName(), time / 1000.0);
-  }
-
-  // Represents a label in bazel.
-  static class Label {
-    protected final String pkg;
-    protected final String name;
-
-    public String fullName() {
-      return "//" + pkg + ":" + name;
-    }
-
-    @Override
-    public String toString() {
-      return fullName();
-    }
-
-    // Label in Bazel style.
-    Label(String pkg, String name) {
-      this.name = name;
-      this.pkg = pkg;
-    }
-  }
-
-  static class BuildFailureException extends Exception {
-    private static final long serialVersionUID = 1L;
-
-    final byte[] why;
-
-    BuildFailureException(byte[] why) {
-      this.why = why;
-    }
-
-    public void display(String rule, HttpServletResponse res) throws IOException {
-      res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
-      res.setContentType("text/html");
-      res.setCharacterEncoding(UTF_8.name());
-      CacheHeaders.setNotCacheable(res);
-
-      Escaper html = HtmlEscapers.htmlEscaper();
-      try (PrintWriter w = res.getWriter()) {
-        w.write("<html><title>BUILD FAILED</title><body>");
-        w.format("<h1>%s FAILED</h1>", html.escape(rule));
-        w.write("<pre>");
-        w.write(html.escape(RawParseUtils.decode(why)));
-        w.write("</pre>");
-        w.write("</body></html>");
-      }
-    }
-  }
-
-  private ProcessBuilder newBuildProcess(Label label) throws IOException {
-    Properties properties = GerritLauncher.loadBuildProperties(sourceRoot.resolve(".bazel_path"));
-    String bazel = firstNonNull(properties.getProperty("bazel"), "bazel");
-    List<String> cmd = new ArrayList<>();
-    cmd.add(bazel);
-    cmd.add("build");
-    if (GerritLauncher.isJdk9OrLater()) {
-      String v = GerritLauncher.getJdkVersionPostJdk8();
-      cmd.add("--host_java_toolchain=@bazel_tools//tools/jdk:toolchain_java" + v);
-      cmd.add("--java_toolchain=@bazel_tools//tools/jdk:toolchain_java" + v);
-    }
-    cmd.add(label.fullName());
-    ProcessBuilder proc = new ProcessBuilder(cmd);
-    if (properties.containsKey("PATH")) {
-      proc.environment().put("PATH", properties.getProperty("PATH"));
-    }
-    return proc;
-  }
-
-  /** returns the root relative path to the artifact for the given label */
-  public Path targetPath(Label l) {
-    return sourceRoot.resolve("bazel-bin").resolve(l.pkg).resolve(l.name);
-  }
-
-  /** Label for the polygerrit component zip. */
-  public Label polygerritComponents() {
-    return new Label("polygerrit-ui", "polygerrit_components.bower_components.zip");
-  }
-
-  /** Label for the fonts zip file. */
-  public Label fontZipLabel() {
-    return new Label("polygerrit-ui", "fonts.zip");
-  }
-}
diff --git a/java/com/google/gerrit/httpd/raw/BowerComponentsDevServlet.java b/java/com/google/gerrit/httpd/raw/BowerComponentsDevServlet.java
deleted file mode 100644
index 1be3045..0000000
--- a/java/com/google/gerrit/httpd/raw/BowerComponentsDevServlet.java
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright (C) 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.httpd.raw;
-
-import com.google.common.cache.Cache;
-import com.google.gerrit.launcher.GerritLauncher;
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Objects;
-
-/* Bower component servlet only used in development mode */
-class BowerComponentsDevServlet extends ResourceServlet {
-  private static final long serialVersionUID = 1L;
-
-  private final Path bowerComponents;
-  private final Path zip;
-
-  BowerComponentsDevServlet(Cache<Path, Resource> cache, BazelBuild builder) throws IOException {
-    super(cache, true);
-
-    Objects.requireNonNull(builder);
-    BazelBuild.Label label = builder.polygerritComponents();
-    try {
-      builder.build(label);
-    } catch (BazelBuild.BuildFailureException e) {
-      throw new IOException(e);
-    }
-
-    zip = builder.targetPath(label);
-    bowerComponents = GerritLauncher.newZipFileSystem(zip).getPath("/");
-  }
-
-  @Override
-  protected Path getResourcePath(String pathInfo) throws IOException {
-    return bowerComponents.resolve(pathInfo);
-  }
-}
diff --git a/java/com/google/gerrit/httpd/raw/FontsDevServlet.java b/java/com/google/gerrit/httpd/raw/FontsDevServlet.java
deleted file mode 100644
index 68b0d8c..0000000
--- a/java/com/google/gerrit/httpd/raw/FontsDevServlet.java
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.httpd.raw;
-
-import com.google.common.cache.Cache;
-import com.google.gerrit.launcher.GerritLauncher;
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Objects;
-
-/* Font servlet only used in development mode */
-class FontsDevServlet extends ResourceServlet {
-  private static final long serialVersionUID = 1L;
-
-  private final Path fonts;
-
-  FontsDevServlet(Cache<Path, Resource> cache, BazelBuild builder) throws IOException {
-    super(cache, true);
-    Objects.requireNonNull(builder);
-
-    BazelBuild.Label zipLabel = builder.fontZipLabel();
-    try {
-      builder.build(zipLabel);
-    } catch (BazelBuild.BuildFailureException e) {
-      throw new IOException(e);
-    }
-
-    Path zip = builder.targetPath(zipLabel);
-    Objects.requireNonNull(zip);
-
-    fonts = GerritLauncher.newZipFileSystem(zip).getPath("/");
-  }
-
-  @Override
-  protected Path getResourcePath(String pathInfo) throws IOException {
-    return fonts.resolve(pathInfo);
-  }
-}
diff --git a/java/com/google/gerrit/httpd/raw/StaticModule.java b/java/com/google/gerrit/httpd/raw/StaticModule.java
index 0d4c67e..414a120 100644
--- a/java/com/google/gerrit/httpd/raw/StaticModule.java
+++ b/java/com/google/gerrit/httpd/raw/StaticModule.java
@@ -14,7 +14,6 @@
 
 package com.google.gerrit.httpd.raw;
 
-import static com.google.common.base.Preconditions.checkArgument;
 import static java.nio.file.Files.exists;
 import static java.nio.file.Files.isReadable;
 
@@ -222,7 +221,8 @@
         @CanonicalWebUrl @Nullable String canonicalUrl,
         @GerritServerConfig Config cfg,
         GerritApi gerritApi) {
-      String cdnPath = cfg.getString("gerrit", null, "cdnPath");
+      String cdnPath =
+          options.useDevCdn() ? options.devCdn() : cfg.getString("gerrit", null, "cdnPath");
       String faviconPath = cfg.getString("gerrit", null, "faviconPath");
       return new IndexServlet(canonicalUrl, cdnPath, faviconPath, gerritApi);
     }
@@ -233,29 +233,8 @@
       return new PolyGerritUiServlet(cache, polyGerritBasePath());
     }
 
-    @Provides
-    @Singleton
-    BowerComponentsDevServlet getBowerComponentsServlet(@Named(CACHE) Cache<Path, Resource> cache)
-        throws IOException {
-      return getPaths().isDev() ? new BowerComponentsDevServlet(cache, getPaths().builder) : null;
-    }
-
-    @Provides
-    @Singleton
-    FontsDevServlet getFontsServlet(@Named(CACHE) Cache<Path, Resource> cache) throws IOException {
-      return getPaths().isDev() ? new FontsDevServlet(cache, getPaths().builder) : null;
-    }
-
     private Path polyGerritBasePath() {
       Paths p = getPaths();
-      if (options.forcePolyGerritDev()) {
-        checkArgument(
-            p.sourceRoot != null, "no source root directory found for PolyGerrit developer mode");
-      }
-
-      if (p.isDev()) {
-        return p.sourceRoot.resolve("polygerrit-ui").resolve("app");
-      }
 
       return p.warFs != null
           ? p.warFs.getPath("/polygerrit_ui")
@@ -265,7 +244,6 @@
 
   private static class Paths {
     private final FileSystem warFs;
-    private final BazelBuild builder;
     private final Path sourceRoot;
     private final Path unpackedWar;
     private final boolean development;
@@ -285,21 +263,19 @@
                   launcherLoadedFrom.getParentFile().getParentFile().getParentFile().toURI());
           sourceRoot = null;
           development = false;
-          builder = null;
           return;
         }
         warFs = getDistributionArchive(launcherLoadedFrom);
         if (warFs == null) {
           unpackedWar = makeWarTempDir();
           development = true;
-        } else if (options.forcePolyGerritDev()) {
+        } else if (options.useDevCdn()) {
           unpackedWar = null;
           development = true;
         } else {
           unpackedWar = null;
           development = false;
           sourceRoot = null;
-          builder = null;
           return;
         }
       } catch (IOException e) {
@@ -307,7 +283,6 @@
       }
 
       sourceRoot = getSourceRootOrNull();
-      builder = new BazelBuild(sourceRoot);
     }
 
     private static Path getSourceRootOrNull() {
@@ -373,24 +348,15 @@
 
   @Singleton
   private static class PolyGerritFilter implements Filter {
-    private final Paths paths;
     private final HttpServlet polyGerritIndex;
     private final PolyGerritUiServlet polygerritUI;
-    private final BowerComponentsDevServlet bowerComponentServlet;
-    private final FontsDevServlet fontServlet;
 
     @Inject
     PolyGerritFilter(
-        Paths paths,
         @Named(POLYGERRIT_INDEX_SERVLET) HttpServlet polyGerritIndex,
-        PolyGerritUiServlet polygerritUI,
-        @Nullable BowerComponentsDevServlet bowerComponentServlet,
-        @Nullable FontsDevServlet fontServlet) {
-      this.paths = paths;
+        PolyGerritUiServlet polygerritUI) {
       this.polyGerritIndex = polyGerritIndex;
       this.polygerritUI = polygerritUI;
-      this.bowerComponentServlet = bowerComponentServlet;
-      this.fontServlet = fontServlet;
     }
 
     @Override
@@ -408,22 +374,6 @@
       GuiceFilterRequestWrapper reqWrapper = new GuiceFilterRequestWrapper(req);
       String path = pathInfo(req);
 
-      // Special case assets during development that are built by Bazel and not
-      // served out of the source tree.
-      //
-      // In the war case, these are either inlined, or live under
-      // /polygerrit_ui in the war file, so we can just treat them as normal
-      // assets.
-      if (paths.isDev()) {
-        if (path.startsWith("/bower_components/")) {
-          bowerComponentServlet.service(reqWrapper, res);
-          return;
-        } else if (path.startsWith("/fonts/")) {
-          fontServlet.service(reqWrapper, res);
-          return;
-        }
-      }
-
       if (isPolyGerritIndex(path)) {
         polyGerritIndex.service(reqWrapper, res);
         return;
diff --git a/java/com/google/gerrit/pgm/Daemon.java b/java/com/google/gerrit/pgm/Daemon.java
index 2e9ef2f..8905ee5 100644
--- a/java/com/google/gerrit/pgm/Daemon.java
+++ b/java/com/google/gerrit/pgm/Daemon.java
@@ -168,8 +168,18 @@
   @Option(name = "--headless", usage = "Don't start the UI frontend")
   private boolean headless;
 
-  @Option(name = "--polygerrit-dev", usage = "Force PolyGerrit UI for development")
-  private boolean polyGerritDev;
+  private String devCdn = "";
+
+  @Option(name = "--dev-cdn", usage = "Use specified cdn for serving static content.")
+  private void setDevCdn(String cdn) {
+    if (cdn == null) {
+      cdn = "";
+    }
+    if (cdn.endsWith("/")) {
+      cdn = cdn.substring(0, cdn.length() - 1);
+    }
+    devCdn = cdn;
+  }
 
   @Option(
       name = "--init",
@@ -463,8 +473,7 @@
         new AbstractModule() {
           @Override
           protected void configure() {
-            bind(GerritOptions.class)
-                .toInstance(new GerritOptions(headless, replica, polyGerritDev));
+            bind(GerritOptions.class).toInstance(new GerritOptions(headless, replica, devCdn));
             if (inMemoryTest) {
               bind(String.class)
                   .annotatedWith(SecureStoreClassName.class)
diff --git a/java/com/google/gerrit/server/account/AccountConfig.java b/java/com/google/gerrit/server/account/AccountConfig.java
index 5a1bb8a..afe8c7b 100644
--- a/java/com/google/gerrit/server/account/AccountConfig.java
+++ b/java/com/google/gerrit/server/account/AccountConfig.java
@@ -190,6 +190,7 @@
             InternalAccountUpdate.builder()
                 .setActive(account.isActive())
                 .setFullName(account.fullName())
+                .setDisplayName(account.displayName())
                 .setPreferredEmail(account.preferredEmail())
                 .setStatus(account.status())
                 .build());
diff --git a/java/com/google/gerrit/server/account/AccountProperties.java b/java/com/google/gerrit/server/account/AccountProperties.java
index 4f29b25..5ae5567 100644
--- a/java/com/google/gerrit/server/account/AccountProperties.java
+++ b/java/com/google/gerrit/server/account/AccountProperties.java
@@ -33,6 +33,7 @@
  *   [account]
  *     active = false
  *     fullName = John Doe
+ *     displayName = John
  *     preferredEmail = john.doe@foo.com
  *     status = Overloaded with reviews
  * </pre>
@@ -51,6 +52,7 @@
   public static final String ACCOUNT = "account";
   public static final String KEY_ACTIVE = "active";
   public static final String KEY_FULL_NAME = "fullName";
+  public static final String KEY_DISPLAY_NAME = "displayName";
   public static final String KEY_PREFERRED_EMAIL = "preferredEmail";
   public static final String KEY_STATUS = "status";
 
@@ -91,6 +93,7 @@
     Account.Builder accountBuilder = Account.builder(accountId, registeredOn);
     accountBuilder.setActive(accountConfig.getBoolean(ACCOUNT, null, KEY_ACTIVE, true));
     accountBuilder.setFullName(get(accountConfig, KEY_FULL_NAME));
+    accountBuilder.setDisplayName(get(accountConfig, KEY_DISPLAY_NAME));
 
     String preferredEmail = get(accountConfig, KEY_PREFERRED_EMAIL);
     accountBuilder.setPreferredEmail(preferredEmail);
@@ -109,6 +112,9 @@
     accountUpdate.getActive().ifPresent(active -> setActive(cfg, active));
     accountUpdate.getFullName().ifPresent(fullName -> set(cfg, KEY_FULL_NAME, fullName));
     accountUpdate
+        .getDisplayName()
+        .ifPresent(displayName -> set(cfg, KEY_DISPLAY_NAME, displayName));
+    accountUpdate
         .getPreferredEmail()
         .ifPresent(preferredEmail -> set(cfg, KEY_PREFERRED_EMAIL, preferredEmail));
     accountUpdate.getStatus().ifPresent(status -> set(cfg, KEY_STATUS, status));
diff --git a/java/com/google/gerrit/server/account/AccountsUpdate.java b/java/com/google/gerrit/server/account/AccountsUpdate.java
index 125edfe..8b2a081 100644
--- a/java/com/google/gerrit/server/account/AccountsUpdate.java
+++ b/java/com/google/gerrit/server/account/AccountsUpdate.java
@@ -83,14 +83,14 @@
  *
  * <p>The account updates are written to NoteDb. In NoteDb accounts are represented as user branches
  * in the {@code All-Users} repository. Optionally a user branch can contain a 'account.config' file
- * that stores account properties, such as full name, preferred email, status and the active flag.
- * The timestamp of the first commit on a user branch denotes the registration date. The initial
- * commit on the user branch may be empty (since having an 'account.config' is optional). See {@link
- * AccountConfig} for details of the 'account.config' file format. In addition the user branch can
- * contain a 'preferences.config' config file to store preferences (see {@link StoredPreferences})
- * and a 'watch.config' config file to store project watches (see {@link ProjectWatches}). External
- * IDs are stored separately in the {@code refs/meta/external-ids} notes branch (see {@link
- * ExternalIdNotes}).
+ * that stores account properties, such as full name, display name, preferred email, status and the
+ * active flag. The timestamp of the first commit on a user branch denotes the registration date.
+ * The initial commit on the user branch may be empty (since having an 'account.config' is
+ * optional). See {@link AccountConfig} for details of the 'account.config' file format. In addition
+ * the user branch can contain a 'preferences.config' config file to store preferences (see {@link
+ * StoredPreferences}) and a 'watch.config' config file to store project watches (see {@link
+ * ProjectWatches}). External IDs are stored separately in the {@code refs/meta/external-ids} notes
+ * branch (see {@link ExternalIdNotes}).
  *
  * <p>On updating an account the account is evicted from the account cache and reindexed. The
  * eviction from the account cache and the reindexing is done by the {@link ReindexAfterRefUpdate}
diff --git a/java/com/google/gerrit/server/account/CreateGroupArgs.java b/java/com/google/gerrit/server/account/CreateGroupArgs.java
index 2c59a08..2a764cc 100644
--- a/java/com/google/gerrit/server/account/CreateGroupArgs.java
+++ b/java/com/google/gerrit/server/account/CreateGroupArgs.java
@@ -20,6 +20,7 @@
 
 public class CreateGroupArgs {
   private AccountGroup.NameKey groupName;
+  public AccountGroup.UUID uuid;
   public String groupDescription;
   public boolean visibleToAll;
   public AccountGroup.UUID ownerGroupUuid;
diff --git a/java/com/google/gerrit/server/account/InternalAccountUpdate.java b/java/com/google/gerrit/server/account/InternalAccountUpdate.java
index cf77a75..bfbe917 100644
--- a/java/com/google/gerrit/server/account/InternalAccountUpdate.java
+++ b/java/com/google/gerrit/server/account/InternalAccountUpdate.java
@@ -18,6 +18,7 @@
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
+import com.google.gerrit.common.Nullable;
 import com.google.gerrit.entities.Account;
 import com.google.gerrit.extensions.client.DiffPreferencesInfo;
 import com.google.gerrit.extensions.client.EditPreferencesInfo;
@@ -61,6 +62,15 @@
   public abstract Optional<String> getFullName();
 
   /**
+   * Returns the new value for the display name.
+   *
+   * @return the new value for the display name, {@code Optional#empty()} if the display name is not
+   *     being updated, {@code Optional#of("")} if the display name is unset, the wrapped value is
+   *     never {@code null}
+   */
+  public abstract Optional<String> getDisplayName();
+
+  /**
    * Returns the new value for the preferred email.
    *
    * @return the new value for the preferred email, {@code Optional#empty()} if the preferred email
@@ -166,25 +176,30 @@
      * Sets a new full name for the account.
      *
      * @param fullName the new full name, if {@code null} or empty string the full name is unset
-     * @return the builder
      */
-    public abstract Builder setFullName(String fullName);
+    public abstract Builder setFullName(@Nullable String fullName);
+
+    /**
+     * Sets a new display name for the account.
+     *
+     * @param displayName the new display name, if {@code null} or empty string the display name is
+     *     unset
+     */
+    public abstract Builder setDisplayName(@Nullable String displayName);
 
     /**
      * Sets a new preferred email for the account.
      *
      * @param preferredEmail the new preferred email, if {@code null} or empty string the preferred
      *     email is unset
-     * @return the builder
      */
-    public abstract Builder setPreferredEmail(String preferredEmail);
+    public abstract Builder setPreferredEmail(@Nullable String preferredEmail);
 
     /**
      * Sets the active flag for the account.
      *
      * @param active {@code true} if the account should be set to active, {@code false} if the
      *     account should be set to inactive
-     * @return the builder
      */
     public abstract Builder setActive(boolean active);
 
@@ -192,9 +207,8 @@
      * Sets a new status for the account.
      *
      * @param status the new status, if {@code null} or empty string the status is unset
-     * @return the builder
      */
-    public abstract Builder setStatus(String status);
+    public abstract Builder setStatus(@Nullable String status);
 
     /**
      * Returns a builder for the set of created external IDs.
@@ -487,6 +501,12 @@
       }
 
       @Override
+      public Builder setDisplayName(String displayName) {
+        delegate.setDisplayName(Strings.nullToEmpty(displayName));
+        return this;
+      }
+
+      @Override
       public Builder setPreferredEmail(String preferredEmail) {
         delegate.setPreferredEmail(Strings.nullToEmpty(preferredEmail));
         return this;
diff --git a/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java b/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java
index 7fa9767..4f85412 100644
--- a/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java
+++ b/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java
@@ -22,6 +22,7 @@
 import com.google.gerrit.extensions.api.accounts.AgreementInput;
 import com.google.gerrit.extensions.api.accounts.DeleteDraftCommentsInput;
 import com.google.gerrit.extensions.api.accounts.DeletedDraftCommentInfo;
+import com.google.gerrit.extensions.api.accounts.DisplayNameInput;
 import com.google.gerrit.extensions.api.accounts.EmailApi;
 import com.google.gerrit.extensions.api.accounts.EmailInput;
 import com.google.gerrit.extensions.api.accounts.GpgKeyApi;
@@ -76,6 +77,7 @@
 import com.google.gerrit.server.restapi.account.PostWatchedProjects;
 import com.google.gerrit.server.restapi.account.PutActive;
 import com.google.gerrit.server.restapi.account.PutAgreement;
+import com.google.gerrit.server.restapi.account.PutDisplayName;
 import com.google.gerrit.server.restapi.account.PutHttpPassword;
 import com.google.gerrit.server.restapi.account.PutName;
 import com.google.gerrit.server.restapi.account.PutStatus;
@@ -134,6 +136,7 @@
   private final DeleteExternalIds deleteExternalIds;
   private final DeleteDraftComments deleteDraftComments;
   private final PutStatus putStatus;
+  private final PutDisplayName putDisplayName;
   private final GetGroups getGroups;
   private final EmailApiImpl.Factory emailApi;
   private final PutName putName;
@@ -177,6 +180,7 @@
       DeleteExternalIds deleteExternalIds,
       DeleteDraftComments deleteDraftComments,
       PutStatus putStatus,
+      PutDisplayName putDisplayName,
       GetGroups getGroups,
       EmailApiImpl.Factory emailApi,
       PutName putName,
@@ -219,6 +223,7 @@
     this.deleteExternalIds = deleteExternalIds;
     this.deleteDraftComments = deleteDraftComments;
     this.putStatus = putStatus;
+    this.putDisplayName = putDisplayName;
     this.getGroups = getGroups;
     this.emailApi = emailApi;
     this.putName = putName;
@@ -477,6 +482,16 @@
   }
 
   @Override
+  public void setDisplayName(String displayName) throws RestApiException {
+    DisplayNameInput in = new DisplayNameInput(displayName);
+    try {
+      putDisplayName.apply(account, in);
+    } catch (Exception e) {
+      throw asRestApiException("Cannot set display name", e);
+    }
+  }
+
+  @Override
   public List<SshKeyInfo> listSshKeys() throws RestApiException {
     try {
       return getSshKeys.apply(account).value();
diff --git a/java/com/google/gerrit/server/config/GerritOptions.java b/java/com/google/gerrit/server/config/GerritOptions.java
index 17b65c9..d9edf23 100644
--- a/java/com/google/gerrit/server/config/GerritOptions.java
+++ b/java/com/google/gerrit/server/config/GerritOptions.java
@@ -17,12 +17,12 @@
 public class GerritOptions {
   private final boolean headless;
   private final boolean slave;
-  private final boolean forcePolyGerritDev;
+  private final String devCdn;
 
-  public GerritOptions(boolean headless, boolean slave, boolean forcePolyGerritDev) {
+  public GerritOptions(boolean headless, boolean slave, String devCdn) {
     this.headless = headless;
     this.slave = slave;
-    this.forcePolyGerritDev = forcePolyGerritDev;
+    this.devCdn = devCdn;
   }
 
   public boolean headless() {
@@ -33,7 +33,11 @@
     return !slave;
   }
 
-  public boolean forcePolyGerritDev() {
-    return !headless && forcePolyGerritDev;
+  public String devCdn() {
+    return devCdn;
+  }
+
+  public boolean useDevCdn() {
+    return !headless && devCdn.length() > 0;
   }
 }
diff --git a/java/com/google/gerrit/server/git/meta/VersionedMetaData.java b/java/com/google/gerrit/server/git/meta/VersionedMetaData.java
index 2ed755a..38c8d7d 100644
--- a/java/com/google/gerrit/server/git/meta/VersionedMetaData.java
+++ b/java/com/google/gerrit/server/git/meta/VersionedMetaData.java
@@ -17,6 +17,7 @@
 import static com.google.common.base.Preconditions.checkArgument;
 
 import com.google.common.base.MoreObjects;
+import com.google.common.flogger.FluentLogger;
 import com.google.gerrit.common.Nullable;
 import com.google.gerrit.entities.Project;
 import com.google.gerrit.git.GitUpdateFailureException;
@@ -70,6 +71,8 @@
  * read from the repository, or format an update that can later be written back to the repository.
  */
 public abstract class VersionedMetaData {
+  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
   /**
    * Path information that does not hold references to any repository data structures, allowing the
    * application to retain this object for long periods of time.
@@ -409,6 +412,7 @@
           // read the subject line and use it as reflog message
           ru.setRefLogMessage("commit: " + reader.readLine(), true);
         }
+        logger.atFine().log("Saving commit: " + message);
         inserter.flush();
         RefUpdate.Result result = ru.update();
         switch (result) {
diff --git a/java/com/google/gerrit/server/permissions/PermissionCollection.java b/java/com/google/gerrit/server/permissions/PermissionCollection.java
index b23b5a9..1f0370b 100644
--- a/java/com/google/gerrit/server/permissions/PermissionCollection.java
+++ b/java/com/google/gerrit/server/permissions/PermissionCollection.java
@@ -15,6 +15,7 @@
 package com.google.gerrit.server.permissions;
 
 import static com.google.gerrit.common.data.PermissionRule.Action.BLOCK;
+import static com.google.gerrit.server.project.RefPattern.containsParameters;
 import static com.google.gerrit.server.project.RefPattern.isRE;
 import static java.util.stream.Collectors.mapping;
 import static java.util.stream.Collectors.toList;
@@ -131,7 +132,9 @@
         Iterable<SectionMatcher> matcherList, String ref, CurrentUser user) {
       try (Timer0.Context ignored = filterLatency.start()) {
         if (isRE(ref)) {
-          ref = RefPattern.shortestExample(ref);
+          if (!containsParameters(ref)) {
+            ref = RefPattern.shortestExample(ref);
+          }
         } else if (ref.endsWith("/*")) {
           ref = ref.substring(0, ref.length() - 1);
         }
diff --git a/java/com/google/gerrit/server/project/ProjectCacheImpl.java b/java/com/google/gerrit/server/project/ProjectCacheImpl.java
index 62de2ae..f5d66df 100644
--- a/java/com/google/gerrit/server/project/ProjectCacheImpl.java
+++ b/java/com/google/gerrit/server/project/ProjectCacheImpl.java
@@ -168,7 +168,7 @@
         }
         throw new IOException(e);
       }
-      logger.atFine().withCause(e).log("Cannot find project %s", projectName.get());
+      logger.atFine().log("Cannot find project %s", projectName.get());
       return null;
     }
   }
diff --git a/java/com/google/gerrit/server/project/RefPattern.java b/java/com/google/gerrit/server/project/RefPattern.java
index 0e916fb..c52914b 100644
--- a/java/com/google/gerrit/server/project/RefPattern.java
+++ b/java/com/google/gerrit/server/project/RefPattern.java
@@ -18,9 +18,12 @@
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableMap;
 import com.google.gerrit.common.data.AccessSection;
+import com.google.gerrit.common.data.ParameterizedString;
 import com.google.gerrit.exceptions.InvalidNameException;
 import dk.brics.automaton.RegExp;
+import java.util.Map;
 import java.util.concurrent.ExecutionException;
 import java.util.regex.Pattern;
 import java.util.regex.PatternSyntaxException;
@@ -69,11 +72,21 @@
     return refPattern.startsWith(AccessSection.REGEX_PREFIX);
   }
 
+  public static boolean containsParameters(String refPattern) {
+    return refPattern.contains("${");
+  }
+
   public static RegExp toRegExp(String refPattern) {
     if (isRE(refPattern)) {
       refPattern = refPattern.substring(1);
     }
-    return new RegExp(refPattern, RegExp.NONE);
+    ParameterizedString template = new ParameterizedString(refPattern);
+    String replacement = "_PLACEHOLDER_";
+    Map<String, String> params =
+        ImmutableMap.of(
+            RefPattern.USERID_SHARDED, replacement,
+            RefPattern.USERNAME, replacement);
+    return new RegExp(template.replace(params), RegExp.NONE);
   }
 
   public static void validate(String refPattern) throws InvalidNameException {
diff --git a/java/com/google/gerrit/server/project/RefPatternMatcher.java b/java/com/google/gerrit/server/project/RefPatternMatcher.java
index f00e98e..b9076b3 100644
--- a/java/com/google/gerrit/server/project/RefPatternMatcher.java
+++ b/java/com/google/gerrit/server/project/RefPatternMatcher.java
@@ -15,6 +15,7 @@
 package com.google.gerrit.server.project;
 
 import static com.google.common.collect.ImmutableSet.toImmutableSet;
+import static com.google.gerrit.server.project.RefPattern.containsParameters;
 import static com.google.gerrit.server.project.RefPattern.isRE;
 
 import com.google.common.collect.ImmutableMap;
@@ -32,7 +33,7 @@
 
 public abstract class RefPatternMatcher {
   public static RefPatternMatcher getMatcher(String pattern) {
-    if (pattern.contains("${")) {
+    if (containsParameters(pattern)) {
       return new ExpandParameters(pattern);
     } else if (isRE(pattern)) {
       return new Regexp(pattern);
@@ -80,7 +81,7 @@
 
     @Override
     public boolean match(String ref, CurrentUser user) {
-      return pattern.matcher(ref).matches();
+      return pattern.matcher(ref).matches() || (isRE(ref) && pattern.pattern().equals(ref));
     }
   }
 
@@ -112,7 +113,11 @@
 
     @Override
     public boolean match(String ref, CurrentUser user) {
-      if (!ref.startsWith(prefix)) {
+      if (isRE(ref)) {
+        if (!ref.substring(1).startsWith(prefix)) {
+          return false;
+        }
+      } else if (!ref.startsWith(prefix)) {
         return false;
       }
 
@@ -142,6 +147,9 @@
     }
 
     public boolean matchPrefix(String ref) {
+      if (isRE(ref)) {
+        return ref.substring(1).startsWith(prefix);
+      }
       return ref.startsWith(prefix);
     }
 
diff --git a/java/com/google/gerrit/server/restapi/account/Module.java b/java/com/google/gerrit/server/restapi/account/Module.java
index f41764d..51055b8 100644
--- a/java/com/google/gerrit/server/restapi/account/Module.java
+++ b/java/com/google/gerrit/server/restapi/account/Module.java
@@ -53,6 +53,7 @@
     delete(ACCOUNT_KIND, "name").to(PutName.class);
     get(ACCOUNT_KIND, "status").to(GetStatus.class);
     put(ACCOUNT_KIND, "status").to(PutStatus.class);
+    put(ACCOUNT_KIND, "displayname").to(PutDisplayName.class);
     get(ACCOUNT_KIND, "username").to(GetUsername.class);
     put(ACCOUNT_KIND, "username").to(PutUsername.class);
     get(ACCOUNT_KIND, "active").to(GetActive.class);
diff --git a/java/com/google/gerrit/server/restapi/account/PutDisplayName.java b/java/com/google/gerrit/server/restapi/account/PutDisplayName.java
new file mode 100644
index 0000000..557e660
--- /dev/null
+++ b/java/com/google/gerrit/server/restapi/account/PutDisplayName.java
@@ -0,0 +1,89 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.restapi.account;
+
+import com.google.common.base.Strings;
+import com.google.gerrit.common.Nullable;
+import com.google.gerrit.extensions.api.accounts.DisplayNameInput;
+import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
+import com.google.gerrit.extensions.restapi.Response;
+import com.google.gerrit.extensions.restapi.RestModifyView;
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.ServerInitiated;
+import com.google.gerrit.server.account.AccountResource;
+import com.google.gerrit.server.account.AccountState;
+import com.google.gerrit.server.account.AccountsUpdate;
+import com.google.gerrit.server.permissions.GlobalPermission;
+import com.google.gerrit.server.permissions.PermissionBackend;
+import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+import java.io.IOException;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+
+/**
+ * REST endpoint to set the display name of an account.
+ *
+ * <p>This REST endpoint handles {@code PUT /accounts/<account-identifier>/displayname} requests.
+ *
+ * <p>The display name is a free-form text that a user can set for their own account. It defines how
+ * the user's name will be rendered in the UI in most screens. It is optional, and if not set, then
+ * the UI falls back to whatever is configured as the default display name, e.g. the full name.
+ */
+@Singleton
+public class PutDisplayName implements RestModifyView<AccountResource, DisplayNameInput> {
+  private final Provider<CurrentUser> self;
+  private final PermissionBackend permissionBackend;
+  private final Provider<AccountsUpdate> accountsUpdateProvider;
+
+  @Inject
+  PutDisplayName(
+      Provider<CurrentUser> self,
+      PermissionBackend permissionBackend,
+      @ServerInitiated Provider<AccountsUpdate> accountsUpdateProvider) {
+    this.self = self;
+    this.permissionBackend = permissionBackend;
+    this.accountsUpdateProvider = accountsUpdateProvider;
+  }
+
+  @Override
+  public Response<String> apply(AccountResource rsrc, @Nullable DisplayNameInput input)
+      throws AuthException, ResourceNotFoundException, IOException, PermissionBackendException,
+          ConfigInvalidException {
+    IdentifiedUser user = rsrc.getUser();
+    if (!self.get().hasSameAccountId(user)) {
+      permissionBackend.currentUser().check(GlobalPermission.MODIFY_ACCOUNT);
+    }
+    if (input == null) {
+      input = new DisplayNameInput();
+    }
+
+    String newDisplayName = input.displayName;
+    AccountState accountState =
+        accountsUpdateProvider
+            .get()
+            .update(
+                "Set Display Name via API",
+                user.getAccountId(),
+                u -> u.setDisplayName(newDisplayName))
+            .orElseThrow(() -> new ResourceNotFoundException("account not found"));
+    return Strings.isNullOrEmpty(accountState.account().displayName())
+        ? Response.none()
+        : Response.ok(accountState.account().displayName());
+  }
+}
diff --git a/java/com/google/gerrit/server/restapi/change/CreateChange.java b/java/com/google/gerrit/server/restapi/change/CreateChange.java
index 60631d2..a6a1eef 100644
--- a/java/com/google/gerrit/server/restapi/change/CreateChange.java
+++ b/java/com/google/gerrit/server/restapi/change/CreateChange.java
@@ -30,6 +30,7 @@
 import com.google.gerrit.entities.RefNames;
 import com.google.gerrit.exceptions.InvalidMergeStrategyException;
 import com.google.gerrit.exceptions.MergeWithConflictsNotSupportedException;
+import com.google.gerrit.extensions.api.accounts.AccountInput;
 import com.google.gerrit.extensions.api.changes.NotifyHandling;
 import com.google.gerrit.extensions.client.ChangeStatus;
 import com.google.gerrit.extensions.client.SubmitType;
@@ -188,7 +189,7 @@
     Project.NameKey project = projectResource.getNameKey();
     contributorAgreements.check(project, user.get());
 
-    checkRequiredPermissions(project, input.branch);
+    checkRequiredPermissions(project, input.branch, input.author);
 
     ChangeInfo newChange = createNewChange(input, me, projectState, updateFactory);
     return Response.created(newChange);
@@ -275,21 +276,27 @@
         throw new BadRequestException("Submit type: " + submitType + " is not supported");
       }
     }
+
+    if (input.author != null
+        && (Strings.isNullOrEmpty(input.author.email)
+            || Strings.isNullOrEmpty(input.author.name))) {
+      throw new BadRequestException("Author must specify name and email");
+    }
   }
 
-  private void checkRequiredPermissions(Project.NameKey project, String refName)
+  private void checkRequiredPermissions(
+      Project.NameKey project, String refName, @Nullable AccountInput author)
       throws ResourceNotFoundException, AuthException, PermissionBackendException {
+    PermissionBackend.ForRef forRef = permissionBackend.currentUser().project(project).ref(refName);
     try {
-      permissionBackend.currentUser().project(project).ref(refName).check(RefPermission.READ);
+      forRef.check(RefPermission.READ);
     } catch (AuthException e) {
       throw new ResourceNotFoundException(String.format("ref %s not found", refName), e);
     }
-
-    permissionBackend
-        .currentUser()
-        .project(project)
-        .ref(refName)
-        .check(RefPermission.CREATE_CHANGE);
+    forRef.check(RefPermission.CREATE_CHANGE);
+    if (author != null) {
+      forRef.check(RefPermission.FORGE_AUTHOR);
+    }
   }
 
   private ChangeInfo createNewChange(
@@ -327,7 +334,12 @@
       RevCommit mergeTip = parentCommit == null ? null : rw.parseCommit(parentCommit);
 
       Timestamp now = TimeUtil.nowTs();
-      PersonIdent author = me.newCommitterIdent(now, serverTimeZone);
+
+      PersonIdent author =
+          input.author == null
+              ? me.newCommitterIdent(now, serverTimeZone)
+              : new PersonIdent(input.author.name, input.author.email, now, serverTimeZone);
+
       String commitMessage = getCommitMessage(input.subject, me);
 
       CodeReviewCommit c;
diff --git a/java/com/google/gerrit/server/restapi/group/CreateGroup.java b/java/com/google/gerrit/server/restapi/group/CreateGroup.java
index 531d350..e5a1478 100644
--- a/java/com/google/gerrit/server/restapi/group/CreateGroup.java
+++ b/java/com/google/gerrit/server/restapi/group/CreateGroup.java
@@ -138,6 +138,16 @@
     AccountGroup.UUID ownerUuid = owner(input);
     CreateGroupArgs args = new CreateGroupArgs();
     args.setGroupName(name);
+    args.uuid = Strings.isNullOrEmpty(input.uuid) ? null : AccountGroup.UUID.parse(input.uuid);
+    if (args.uuid != null) {
+      if (!args.uuid.isInternalGroup()) {
+        throw new BadRequestException(String.format("invalid group UUID '%s'", args.uuid.get()));
+      }
+      if (groupCache.get(args.uuid).isPresent()) {
+        throw new ResourceConflictException(
+            String.format("group with UUID '%s' already exists", args.uuid.get()));
+      }
+    }
     args.groupDescription = Strings.emptyToNull(input.description);
     args.visibleToAll = MoreObjects.firstNonNull(input.visibleToAll, defaultVisibleToAll);
     args.ownerGroupUuid = ownerUuid;
@@ -196,9 +206,11 @@
 
     AccountGroup.Id groupId = AccountGroup.id(sequences.nextGroupId());
     AccountGroup.UUID uuid =
-        GroupUuid.make(
-            createGroupArgs.getGroupName(),
-            self.get().newCommitterIdent(serverIdent.getWhen(), serverIdent.getTimeZone()));
+        MoreObjects.firstNonNull(
+            createGroupArgs.uuid,
+            GroupUuid.make(
+                createGroupArgs.getGroupName(),
+                self.get().newCommitterIdent(serverIdent.getWhen(), serverIdent.getTimeZone())));
     InternalGroupCreation groupCreation =
         InternalGroupCreation.builder()
             .setGroupUUID(uuid)
diff --git a/java/com/google/gerrit/sshd/BaseCommand.java b/java/com/google/gerrit/sshd/BaseCommand.java
index 5d7dba2..ab1f062 100644
--- a/java/com/google/gerrit/sshd/BaseCommand.java
+++ b/java/com/google/gerrit/sshd/BaseCommand.java
@@ -80,7 +80,7 @@
   protected OutputStream out;
   protected OutputStream err;
 
-  private ExitCallback exit;
+  protected ExitCallback exit;
 
   @Inject protected CurrentUser user;
 
@@ -88,7 +88,7 @@
 
   @Inject private CmdLineParser.Factory cmdLineParserFactory;
 
-  @Inject private RequestCleanup cleanup;
+  @Inject protected RequestCleanup cleanup;
 
   @Inject @CommandExecutor private ScheduledThreadPoolExecutor executor;
 
diff --git a/java/com/google/gerrit/sshd/CommandFactoryProvider.java b/java/com/google/gerrit/sshd/CommandFactoryProvider.java
index 19f3386..38ac26d 100644
--- a/java/com/google/gerrit/sshd/CommandFactoryProvider.java
+++ b/java/com/google/gerrit/sshd/CommandFactoryProvider.java
@@ -187,7 +187,7 @@
                 @Override
                 public void onExit(int rc, String exitMessage) {
                   exit.onExit(translateExit(rc), exitMessage);
-                  log(rc);
+                  log(rc, exitMessage);
                 }
 
                 @Override
@@ -225,6 +225,12 @@
       }
     }
 
+    private void log(int rc, String message) {
+      if (logged.compareAndSet(false, true)) {
+        log.onExecute(cmd, rc, ctx.getSession(), message);
+      }
+    }
+
     @Override
     public void destroy(ChannelSession channel) {
       Future<?> future = task.getAndSet(null);
diff --git a/java/com/google/gerrit/sshd/SshLog.java b/java/com/google/gerrit/sshd/SshLog.java
index 6ea03c6..e8df441 100644
--- a/java/com/google/gerrit/sshd/SshLog.java
+++ b/java/com/google/gerrit/sshd/SshLog.java
@@ -53,6 +53,7 @@
   private static final String P_EXEC = "executionTime";
   private static final String P_STATUS = "status";
   private static final String P_AGENT = "agent";
+  private static final String P_MESSAGE = "message";
 
   private final Provider<SshSession> session;
   private final Provider<Context> context;
@@ -147,6 +148,10 @@
   }
 
   void onExecute(DispatchCommand dcmd, int exitValue, SshSession sshSession) {
+    onExecute(dcmd, exitValue, sshSession, null);
+  }
+
+  void onExecute(DispatchCommand dcmd, int exitValue, SshSession sshSession, String message) {
     final Context ctx = context.get();
     ctx.finished = TimeUtil.nowMs();
 
@@ -180,6 +185,10 @@
       event.setProperty(P_AGENT, peerAgent);
     }
 
+    if (message != null) {
+      event.setProperty(P_MESSAGE, message);
+    }
+
     if (async != null) {
       async.append(event);
     }
diff --git a/java/com/google/gerrit/sshd/SshLogLayout.java b/java/com/google/gerrit/sshd/SshLogLayout.java
index fd7fef1..f16dd73 100644
--- a/java/com/google/gerrit/sshd/SshLogLayout.java
+++ b/java/com/google/gerrit/sshd/SshLogLayout.java
@@ -30,6 +30,7 @@
   private static final String P_EXEC = "executionTime";
   private static final String P_STATUS = "status";
   private static final String P_AGENT = "agent";
+  private static final String P_MESSAGE = "message";
 
   private final Calendar calendar;
   private long lastTimeMillis;
@@ -68,6 +69,7 @@
 
     opt(P_WAIT, buf, event);
     opt(P_EXEC, buf, event);
+    opt(P_MESSAGE, buf, event);
     opt(P_STATUS, buf, event);
     opt(P_AGENT, buf, event);
 
diff --git a/java/com/google/gerrit/sshd/commands/Upload.java b/java/com/google/gerrit/sshd/commands/Upload.java
index 6c4e80a..a10c52e 100644
--- a/java/com/google/gerrit/sshd/commands/Upload.java
+++ b/java/com/google/gerrit/sshd/commands/Upload.java
@@ -37,6 +37,7 @@
 import java.io.IOException;
 import java.util.List;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.storage.pack.PackStatistics;
 import org.eclipse.jgit.transport.PostUploadHook;
 import org.eclipse.jgit.transport.PostUploadHookChain;
 import org.eclipse.jgit.transport.PreUploadHook;
@@ -54,6 +55,8 @@
   @Inject private SshSession session;
   @Inject private PermissionBackend permissionBackend;
 
+  private PackStatistics stats;
+
   @Override
   protected void runImpl() throws IOException, Failure {
     PermissionBackend.ForProject perm =
@@ -94,6 +97,7 @@
       up.setProtocolV2Hook(tracingHook);
       up.upload(in, out, err);
       session.setPeerAgent(up.getPeerUserAgent());
+      stats = up.getStatistics();
     } catch (UploadValidationException e) {
       // UploadValidationException is used by the UploadValidators to
       // stop the uploadPack. We do not want this exception to go beyond this
@@ -104,4 +108,36 @@
       }
     }
   }
+
+  @Override
+  protected void onExit(int rc) {
+    exit.onExit(
+        rc,
+        stats != null
+            ? stats.getTimeNegotiating()
+                + "ms "
+                + stats.getTimeSearchingForReuse()
+                + "ms "
+                + stats.getTimeSearchingForSizes()
+                + "ms "
+                + stats.getTimeCounting()
+                + "ms "
+                + stats.getTimeCompressing()
+                + "ms "
+                + stats.getTimeWriting()
+                + "ms "
+                + stats.getTimeTotal()
+                + "ms "
+                + stats.getBitmapIndexMisses()
+                + " "
+                + stats.getTotalDeltas()
+                + " "
+                + stats.getTotalObjects()
+                + " "
+                + stats.getTotalBytes()
+            : "-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1");
+    if (cleanup != null) {
+      cleanup.run();
+    }
+  }
 }
diff --git a/java/com/google/gerrit/testing/InMemoryModule.java b/java/com/google/gerrit/testing/InMemoryModule.java
index fa9685e..af9d8c3 100644
--- a/java/com/google/gerrit/testing/InMemoryModule.java
+++ b/java/com/google/gerrit/testing/InMemoryModule.java
@@ -181,7 +181,7 @@
     // support Path-based Configs, only FileBasedConfig.
     bind(Path.class).annotatedWith(SitePath.class).toInstance(Paths.get("."));
     bind(Config.class).annotatedWith(GerritServerConfig.class).toInstance(cfg);
-    bind(GerritOptions.class).toInstance(new GerritOptions(false, false, false));
+    bind(GerritOptions.class).toInstance(new GerritOptions(false, false, ""));
 
     bind(GitRepositoryManager.class).to(InMemoryRepositoryManager.class);
     bind(InMemoryRepositoryManager.class).in(SINGLETON);
diff --git a/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java b/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java
index 988580e..17a0ea6 100644
--- a/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java
@@ -415,6 +415,43 @@
   }
 
   @Test
+  public void createGroupWithUuid() throws Exception {
+    AccountGroup.UUID uuid = AccountGroup.UUID.parse("4eb25d1cca562f53b9356117f33840706a36a349");
+    GroupInput input = new GroupInput();
+    input.uuid = uuid.get();
+    input.name = name("new-group");
+    GroupInfo info = gApi.groups().create(input).get();
+    assertThat(info.name).isEqualTo(input.name);
+    assertThat(info.id).isEqualTo(input.uuid);
+  }
+
+  @Test
+  public void createGroupWithExistingUuid_Conflict() throws Exception {
+    GroupInfo existingGroup = gApi.groups().create(name("new-group")).get();
+    GroupInput input = new GroupInput();
+    input.uuid = existingGroup.id;
+    input.name = name("another-new-group");
+    ResourceConflictException thrown =
+        assertThrows(ResourceConflictException.class, () -> gApi.groups().create(input).get());
+    assertThat(thrown)
+        .hasMessageThat()
+        .isEqualTo(String.format("group with UUID '%s' already exists", input.uuid));
+  }
+
+  @Test
+  public void createGroupWithInvalidUuid_BadRequest() throws Exception {
+    AccountGroup.UUID uuid = AccountGroup.UUID.parse("foo:bar");
+    GroupInput input = new GroupInput();
+    input.uuid = uuid.get();
+    input.name = name("new-group");
+    BadRequestException thrown =
+        assertThrows(BadRequestException.class, () -> gApi.groups().create(input).get());
+    assertThat(thrown)
+        .hasMessageThat()
+        .isEqualTo(String.format("invalid group UUID '%s'", input.uuid));
+  }
+
+  @Test
   public void createGroupWithProperties() throws Exception {
     GroupInput in = new GroupInput();
     in.name = name("newGroup");
diff --git a/javatests/com/google/gerrit/acceptance/pgm/ElasticReindexIT.java b/javatests/com/google/gerrit/acceptance/pgm/ElasticReindexIT.java
index eeeacab..5bbaf40 100644
--- a/javatests/com/google/gerrit/acceptance/pgm/ElasticReindexIT.java
+++ b/javatests/com/google/gerrit/acceptance/pgm/ElasticReindexIT.java
@@ -37,7 +37,7 @@
 
   @ConfigSuite.Config
   public static Config elasticsearchV7() {
-    return getConfig(ElasticVersion.V7_5);
+    return getConfig(ElasticVersion.V7_6);
   }
 
   @Override
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/CreateChangeIT.java b/javatests/com/google/gerrit/acceptance/rest/change/CreateChangeIT.java
index 0b6ecdc..0af1295 100644
--- a/javatests/com/google/gerrit/acceptance/rest/change/CreateChangeIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/change/CreateChangeIT.java
@@ -18,6 +18,7 @@
 import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.block;
 import static com.google.gerrit.common.data.Permission.READ;
 import static com.google.gerrit.entities.RefNames.changeMetaRef;
+import static com.google.gerrit.extensions.common.testing.GitPersonSubject.assertThat;
 import static com.google.gerrit.git.ObjectIds.abbreviateName;
 import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
 import static com.google.gerrit.testing.GerritJUnit.assertThrows;
@@ -35,19 +36,23 @@
 import com.google.gerrit.acceptance.UseSystemTime;
 import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
 import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations;
+import com.google.gerrit.common.data.Permission;
 import com.google.gerrit.entities.BranchNameKey;
 import com.google.gerrit.entities.Change;
 import com.google.gerrit.entities.RefNames;
+import com.google.gerrit.extensions.api.accounts.AccountInput;
 import com.google.gerrit.extensions.api.changes.ChangeApi;
 import com.google.gerrit.extensions.api.changes.CherryPickInput;
 import com.google.gerrit.extensions.api.changes.NotifyHandling;
 import com.google.gerrit.extensions.api.changes.ReviewInput;
+import com.google.gerrit.extensions.api.changes.RevisionApi;
 import com.google.gerrit.extensions.api.projects.BranchInput;
 import com.google.gerrit.extensions.client.ChangeStatus;
 import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
 import com.google.gerrit.extensions.common.ChangeInfo;
 import com.google.gerrit.extensions.common.ChangeInput;
 import com.google.gerrit.extensions.common.ChangeMessageInfo;
+import com.google.gerrit.extensions.common.GitPerson;
 import com.google.gerrit.extensions.common.MergeInput;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.BadRequestException;
@@ -266,6 +271,54 @@
   }
 
   @Test
+  public void createDefaultAuthor() throws Exception {
+    ChangeInput input = newChangeInput(ChangeStatus.NEW);
+    ChangeInfo info = assertCreateSucceeds(input);
+    GitPerson person = gApi.changes().id(info.id).current().commit(false).author;
+    assertThat(person).email().isEqualTo(admin.email());
+  }
+
+  @Test
+  public void createAuthorOverrideBadRequest() throws Exception {
+    ChangeInput input = newChangeInput(ChangeStatus.NEW);
+    input.author = new AccountInput();
+    input.author.name = "name";
+    assertCreateFails(input, BadRequestException.class, "email");
+    input.author.name = null;
+    input.author.email = "gerritlessjane@invalid";
+    assertCreateFails(input, BadRequestException.class, "email");
+  }
+
+  @Test
+  public void createAuthorOverride() throws Exception {
+    ChangeInput input = newChangeInput(ChangeStatus.NEW);
+    input.author = new AccountInput();
+    input.author.email = "gerritlessjane@invalid";
+    // This is an email address that doesn't exist as account on the Gerrit server.
+    input.author.name = "Gerritless Jane";
+    ChangeInfo info = assertCreateSucceeds(input);
+
+    RevisionApi rApi = gApi.changes().id(info.id).current();
+    GitPerson person = rApi.commit(false).author;
+    assertThat(person).email().isEqualTo(input.author.email);
+    assertThat(person).name().isEqualTo(input.author.name);
+  }
+
+  @Test
+  public void createAuthorPermission() throws Exception {
+    ChangeInput input = newChangeInput(ChangeStatus.NEW);
+    input.author = new AccountInput();
+    input.author.name = "Jane";
+    input.author.email = "jane@invalid";
+    projectOperations
+        .project(project)
+        .forUpdate()
+        .add(block(Permission.FORGE_AUTHOR).ref("refs/*").group(REGISTERED_USERS))
+        .update();
+    assertCreateFails(input, AuthException.class, "forge author");
+  }
+
+  @Test
   public void createNewWorkInProgressChange() throws Exception {
     ChangeInput input = newChangeInput(ChangeStatus.NEW);
     input.workInProgress = true;
diff --git a/javatests/com/google/gerrit/acceptance/ssh/ElasticIndexIT.java b/javatests/com/google/gerrit/acceptance/ssh/ElasticIndexIT.java
index 1940274..049fb8b 100644
--- a/javatests/com/google/gerrit/acceptance/ssh/ElasticIndexIT.java
+++ b/javatests/com/google/gerrit/acceptance/ssh/ElasticIndexIT.java
@@ -38,7 +38,7 @@
 
   @ConfigSuite.Config
   public static Config elasticsearchV7() {
-    return getConfig(ElasticVersion.V7_5);
+    return getConfig(ElasticVersion.V7_6);
   }
 
   @Override
diff --git a/javatests/com/google/gerrit/elasticsearch/ElasticContainer.java b/javatests/com/google/gerrit/elasticsearch/ElasticContainer.java
index 53acdeb..77c50ef 100644
--- a/javatests/com/google/gerrit/elasticsearch/ElasticContainer.java
+++ b/javatests/com/google/gerrit/elasticsearch/ElasticContainer.java
@@ -64,6 +64,8 @@
         return "blacktop/elasticsearch:7.4.2";
       case V7_5:
         return "blacktop/elasticsearch:7.5.2";
+      case V7_6:
+        return "blacktop/elasticsearch:7.6.0";
     }
     throw new IllegalStateException("No tests for version: " + version.name());
   }
diff --git a/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryAccountsTest.java b/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryAccountsTest.java
index c55417e..4bfcb6c 100644
--- a/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryAccountsTest.java
+++ b/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryAccountsTest.java
@@ -41,7 +41,7 @@
       return;
     }
 
-    container = ElasticContainer.createAndStart(ElasticVersion.V7_5);
+    container = ElasticContainer.createAndStart(ElasticVersion.V7_6);
     nodeInfo = new ElasticNodeInfo(container.getHttpHost().getPort());
   }
 
diff --git a/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryChangesTest.java b/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryChangesTest.java
index b4feb32..d927c2d 100644
--- a/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryChangesTest.java
+++ b/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryChangesTest.java
@@ -51,7 +51,7 @@
       return;
     }
 
-    container = ElasticContainer.createAndStart(ElasticVersion.V7_5);
+    container = ElasticContainer.createAndStart(ElasticVersion.V7_6);
     nodeInfo = new ElasticNodeInfo(container.getHttpHost().getPort());
     client = HttpAsyncClients.createDefault();
     client.start();
diff --git a/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryGroupsTest.java b/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryGroupsTest.java
index c2d6246..447d47a 100644
--- a/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryGroupsTest.java
+++ b/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryGroupsTest.java
@@ -41,7 +41,7 @@
       return;
     }
 
-    container = ElasticContainer.createAndStart(ElasticVersion.V7_5);
+    container = ElasticContainer.createAndStart(ElasticVersion.V7_6);
     nodeInfo = new ElasticNodeInfo(container.getHttpHost().getPort());
   }
 
diff --git a/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryProjectsTest.java b/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryProjectsTest.java
index 2fc4366..5eebf41 100644
--- a/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryProjectsTest.java
+++ b/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryProjectsTest.java
@@ -41,7 +41,7 @@
       return;
     }
 
-    container = ElasticContainer.createAndStart(ElasticVersion.V7_5);
+    container = ElasticContainer.createAndStart(ElasticVersion.V7_6);
     nodeInfo = new ElasticNodeInfo(container.getHttpHost().getPort());
   }
 
diff --git a/javatests/com/google/gerrit/elasticsearch/ElasticVersionTest.java b/javatests/com/google/gerrit/elasticsearch/ElasticVersionTest.java
index 5d2f99c..0482211 100644
--- a/javatests/com/google/gerrit/elasticsearch/ElasticVersionTest.java
+++ b/javatests/com/google/gerrit/elasticsearch/ElasticVersionTest.java
@@ -63,6 +63,9 @@
 
     assertThat(ElasticVersion.forVersion("7.5.0")).isEqualTo(ElasticVersion.V7_5);
     assertThat(ElasticVersion.forVersion("7.5.1")).isEqualTo(ElasticVersion.V7_5);
+
+    assertThat(ElasticVersion.forVersion("7.6.0")).isEqualTo(ElasticVersion.V7_6);
+    assertThat(ElasticVersion.forVersion("7.6.1")).isEqualTo(ElasticVersion.V7_6);
   }
 
   @Test
@@ -93,6 +96,7 @@
     assertThat(ElasticVersion.V7_3.isAtLeastMinorVersion(ElasticVersion.V6_7)).isFalse();
     assertThat(ElasticVersion.V7_4.isAtLeastMinorVersion(ElasticVersion.V6_7)).isFalse();
     assertThat(ElasticVersion.V7_5.isAtLeastMinorVersion(ElasticVersion.V6_7)).isFalse();
+    assertThat(ElasticVersion.V7_6.isAtLeastMinorVersion(ElasticVersion.V6_7)).isFalse();
   }
 
   @Test
@@ -111,6 +115,7 @@
     assertThat(ElasticVersion.V7_3.isV6OrLater()).isTrue();
     assertThat(ElasticVersion.V7_4.isV6OrLater()).isTrue();
     assertThat(ElasticVersion.V7_5.isV6OrLater()).isTrue();
+    assertThat(ElasticVersion.V7_6.isV6OrLater()).isTrue();
   }
 
   @Test
@@ -129,5 +134,6 @@
     assertThat(ElasticVersion.V7_3.isV7OrLater()).isTrue();
     assertThat(ElasticVersion.V7_4.isV7OrLater()).isTrue();
     assertThat(ElasticVersion.V7_5.isV7OrLater()).isTrue();
+    assertThat(ElasticVersion.V7_6.isV7OrLater()).isTrue();
   }
 }
diff --git a/javatests/com/google/gerrit/server/permissions/RefControlTest.java b/javatests/com/google/gerrit/server/permissions/RefControlTest.java
index 08b008d..43a3f10 100644
--- a/javatests/com/google/gerrit/server/permissions/RefControlTest.java
+++ b/javatests/com/google/gerrit/server/permissions/RefControlTest.java
@@ -477,6 +477,21 @@
   }
 
   @Test
+  public void usernamePatternRegExpCanUploadToAnyRef() throws Exception {
+    projectOperations
+        .project(localKey)
+        .forUpdate()
+        .add(
+            allow(PUSH)
+                .ref("^refs/heads/users/${username}/(public|private)/.+")
+                .group(REGISTERED_USERS))
+        .update();
+    ProjectControl u = user(localKey, "a-registered-user");
+    assertCanUpload(u);
+    assertCanUpdate("refs/heads/users/a-registered-user/private/a", u);
+  }
+
+  @Test
   public void usernamePatternNonRegex() throws Exception {
     projectOperations
         .project(localKey)
@@ -500,6 +515,8 @@
 
     ProjectControl u = user(localKey, "d.v", DEVS);
     ProjectControl d = user(localKey, "dev", DEVS);
+    assertCanAccess(u);
+    assertCanAccess(d);
     assertCannotRead("refs/sb/dev/heads/foobar", u);
     assertCanRead("refs/sb/dev/heads/foobar", d);
   }
@@ -1127,6 +1144,7 @@
     RefPattern.validate("^refs/heads/*");
     RefPattern.validate("^refs/tags/[0-9a-zA-Z-_.]+");
     RefPattern.validate("refs/heads/review/${username}/*");
+    RefPattern.validate("^refs/heads/review/${username}/.+");
   }
 
   @Test
diff --git a/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java b/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
index e7f0812..31d2048 100644
--- a/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
+++ b/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
@@ -91,10 +91,14 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Optional;
+import org.apache.log4j.Level;
+import org.apache.log4j.LogManager;
 import org.eclipse.jgit.lib.PersonIdent;
 import org.eclipse.jgit.lib.Repository;
 import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
@@ -146,6 +150,20 @@
 
   protected abstract Injector createInjector();
 
+  @BeforeClass
+  public static void setLogLevel() {
+    if (Boolean.getBoolean("debug")) {
+      LogManager.getRootLogger().setLevel(Level.DEBUG);
+    }
+  }
+
+  @AfterClass
+  public static void resetLogLevel() {
+    if (Boolean.getBoolean("debug")) {
+      LogManager.getRootLogger().setLevel(Level.INFO);
+    }
+  }
+
   @Before
   public void setUpInjector() throws Exception {
     lifecycle = new LifecycleManager();
diff --git a/javatests/com/google/gerrit/server/query/account/BUILD b/javatests/com/google/gerrit/server/query/account/BUILD
index 5c910a0..da37f26 100644
--- a/javatests/com/google/gerrit/server/query/account/BUILD
+++ b/javatests/com/google/gerrit/server/query/account/BUILD
@@ -23,8 +23,10 @@
         "//lib:guava",
         "//lib:jgit",
         "//lib/guice",
+        "//lib/log:log4j",
         "//lib/truth",
         "//lib/truth:truth-java8-extension",
+        "//resources:log4j-config",
     ],
 )
 
diff --git a/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
index 38e4ca4..71bdd69 100644
--- a/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
+++ b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
@@ -132,6 +132,8 @@
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
+import org.apache.log4j.Level;
+import org.apache.log4j.LogManager;
 import org.eclipse.jgit.junit.TestRepository;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectInserter;
@@ -143,7 +145,9 @@
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.util.SystemReader;
 import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Ignore;
 import org.junit.Test;
 
@@ -206,6 +210,20 @@
 
   protected abstract Injector createInjector();
 
+  @BeforeClass
+  public static void setLogLevel() {
+    if (Boolean.getBoolean("debug")) {
+      LogManager.getRootLogger().setLevel(Level.DEBUG);
+    }
+  }
+
+  @AfterClass
+  public static void resetLogLevel() {
+    if (Boolean.getBoolean("debug")) {
+      LogManager.getRootLogger().setLevel(Level.INFO);
+    }
+  }
+
   @Before
   public void setUpInjector() throws Exception {
     lifecycle = new LifecycleManager();
diff --git a/javatests/com/google/gerrit/server/query/change/BUILD b/javatests/com/google/gerrit/server/query/change/BUILD
index e5b51e7..520e65a 100644
--- a/javatests/com/google/gerrit/server/query/change/BUILD
+++ b/javatests/com/google/gerrit/server/query/change/BUILD
@@ -34,7 +34,9 @@
         "//lib:jgit",
         "//lib:jgit-junit",
         "//lib/guice",
+        "//lib/log:log4j",
         "//lib/truth",
+        "//resources:log4j-config",
     ],
 )
 
diff --git a/javatests/com/google/gerrit/server/query/group/AbstractQueryGroupsTest.java b/javatests/com/google/gerrit/server/query/group/AbstractQueryGroupsTest.java
index d80eac0..9b01f8d 100644
--- a/javatests/com/google/gerrit/server/query/group/AbstractQueryGroupsTest.java
+++ b/javatests/com/google/gerrit/server/query/group/AbstractQueryGroupsTest.java
@@ -68,8 +68,12 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Optional;
+import org.apache.log4j.Level;
+import org.apache.log4j.LogManager;
 import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
@@ -115,6 +119,20 @@
 
   protected abstract Injector createInjector();
 
+  @BeforeClass
+  public static void setLogLevel() {
+    if (Boolean.getBoolean("debug")) {
+      LogManager.getRootLogger().setLevel(Level.DEBUG);
+    }
+  }
+
+  @AfterClass
+  public static void resetLogLevel() {
+    if (Boolean.getBoolean("debug")) {
+      LogManager.getRootLogger().setLevel(Level.INFO);
+    }
+  }
+
   @Before
   public void setUpInjector() throws Exception {
     lifecycle = new LifecycleManager();
diff --git a/javatests/com/google/gerrit/server/query/group/BUILD b/javatests/com/google/gerrit/server/query/group/BUILD
index e14350f..8f6fd6d 100644
--- a/javatests/com/google/gerrit/server/query/group/BUILD
+++ b/javatests/com/google/gerrit/server/query/group/BUILD
@@ -20,8 +20,10 @@
         "//lib:guava",
         "//lib:jgit",
         "//lib/guice",
+        "//lib/log:log4j",
         "//lib/truth",
         "//lib/truth:truth-java8-extension",
+        "//resources:log4j-config",
     ],
 )
 
diff --git a/javatests/com/google/gerrit/server/query/project/AbstractQueryProjectsTest.java b/javatests/com/google/gerrit/server/query/project/AbstractQueryProjectsTest.java
index dfd7928..e142e0c 100644
--- a/javatests/com/google/gerrit/server/query/project/AbstractQueryProjectsTest.java
+++ b/javatests/com/google/gerrit/server/query/project/AbstractQueryProjectsTest.java
@@ -68,8 +68,12 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Set;
+import org.apache.log4j.Level;
+import org.apache.log4j.LogManager;
 import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
@@ -111,6 +115,20 @@
 
   protected abstract Injector createInjector();
 
+  @BeforeClass
+  public static void setLogLevel() {
+    if (Boolean.getBoolean("debug")) {
+      LogManager.getRootLogger().setLevel(Level.DEBUG);
+    }
+  }
+
+  @AfterClass
+  public static void resetLogLevel() {
+    if (Boolean.getBoolean("debug")) {
+      LogManager.getRootLogger().setLevel(Level.INFO);
+    }
+  }
+
   @Before
   public void setUpInjector() throws Exception {
     lifecycle = new LifecycleManager();
diff --git a/javatests/com/google/gerrit/server/query/project/BUILD b/javatests/com/google/gerrit/server/query/project/BUILD
index 984d824..996be2f 100644
--- a/javatests/com/google/gerrit/server/query/project/BUILD
+++ b/javatests/com/google/gerrit/server/query/project/BUILD
@@ -21,7 +21,9 @@
         "//lib:guava",
         "//lib:jgit",
         "//lib/guice",
+        "//lib/log:log4j",
         "//lib/truth",
+        "//resources:log4j-config",
     ],
 )
 
diff --git a/lib/ba-linkify/BUILD b/lib/ba-linkify/BUILD
index 9a8b442..9f0b41d 100644
--- a/lib/ba-linkify/BUILD
+++ b/lib/ba-linkify/BUILD
@@ -1 +1,9 @@
-exports_files(["ba-linkify.js"])
+# Initially, ba-linkify.js was placed in this folder
+# Because BUILD file can't be in the npm package, the .js file was moved to a src/... subfolder.
+# Some plugin can still use ba-linkify, so we add alias to this file, so plugins
+# сan be built without any update.
+alias(
+    name = "ba-linkify.js",
+    actual = "src/ba-linkify.js",
+    visibility = ["//visibility:public"],
+)
diff --git a/lib/ba-linkify/src/LICENSE-MIT b/lib/ba-linkify/src/LICENSE-MIT
new file mode 100644
index 0000000..93672f9
--- /dev/null
+++ b/lib/ba-linkify/src/LICENSE-MIT
@@ -0,0 +1,22 @@
+Copyright (c) 2009 "Cowboy" Ben Alman
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
diff --git a/lib/ba-linkify/README.md b/lib/ba-linkify/src/README.md
similarity index 100%
rename from lib/ba-linkify/README.md
rename to lib/ba-linkify/src/README.md
diff --git a/lib/ba-linkify/ba-linkify.js b/lib/ba-linkify/src/ba-linkify.js
similarity index 100%
rename from lib/ba-linkify/ba-linkify.js
rename to lib/ba-linkify/src/ba-linkify.js
diff --git a/lib/ba-linkify/src/package.json b/lib/ba-linkify/src/package.json
new file mode 100644
index 0000000..813d75f
--- /dev/null
+++ b/lib/ba-linkify/src/package.json
@@ -0,0 +1,8 @@
+{
+  "name": "ba-linkify",
+  "version": "1.0.0",
+  "description": "See README.md",
+  "main": "ba-linkify.js",
+  "license": "MIT",
+  "private": true
+}
diff --git a/lib/js/BUILD b/lib/js/BUILD
index 7478ef3..106aabb 100644
--- a/lib/js/BUILD
+++ b/lib/js/BUILD
@@ -1,36 +1,18 @@
-load("//lib/js:bower_components.bzl", "define_bower_components")
 load("//tools/bzl:js.bzl", "bower_component", "js_component")
 
 package(default_visibility = ["//visibility:public"])
 
-# For importing new versions of existing bower packages,
-#
-# 1) edit the versions of 'seed' components in WORKSPACE as desired
-#
-# 2) Run: 'python tools/js/bower2bazel.py -w lib/js/bower_archives.bzl -b lib/js/bower_components.bzl', to update dependency versions.
-#
-
-# For adding a new component as dependency to a bower_component_bundle
-#
-# 1) add a new bower_archive in WORKSPACE
-#
-# 2) add bower_component(name="my_new_dependency", seed=True) here
-#
-# 3) run bower2bazel (see above.)
-#
-# 4) remove bower_component(name="my_new_dependency", .. ) here
-#
-
-define_bower_components()
-
 js_component(
     name = "highlightjs",
     srcs = ["//lib/highlightjs:highlight.min.js"],
     license = "//lib:LICENSE-highlightjs",
 )
 
+# TODO(dmfilippov) - rename to "highlightjs" after removing js_component
+# license-map.py uses rule name to extract package name; everything after
+# double underscore are removed.
 filegroup(
-    name = "highlightjs_files",
+    name = "highlightjs__files",
     srcs = ["//lib/highlightjs:highlight.min.js"],
     data = ["//lib:LICENSE-highlightjs"],
 )
@@ -41,6 +23,7 @@
     license = "//lib:LICENSE-ba-linkify",
 )
 
+##TODO: remove after plugins migration to npm
 bower_component(
     name = "codemirror-minified",
     license = "//lib:LICENSE-codemirror-minified",
@@ -50,3 +33,4 @@
     name = "resemblejs",
     license = "//lib:LICENSE-resemblejs",
 )
+#End of removal
diff --git a/lib/js/bower_archives.bzl b/lib/js/bower_archives.bzl
deleted file mode 100644
index 0b2fdef9..0000000
--- a/lib/js/bower_archives.bzl
+++ /dev/null
@@ -1,173 +0,0 @@
-# DO NOT EDIT
-# generated with the following command:
-#
-#   tools/js/bower2bazel.py -w lib/js/bower_archives.bzl -b lib/js/bower_components.bzl
-#
-
-load("//tools/bzl:js.bzl", "bower_archive")
-
-def load_bower_archives():
-    bower_archive(
-        name = "accessibility-developer-tools",
-        package = "accessibility-developer-tools",
-        version = "2.12.0",
-        sha1 = "88ae82dcdeb6c658f76eff509d0ee425cae14d49",
-    )
-    bower_archive(
-        name = "async",
-        package = "async",
-        version = "1.5.2",
-        sha1 = "1ec975d3b3834646a7e3d4b7e68118b90ed72508",
-    )
-    bower_archive(
-        name = "chai",
-        package = "chai",
-        version = "3.5.0",
-        sha1 = "849ad3ee7c77506548b7b5db603a4e150b9431aa",
-    )
-    bower_archive(
-        name = "font-roboto-local",
-        package = "PolymerElements/font-roboto-local",
-        version = "1.1.0",
-        sha1 = "de651abf9b1b2d0935f7b264d48131677196412f",
-    )
-    bower_archive(
-        name = "iron-a11y-announcer",
-        package = "PolymerElements/iron-a11y-announcer",
-        version = "2.1.0",
-        sha1 = "bda12ed6fe7b98a64bf5f70f3e84384053763190",
-    )
-    bower_archive(
-        name = "iron-a11y-keys-behavior",
-        package = "PolymerElements/iron-a11y-keys-behavior",
-        version = "2.1.1",
-        sha1 = "4c8f303479253301e81c63b8ba7bd4cfb62ddf55",
-    )
-    bower_archive(
-        name = "iron-behaviors",
-        package = "PolymerElements/iron-behaviors",
-        version = "2.1.1",
-        sha1 = "d2418e886c3237dcbc8d74a956eec367a95cd068",
-    )
-    bower_archive(
-        name = "iron-checked-element-behavior",
-        package = "PolymerElements/iron-checked-element-behavior",
-        version = "2.1.1",
-        sha1 = "822b6c73e349cf5174e3a17aa9b3d2cb823c37ac",
-    )
-    bower_archive(
-        name = "iron-fit-behavior",
-        package = "PolymerElements/iron-fit-behavior",
-        version = "2.2.1",
-        sha1 = "7b12bc96bf05f04bbb6ad78a16d6c39758263a14",
-    )
-    bower_archive(
-        name = "iron-flex-layout",
-        package = "PolymerElements/iron-flex-layout",
-        version = "2.0.3",
-        sha1 = "c88e9577cabb005ea6d33f35b97d9c39c68f3d9e",
-    )
-    bower_archive(
-        name = "iron-form-element-behavior",
-        package = "PolymerElements/iron-form-element-behavior",
-        version = "2.1.3",
-        sha1 = "634f01cdedd7a616ae025fdcde85c6c5804f6377",
-    )
-    bower_archive(
-        name = "iron-menu-behavior",
-        package = "PolymerElements/iron-menu-behavior",
-        version = "2.1.1",
-        sha1 = "1504997f6eb9aec490b855dadee473cac064f38c",
-    )
-    bower_archive(
-        name = "iron-meta",
-        package = "PolymerElements/iron-meta",
-        version = "2.1.1",
-        sha1 = "7985a9f18b6c32d62f5d3870d58d73ef66613cb9",
-    )
-    bower_archive(
-        name = "iron-resizable-behavior",
-        package = "PolymerElements/iron-resizable-behavior",
-        version = "2.1.1",
-        sha1 = "31e32da6880a983da32da21ee3f483525b24e458",
-    )
-    bower_archive(
-        name = "iron-validatable-behavior",
-        package = "PolymerElements/iron-validatable-behavior",
-        version = "2.1.0",
-        sha1 = "b5dcf3bf4d95b074b74f8170d7122d34ab417daf",
-    )
-    bower_archive(
-        name = "lodash",
-        package = "lodash",
-        version = "3.10.1",
-        sha1 = "2f207a8293c4c554bf6cf071241f7a00dc513d3a",
-    )
-    bower_archive(
-        name = "mocha",
-        package = "mocha",
-        version = "3.5.3",
-        sha1 = "c14f149821e4e96241b20f85134aa757b73038f1",
-    )
-    bower_archive(
-        name = "neon-animation",
-        package = "PolymerElements/neon-animation",
-        version = "2.2.1",
-        sha1 = "865f4252c6306b91609769fefefb4f641361931f",
-    )
-    bower_archive(
-        name = "paper-behaviors",
-        package = "PolymerElements/paper-behaviors",
-        version = "2.1.1",
-        sha1 = "af59936a9015cda4abcfb235f831090a41faa2c4",
-    )
-    bower_archive(
-        name = "paper-icon-button",
-        package = "PolymerElements/paper-icon-button",
-        version = "2.2.1",
-        sha1 = "68f76af3a9379f256a3900a4b68d871898f1fe57",
-    )
-    bower_archive(
-        name = "paper-ripple",
-        package = "PolymerElements/paper-ripple",
-        version = "2.1.1",
-        sha1 = "d402c8165c6a09d17c12a2b421e69ea54e2fc8ef",
-    )
-    bower_archive(
-        name = "paper-styles",
-        package = "PolymerElements/paper-styles",
-        # Basically 2.1.0 but with
-        # https://github.com/PolymerElements/paper-styles/pull/165 applied
-        version = "a6c207e6eee3402fd7a6550e6f9c387ca22ec4c4",
-        sha1 = "6bd17410578b5d4017ccef330393a4b41b1c716e",
-    )
-    bower_archive(
-        name = "shadycss",
-        package = "webcomponents/shadycss",
-        version = "1.9.1",
-        sha1 = "3ef3bd54280ea2d7ce90434620354a2022c8e13d",
-    )
-    bower_archive(
-        name = "sinon-chai",
-        package = "sinon-chai",
-        version = "2.14.0",
-        sha1 = "78f0dc184efe47012a2b1b9a16a4289acf8300dc",
-    )
-    bower_archive(
-        name = "sinonjs",
-        package = "sinonjs",
-        version = "1.17.1",
-        sha1 = "a26a6aab7358807de52ba738770f6ac709afd240",
-    )
-    bower_archive(
-        name = "stacky",
-        package = "stacky",
-        version = "1.3.2",
-        sha1 = "d6c07a0112ab2e9677fe085933744466a89232fb",
-    )
-    bower_archive(
-        name = "webcomponentsjs",
-        package = "webcomponents/webcomponentsjs",
-        version = "1.3.3",
-        sha1 = "bbad90bd8301a2f2f5e014e750e0c86351579391",
-    )
diff --git a/lib/js/bower_components.bzl b/lib/js/bower_components.bzl
deleted file mode 100644
index 7fd61c7..0000000
--- a/lib/js/bower_components.bzl
+++ /dev/null
@@ -1,377 +0,0 @@
-# DO NOT EDIT
-# generated with the following command:
-#
-#   tools/js/bower2bazel.py -w lib/js/bower_archives.bzl -b lib/js/bower_components.bzl
-#
-
-load("//tools/bzl:js.bzl", "bower_component")
-
-def define_bower_components():
-    bower_component(
-        name = "accessibility-developer-tools",
-        license = "//lib:LICENSE-DO_NOT_DISTRIBUTE",
-    )
-    bower_component(
-        name = "async",
-        license = "//lib:LICENSE-DO_NOT_DISTRIBUTE",
-    )
-    bower_component(
-        name = "chai",
-        license = "//lib:LICENSE-DO_NOT_DISTRIBUTE",
-    )
-    bower_component(
-        name = "es6-promise",
-        license = "//lib:LICENSE-es6-promise",
-        seed = True,
-    )
-    bower_component(
-        name = "fetch",
-        license = "//lib:LICENSE-fetch",
-        seed = True,
-    )
-    bower_component(
-        name = "font-roboto-local",
-        license = "//lib:LICENSE-polymer",
-    )
-    bower_component(
-        name = "iron-a11y-announcer",
-        license = "//lib:LICENSE-polymer",
-        deps = [":polymer"],
-    )
-    bower_component(
-        name = "iron-a11y-keys-behavior",
-        license = "//lib:LICENSE-polymer",
-        deps = [":polymer"],
-    )
-    bower_component(
-        name = "iron-autogrow-textarea",
-        license = "//lib:LICENSE-polymer",
-        deps = [
-            ":iron-behaviors",
-            ":iron-flex-layout",
-            ":iron-validatable-behavior",
-            ":polymer",
-        ],
-        seed = True,
-    )
-    bower_component(
-        name = "iron-behaviors",
-        license = "//lib:LICENSE-polymer",
-        deps = [
-            ":iron-a11y-keys-behavior",
-            ":polymer",
-        ],
-    )
-    bower_component(
-        name = "iron-checked-element-behavior",
-        license = "//lib:LICENSE-polymer",
-        deps = [
-            ":iron-form-element-behavior",
-            ":iron-validatable-behavior",
-            ":polymer",
-        ],
-    )
-    bower_component(
-        name = "iron-dropdown",
-        license = "//lib:LICENSE-polymer",
-        deps = [
-            ":iron-behaviors",
-            ":iron-overlay-behavior",
-            ":neon-animation",
-            ":polymer",
-        ],
-        seed = True,
-    )
-    bower_component(
-        name = "iron-fit-behavior",
-        license = "//lib:LICENSE-polymer",
-        deps = [":polymer"],
-    )
-    bower_component(
-        name = "iron-flex-layout",
-        license = "//lib:LICENSE-polymer",
-        deps = [":polymer"],
-    )
-    bower_component(
-        name = "iron-form-element-behavior",
-        license = "//lib:LICENSE-polymer",
-        deps = [":polymer"],
-    )
-    bower_component(
-        name = "iron-icon",
-        license = "//lib:LICENSE-polymer",
-        deps = [
-            ":iron-flex-layout",
-            ":iron-meta",
-            ":polymer",
-        ],
-        seed = True,
-    )
-    bower_component(
-        name = "iron-iconset-svg",
-        license = "//lib:LICENSE-polymer",
-        deps = [
-            ":iron-meta",
-            ":polymer",
-        ],
-        seed = True,
-    )
-    bower_component(
-        name = "iron-input",
-        license = "//lib:LICENSE-polymer",
-        deps = [
-            ":iron-a11y-announcer",
-            ":iron-validatable-behavior",
-            ":polymer",
-        ],
-        seed = True,
-    )
-    bower_component(
-        name = "iron-menu-behavior",
-        license = "//lib:LICENSE-polymer",
-        deps = [
-            ":iron-a11y-keys-behavior",
-            ":iron-flex-layout",
-            ":iron-selector",
-            ":polymer",
-        ],
-    )
-    bower_component(
-        name = "iron-meta",
-        license = "//lib:LICENSE-polymer",
-        deps = [":polymer"],
-    )
-    bower_component(
-        name = "iron-overlay-behavior",
-        license = "//lib:LICENSE-polymer",
-        deps = [
-            ":iron-a11y-keys-behavior",
-            ":iron-fit-behavior",
-            ":iron-resizable-behavior",
-            ":polymer",
-        ],
-        seed = True,
-    )
-    bower_component(
-        name = "iron-resizable-behavior",
-        license = "//lib:LICENSE-polymer",
-        deps = [":polymer"],
-    )
-    bower_component(
-        name = "iron-selector",
-        license = "//lib:LICENSE-polymer",
-        deps = [":polymer"],
-        seed = True,
-    )
-    bower_component(
-        name = "iron-test-helpers",
-        license = "//lib:LICENSE-DO_NOT_DISTRIBUTE",
-        deps = [":polymer"],
-        seed = True,
-    )
-    bower_component(
-        name = "iron-validatable-behavior",
-        license = "//lib:LICENSE-polymer",
-        deps = [
-            ":iron-meta",
-            ":polymer",
-        ],
-    )
-    bower_component(
-        name = "lodash",
-        license = "//lib:LICENSE-DO_NOT_DISTRIBUTE",
-    )
-    bower_component(
-        name = "mocha",
-        license = "//lib:LICENSE-DO_NOT_DISTRIBUTE",
-    )
-    bower_component(
-        name = "moment",
-        license = "//lib:LICENSE-moment",
-        seed = True,
-    )
-    bower_component(
-        name = "neon-animation",
-        license = "//lib:LICENSE-polymer",
-        deps = [
-            ":iron-resizable-behavior",
-            ":iron-selector",
-            ":polymer",
-        ],
-    )
-    bower_component(
-        name = "page",
-        license = "//lib:LICENSE-page.js",
-        seed = True,
-    )
-    bower_component(
-        name = "paper-behaviors",
-        license = "//lib:LICENSE-polymer",
-        deps = [
-            ":iron-behaviors",
-            ":iron-checked-element-behavior",
-            ":paper-ripple",
-            ":polymer",
-        ],
-    )
-    bower_component(
-        name = "paper-button",
-        license = "//lib:LICENSE-polymer",
-        deps = [
-            ":iron-flex-layout",
-            ":paper-behaviors",
-            ":paper-styles",
-            ":polymer",
-        ],
-        seed = True,
-    )
-    bower_component(
-        name = "paper-icon-button",
-        license = "//lib:LICENSE-polymer",
-        deps = [
-            ":iron-icon",
-            ":paper-behaviors",
-            ":paper-styles",
-            ":polymer",
-        ],
-    )
-    bower_component(
-        name = "paper-input",
-        license = "//lib:LICENSE-polymer",
-        deps = [
-            ":iron-a11y-keys-behavior",
-            ":iron-autogrow-textarea",
-            ":iron-behaviors",
-            ":iron-form-element-behavior",
-            ":iron-input",
-            ":paper-styles",
-            ":polymer",
-        ],
-        seed = True,
-    )
-    bower_component(
-        name = "paper-item",
-        license = "//lib:LICENSE-polymer",
-        deps = [
-            ":iron-behaviors",
-            ":iron-flex-layout",
-            ":paper-styles",
-            ":polymer",
-        ],
-        seed = True,
-    )
-    bower_component(
-        name = "paper-listbox",
-        license = "//lib:LICENSE-polymer",
-        deps = [
-            ":iron-behaviors",
-            ":iron-menu-behavior",
-            ":paper-styles",
-            ":polymer",
-        ],
-        seed = True,
-    )
-    bower_component(
-        name = "paper-ripple",
-        license = "//lib:LICENSE-polymer",
-        deps = [
-            ":iron-a11y-keys-behavior",
-            ":polymer",
-        ],
-    )
-    bower_component(
-        name = "paper-styles",
-        license = "//lib:LICENSE-polymer",
-        deps = [
-            ":font-roboto-local",
-            ":iron-flex-layout",
-            ":polymer",
-        ],
-    )
-    bower_component(
-        name = "paper-tabs",
-        license = "//lib:LICENSE-polymer",
-        deps = [
-            ":iron-behaviors",
-            ":iron-flex-layout",
-            ":iron-icon",
-            ":iron-iconset-svg",
-            ":iron-menu-behavior",
-            ":iron-resizable-behavior",
-            ":paper-behaviors",
-            ":paper-icon-button",
-            ":paper-styles",
-            ":polymer",
-        ],
-        seed = True,
-    )
-    bower_component(
-        name = "paper-toggle-button",
-        license = "//lib:LICENSE-polymer",
-        deps = [
-            ":iron-checked-element-behavior",
-            ":paper-behaviors",
-            ":paper-styles",
-            ":polymer",
-        ],
-        seed = True,
-    )
-    bower_component(
-        name = "polymer-resin",
-        license = "//lib:LICENSE-polymer",
-        deps = [
-            ":polymer",
-            ":webcomponentsjs",
-        ],
-        seed = True,
-    )
-    bower_component(
-        name = "polymer",
-        license = "//lib:LICENSE-polymer",
-        deps = [
-            ":shadycss",
-            ":webcomponentsjs",
-        ],
-        seed = True,
-    )
-    bower_component(
-        name = "shadycss",
-        license = "//lib:LICENSE-shadycss",
-    )
-    bower_component(
-        name = "sinon-chai",
-        license = "//lib:LICENSE-DO_NOT_DISTRIBUTE",
-    )
-    bower_component(
-        name = "sinonjs",
-        license = "//lib:LICENSE-DO_NOT_DISTRIBUTE",
-    )
-    bower_component(
-        name = "stacky",
-        license = "//lib:LICENSE-DO_NOT_DISTRIBUTE",
-    )
-    bower_component(
-        name = "test-fixture",
-        license = "//lib:LICENSE-DO_NOT_DISTRIBUTE",
-        seed = True,
-    )
-    bower_component(
-        name = "web-component-tester",
-        license = "//lib:LICENSE-DO_NOT_DISTRIBUTE",
-        deps = [
-            ":accessibility-developer-tools",
-            ":async",
-            ":chai",
-            ":lodash",
-            ":mocha",
-            ":sinon-chai",
-            ":sinonjs",
-            ":stacky",
-            ":test-fixture",
-        ],
-        seed = True,
-    )
-    bower_component(
-        name = "webcomponentsjs",
-        license = "//lib:LICENSE-polymer",
-    )
diff --git a/modules/jgit b/modules/jgit
index 730b7a5..ffb0a64 160000
--- a/modules/jgit
+++ b/modules/jgit
@@ -1 +1 @@
-Subproject commit 730b7a5ebf149e8df085a19ce4d4eddcea5958dd
+Subproject commit ffb0a644641cd5b9ae13a51c68f202a94a8f1207
diff --git a/package.json b/package.json
index 600f1ab..029e348 100644
--- a/package.json
+++ b/package.json
@@ -4,14 +4,16 @@
   "description": "Gerrit Code Review",
   "dependencies": {},
   "devDependencies": {
+    "@bazel/rollup": "^1.1.0",
+    "@bazel/typescript": "^1.0.1",
     "eslint": "^6.6.0",
     "eslint-config-google": "^0.13.0",
     "eslint-plugin-html": "^6.0.0",
     "eslint-plugin-jsdoc": "^18.4.3",
     "fried-twinkie": "^0.2.2",
     "polymer-cli": "^1.9.11",
-    "typescript": "^2.x.x",
-    "web-component-tester": "^6.5.0"
+    "typescript": "^3.7.4",
+    "web-component-tester": "^6.5.1"
   },
   "scripts": {
     "start": "polygerrit-ui/run-server.sh",
@@ -19,7 +21,7 @@
     "eslint": "./node_modules/eslint/bin/eslint.js --ext .html,.js polygerrit-ui/app",
     "eslintfix": "npm run eslint -- --fix",
     "test-template": "./polygerrit-ui/app/run_template_test.sh",
-    "polylint": "bazel test polygerrit-ui/app:polylint_test"
+    "polylint": "if [[ -z `which bazelisk 2>/dev/null` ]]; then bazel_bin=bazel; else bazel_bin=bazelisk; fi && $bazel_bin test polygerrit-ui/app:polylint_test"
   },
   "repository": {
     "type": "git",
diff --git a/polygerrit-ui/BUILD b/polygerrit-ui/BUILD
index 1c685ab..a029df4 100644
--- a/polygerrit-ui/BUILD
+++ b/polygerrit-ui/BUILD
@@ -1,40 +1,8 @@
 load("@io_bazel_rules_go//go:def.bzl", "go_binary")
 load("//tools/bzl:genrule2.bzl", "genrule2")
-load("//tools/bzl:js.bzl", "bower_component_bundle")
 
 package(default_visibility = ["//visibility:public"])
 
-bower_component_bundle(
-    name = "polygerrit_components.bower_components",
-    deps = [
-        "//lib/js:ba-linkify",
-        "//lib/js:es6-promise",
-        "//lib/js:fetch",
-        # Although highlightjs is inserted separately in the UI zip, it's used
-        # by local development servers (e.g. --polygerrit-dev or run-server.sh).
-        "//lib/js:highlightjs",
-        "//lib/js:iron-a11y-keys-behavior",
-        "//lib/js:iron-autogrow-textarea",
-        "//lib/js:iron-dropdown",
-        "//lib/js:iron-icon",
-        "//lib/js:iron-iconset-svg",
-        "//lib/js:iron-input",
-        "//lib/js:iron-overlay-behavior",
-        "//lib/js:iron-selector",
-        "//lib/js:moment",
-        "//lib/js:page",
-        "//lib/js:paper-button",
-        "//lib/js:paper-input",
-        "//lib/js:paper-item",
-        "//lib/js:paper-listbox",
-        "//lib/js:paper-tabs",
-        "//lib/js:paper-toggle-button",
-        "//lib/js:polymer",
-        "//lib/js:polymer-resin",
-        "//lib/js:shadycss",
-    ],
-)
-
 genrule2(
     name = "fonts",
     srcs = [
@@ -56,7 +24,8 @@
     srcs = ["server.go"],
     data = [
         ":fonts.zip",
-        "//polygerrit-ui/app:test_components.zip",
+        "@ui_dev_npm//:node_modules",
+        "@ui_npm//:node_modules",
     ],
     deps = [
         "@org_golang_x_tools//godoc/vfs/httpfs:go_default_library",
diff --git a/polygerrit-ui/README.md b/polygerrit-ui/README.md
index a35bd6f..c5dd657 100644
--- a/polygerrit-ui/README.md
+++ b/polygerrit-ui/README.md
@@ -12,11 +12,28 @@
 
 ## Installing [Node.js](https://nodejs.org/en/download/) and npm packages
 
+**Note**: Switch between an old branch with bower_components and a new branch with ui-npm
+packages (or vice versa) can lead to some build errors. To avoid such errors clean up the build
+repository:
+```sh
+rm -rf node_modules/ \
+    polygerrit-ui/node_modules/ \
+    polygerrit-ui/app/node_modules \
+    tools/node_tools/node_modules
+
+bazel clean
+```
+
+If it doesn't help also try to run
+```sh
+bazel clean --expunge
+```
+
 The minimum nodejs version supported is 8.x+
 
 ```sh
 # Debian experimental
-sudo apt-get install nodejs-legacy
+sudo apt-get install nodejs
 sudo apt-get install npm
 
 # OS X with Homebrew
@@ -27,22 +44,36 @@
 All other platforms:
 [download from nodejs.org](https://nodejs.org/en/download/).
 
-Various steps below require installing additional npm packages. The full list of
-dependencies can be installed with:
+or use [nvm - Node Version Manager](https://github.com/nvm-sh/nvm).
+
+Various steps below require installing additional npm packages. To start developing, it is enough
+to install only top-level packages with the following command: 
 
 ```sh
-npm install
+# Install packages from root-level packages.json
+bazel fetch @npm//:node_modules
 ```
 
-It may complain about a missing `typescript@2.3.4` peer dependency, which is
-harmless.
+All other packages are installed by bazel when needed. If you want to install them manually, run the
+following commands:
+```sh
+# Install packages from polygerrit-ui/app/packages.json
+bazel fetch @ui_npm//:node_modules
 
-## Running locally against production data
+# Install packages from polygerrit-ui/packages.json
+bazel fetch @ui_dev_npm//:node_modules
+
+# Install packages from tools/node_tools/packages.json
+bazel fetch @ui_dev_npm//:node_modules
+```
+
+More information for installing and using nodejs rules can be found here https://bazelbuild.github.io/rules_nodejs/install.html
+
+## Serving files locally
 
 #### Go server
 
-To test the local Polymer frontend against gerrit-review.googlesource.com
-simply execute:
+To test the local Polymer frontend against production data or a local test site execute:
 
 ```sh
 ./polygerrit-ui/run-server.sh
@@ -51,10 +82,7 @@
 npm run start
 ```
 
-Then visit http://localhost:8081
-
-This method is based on a
-[simple hand-written Go webserver](https://gerrit.googlesource.com/gerrit/+/master/polygerrit-ui/server.go).
+These commands start the [simple hand-written Go webserver](https://gerrit.googlesource.com/gerrit/+/master/polygerrit-ui/server.go).
 Mostly it just switches between serving files locally and proxying the real
 server based on the file name. It also does some basic response rewriting, e.g.
 it patches the `config/server/info` response with plugin information provided on
@@ -64,6 +92,12 @@
 ./polygerrit-ui/run-server.sh --plugins=plugins/my_plugin/static/my_plugin.js,plugins/my_plugin/static/my_plugin.html
 ```
 
+## Running locally against production data
+
+### Local website
+
+Start [Go server](#go-server) and then visit http://localhost:8081
+
 The biggest draw back of this method is that you cannot log in, so cannot test
 scenarios that require it.
 
@@ -87,9 +121,11 @@
 3. Optionally [populate](https://gerrit.googlesource.com/gerrit/+/master/contrib/populate-fixture-data.py) your test site with some test data.
 
 For running a locally built Gerrit war against your test instance use
-[this command](https://gerrit-review.googlesource.com/Documentation/dev-readme.html#run_daemon),
-and add the `--polygerrit-dev` option, if you want to serve the Polymer frontend
-directly from the sources in `polygerrit_ui/app/` instead of from the war:
+[this command](https://gerrit-review.googlesource.com/Documentation/dev-readme.html#run_daemon).
+
+If you want to serve the Polymer frontend directly from the sources in `polygerrit_ui/app/` instead of from the war:
+1. Start [Go server](#go-server)
+2. Add the `--dev-cdn` option:
 
 ```sh
 $(bazel info output_base)/external/local_jdk/bin/java \
@@ -97,16 +133,13 @@
     -jar bazel-bin/gerrit.war daemon \
     -d $GERRIT_SITE \
     --console-log \
-    --polygerrit-dev
+    --dev-cdn http://localhost:8081
 ```
 
+*NOTE* You can use any other cdn here, for example: https://cdn.googlesource.com/polygerrit_ui/678.0
+
 ## Running Tests
 
-This step requires the `web-component-tester` npm module.
-
-Note: it may be necessary to add the options `--unsafe-perm=true --allow-root`
-to the `npm install` command to avoid file permission errors.
-
 For daily development you typically only want to run and debug individual tests.
 Run the local [Go proxy server](#go-server) and navigate for example to
 <http://localhost:8081/elements/shared/gr-account-entry/gr-account-entry_test.html>.
@@ -188,9 +221,7 @@
 
 ## Template Type Safety
 
-> **Warning**: This feature is temporary disabled, because it doesn't work with Polymer 2 and Polymer 3.
-Some of the checks are made by polymer linter.
-
+> **Warning**: This feature is temporary disabled, because it doesn't work with Polymer 2 and Polymer 3. Some of the checks are made by polymer linter.
 
 Polymer elements are not type checked against the element definition, making it
 trivial to break the display when refactoring or moving code. We now run
@@ -228,3 +259,19 @@
 ```sh
 TEMPLATE_NO_DEFAULT=true ./polygerrit-ui/app/run_template_test.sh //polygerrit-ui/app:template_test_change-list --test_arg=gr-change-list-view
 ```
+
+## Contributing
+
+Our users report bugs / feature requests related to the UI through [Monorail Issues - PolyGerrit](https://bugs.chromium.org/p/gerrit/issues/list?q=component%3APolyGerrit).
+
+If you want to help, feel free to grab one from those `New` issues without
+assignees and send us a change.
+
+If you don't know who to assign to review your code change, you can use
+this special account: `gerrit-fe-reviewers@api-project-164060093628.iam.gserviceaccount.com`
+and just assign to that account, it will automatically pick two volunteers
+from the queue we have for FE reviewers.
+
+If you are willing to join the queue and help the community review changes,
+you can create an issue through Monorail and request to join the queue!
+We will review your request and start from there.
\ No newline at end of file
diff --git a/polygerrit-ui/app/.eslintrc.json b/polygerrit-ui/app/.eslintrc.json
index c14b787..82ef94a 100644
--- a/polygerrit-ui/app/.eslintrc.json
+++ b/polygerrit-ui/app/.eslintrc.json
@@ -1,7 +1,8 @@
 {
   "extends": ["eslint:recommended", "google"],
   "parserOptions": {
-    "ecmaVersion": 8
+    "ecmaVersion": 8,
+    "sourceType": "module"
   },
   "env": {
     "browser": true,
diff --git a/polygerrit-ui/app/.gitignore b/polygerrit-ui/app/.gitignore
index 375a75d..c235144 100644
--- a/polygerrit-ui/app/.gitignore
+++ b/polygerrit-ui/app/.gitignore
@@ -1 +1,2 @@
 /plugins/
+/node_modules/
diff --git a/polygerrit-ui/app/BUILD b/polygerrit-ui/app/BUILD
index e21dbe2..063f6c1 100644
--- a/polygerrit-ui/app/BUILD
+++ b/polygerrit-ui/app/BUILD
@@ -1,6 +1,5 @@
-load("//tools/bzl:genrule2.bzl", "genrule2")
-load("//tools/bzl:js.bzl", "bower_component_bundle")
 load(":rules.bzl", "polygerrit_bundle")
+load("//tools/node_tools/polygerrit_app_preprocessor:index.bzl", "update_links")
 
 package(default_visibility = ["//visibility:public"])
 
@@ -12,24 +11,15 @@
             "**/*.js",
         ],
         exclude = [
-            "bower_components/**",
+            "node_modules/**",
+            "node_modules_licenses/**",
             "test/**",
             "**/*_test.html",
         ],
     ),
     outs = ["polygerrit_ui.zip"],
-    app = "elements/gr-app.html",
-)
-
-bower_component_bundle(
-    name = "test_components",
-    testonly = True,
-    deps = [
-        "//lib/js:iron-test-helpers",
-        "//lib/js:test-fixture",
-        "//lib/js:web-component-tester",
-        "//polygerrit-ui:polygerrit_components.bower_components",
-    ],
+    entry_point = "elements/gr-app.html",
+    redirects = "redirects.json",
 )
 
 filegroup(
@@ -40,7 +30,8 @@
             "**/*.js",
         ],
         exclude = [
-            "bower_components/**",
+            "node_modules/**",
+            "node_modules_licenses/**",
         ],
     ),
 )
@@ -53,7 +44,8 @@
             "**/*.js",
         ],
         exclude = [
-            "bower_components/**",
+            "node_modules/**",
+            "node_modules_licenses/**",
             "**/*_test.html",
             "test/**",
             "samples/**",
@@ -61,30 +53,38 @@
     ),
 )
 
-genrule2(
-    name = "pg_code_zip",
-    srcs = [":pg_code"],
-    outs = ["pg_code.zip"],
-    cmd = " && ".join([
-        ("tar -hcf- $(locations :pg_code) |" +
-         " tar --strip-components=2 -C $$TMP/ -xf-"),
-        "cd $$TMP",
-        "TZ=UTC",
-        "export TZ",
-        "find . -exec touch -t 198001010000 '{}' ';'",
-        "zip -rq $$ROOT/$@ *",
-    ]),
+# update_links - temporary action. Later links/references will be updated in repository,
+# so this rule will be removed.
+update_links(
+    name = "test-srcs-updated-links",
+    srcs = [
+        "test/common-test-setup.html",
+        "test/index.html",
+        ":pg_code",
+    ],
+    redirects = "redirects.json",
+)
+
+# Workaround for https://github.com/bazelbuild/bazel/issues/1305
+filegroup(
+    name = "test-srcs-updated-links-fg",
+    srcs = [
+        ":test-srcs-updated-links",
+        "@ui_dev_npm//:node_modules",
+        "@ui_npm//:node_modules",
+    ],
 )
 
 sh_test(
     name = "wct_test",
     size = "enormous",
     srcs = ["wct_test.sh"],
+    args = [
+        "$(location @ui_dev_npm//web-component-tester/bin:wct)",
+    ],
     data = [
-        "test/common-test-setup.html",
-        "test/index.html",
-        ":pg_code.zip",
-        ":test_components.zip",
+        ":test-srcs-updated-links-fg",
+        "@ui_dev_npm//web-component-tester/bin:wct",
     ],
     # Should not run sandboxed.
     tags = [
@@ -109,14 +109,37 @@
     ],
 )
 
+# update_links - temporary action. Later links/references will be updated in repository,
+# so this rule will be removed.
+update_links(
+    name = "polylint-updated-links",
+    srcs = [
+        ":pg_code_without_test",
+    ],
+    redirects = "redirects.json",
+)
+
+# Workaround for https://github.com/bazelbuild/bazel/issues/1305
+filegroup(
+    name = "polylint-updated-links-fg",
+    srcs = [
+        ":polylint-updated-links",
+        "@ui_npm//:node_modules",
+    ],
+)
+
 sh_test(
     name = "polylint_test",
     size = "large",
     srcs = ["polylint_test.sh"],
+    args = [
+        "$(location @tools_npm//polymer-cli/bin:polymer)",
+        "$(location polymer.json)",
+    ],
     data = [
         "polymer.json",
-        ":pg_code_without_test",
-        "//polygerrit-ui:polygerrit_components.bower_components.zip",
+        ":polylint-updated-links-fg",
+        "@tools_npm//polymer-cli/bin:polymer",
     ],
     # Should not run sandboxed.
     tags = [
@@ -146,7 +169,6 @@
     data = [
         ":pg_code",
         ":template_test_srcs",
-        "//polygerrit-ui:polygerrit_components.bower_components.zip",
     ],
     tags = [
         # Should not run sandboxed.
diff --git a/polygerrit-ui/app/behaviors/async-foreach-behavior/async-foreach-behavior_test.html b/polygerrit-ui/app/behaviors/async-foreach-behavior/async-foreach-behavior_test.html
index 03ba6b1..f2f0e6b 100644
--- a/polygerrit-ui/app/behaviors/async-foreach-behavior/async-foreach-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/async-foreach-behavior/async-foreach-behavior_test.html
@@ -23,11 +23,13 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../test/common-test-setup.html"/>
 <link rel="import" href="async-foreach-behavior.html">
 
 <script>
-  suite('async-foreach-behavior tests', () => {
+  suite('async-foreach-behavior tests', async () => {
+    await readyToTest();
     test('loops over each item', () => {
       const fn = sinon.stub().returns(Promise.resolve());
       return Gerrit.AsyncForeachBehavior.asyncForeach([1, 2, 3], fn)
diff --git a/polygerrit-ui/app/behaviors/base-url-behavior/base-url-behavior_test.html b/polygerrit-ui/app/behaviors/base-url-behavior/base-url-behavior_test.html
index 5669bc4..eb6fd3f 100644
--- a/polygerrit-ui/app/behaviors/base-url-behavior/base-url-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/base-url-behavior/base-url-behavior_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../test/common-test-setup.html"/>
 <script>
   /** @type {string} */
@@ -45,7 +46,8 @@
 </test-fixture>
 
 <script>
-  suite('base-url-behavior tests', () => {
+  suite('base-url-behavior tests', async () => {
+    await readyToTest();
     let element;
     // eslint-disable-next-line no-unused-vars
     let overlay;
diff --git a/polygerrit-ui/app/behaviors/docs-url-behavior/docs-url-behavior_test.html b/polygerrit-ui/app/behaviors/docs-url-behavior/docs-url-behavior_test.html
index e554012..e480e30 100644
--- a/polygerrit-ui/app/behaviors/docs-url-behavior/docs-url-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/docs-url-behavior/docs-url-behavior_test.html
@@ -17,6 +17,7 @@
 <!-- Polymer included for the html import polyfill. -->
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../test/common-test-setup.html"/>
 <title>docs-url-behavior</title>
 
@@ -33,7 +34,8 @@
 </test-fixture>
 
 <script>
-  suite('docs-url-behavior tests', () => {
+  suite('docs-url-behavior tests', async () => {
+    await readyToTest();
     let element;
 
     suiteSetup(() => {
diff --git a/polygerrit-ui/app/behaviors/dom-util-behavior/dom-util-behavior_test.html b/polygerrit-ui/app/behaviors/dom-util-behavior/dom-util-behavior_test.html
index a52e0e2..9acc749 100644
--- a/polygerrit-ui/app/behaviors/dom-util-behavior/dom-util-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/dom-util-behavior/dom-util-behavior_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../test/common-test-setup.html"/>
 <link rel="import" href="dom-util-behavior.html">
 
@@ -40,7 +41,8 @@
 </test-fixture>
 
 <script>
-  suite('dom-util-behavior tests', () => {
+  suite('dom-util-behavior tests', async () => {
+    await readyToTest();
     let element;
     let divs;
 
diff --git a/polygerrit-ui/app/behaviors/gr-access-behavior/gr-access-behavior_test.html b/polygerrit-ui/app/behaviors/gr-access-behavior/gr-access-behavior_test.html
index 48565a6..f4b3ab0 100644
--- a/polygerrit-ui/app/behaviors/gr-access-behavior/gr-access-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/gr-access-behavior/gr-access-behavior_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../test/common-test-setup.html"/>
 <link rel="import" href="gr-access-behavior.html">
 
@@ -33,7 +34,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-access-behavior tests', () => {
+  suite('gr-access-behavior tests', async () => {
+    await readyToTest();
     let element;
 
     suiteSetup(() => {
diff --git a/polygerrit-ui/app/behaviors/gr-admin-nav-behavior/gr-admin-nav-behavior_test.html b/polygerrit-ui/app/behaviors/gr-admin-nav-behavior/gr-admin-nav-behavior_test.html
index d02483f..7c179b8 100644
--- a/polygerrit-ui/app/behaviors/gr-admin-nav-behavior/gr-admin-nav-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/gr-admin-nav-behavior/gr-admin-nav-behavior_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../test/common-test-setup.html"/>
 <link rel="import" href="gr-admin-nav-behavior.html">
 
@@ -33,7 +34,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-admin-nav-behavior tests', () => {
+  suite('gr-admin-nav-behavior tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
     let capabilityStub;
diff --git a/polygerrit-ui/app/behaviors/gr-change-table-behavior/gr-change-table-behavior_test.html b/polygerrit-ui/app/behaviors/gr-change-table-behavior/gr-change-table-behavior_test.html
index 52931bc..a8d4041 100644
--- a/polygerrit-ui/app/behaviors/gr-change-table-behavior/gr-change-table-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/gr-change-table-behavior/gr-change-table-behavior_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../test/common-test-setup.html"/>
 <link rel="import" href="gr-change-table-behavior.html">
 
@@ -41,7 +42,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-change-table-behavior tests', () => {
+  suite('gr-change-table-behavior tests', async () => {
+    await readyToTest();
     let element;
     // eslint-disable-next-line no-unused-vars
     let overlay;
diff --git a/polygerrit-ui/app/behaviors/gr-display-name-behavior/gr-display-name-behavior_test.html b/polygerrit-ui/app/behaviors/gr-display-name-behavior/gr-display-name-behavior_test.html
index aa217a1..931f6fa 100644
--- a/polygerrit-ui/app/behaviors/gr-display-name-behavior/gr-display-name-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/gr-display-name-behavior/gr-display-name-behavior_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../test/common-test-setup.html"/>
 <link rel="import" href="gr-display-name-behavior.html">
 
@@ -33,7 +34,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-display-name-behavior tests', () => {
+  suite('gr-display-name-behavior tests', async () => {
+    await readyToTest();
     let element;
     // eslint-disable-next-line no-unused-vars
     const config = {
diff --git a/polygerrit-ui/app/behaviors/gr-list-view-behavior/gr-list-view-behavior_test.html b/polygerrit-ui/app/behaviors/gr-list-view-behavior/gr-list-view-behavior_test.html
index 9b48cdc..c2cb073 100644
--- a/polygerrit-ui/app/behaviors/gr-list-view-behavior/gr-list-view-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/gr-list-view-behavior/gr-list-view-behavior_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../test/common-test-setup.html"/>
 <link rel="import" href="gr-list-view-behavior.html">
 
@@ -33,7 +34,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-list-view-behavior tests', () => {
+  suite('gr-list-view-behavior tests', async () => {
+    await readyToTest();
     let element;
     // eslint-disable-next-line no-unused-vars
     let overlay;
diff --git a/polygerrit-ui/app/behaviors/gr-patch-set-behavior/gr-patch-set-behavior_test.html b/polygerrit-ui/app/behaviors/gr-patch-set-behavior/gr-patch-set-behavior_test.html
index 0e4033e..d9adb8b 100644
--- a/polygerrit-ui/app/behaviors/gr-patch-set-behavior/gr-patch-set-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/gr-patch-set-behavior/gr-patch-set-behavior_test.html
@@ -17,6 +17,7 @@
 <!-- Polymer included for the html import polyfill. -->
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../test/common-test-setup.html"/>
 <title>gr-patch-set-behavior</title>
 
@@ -25,7 +26,8 @@
 <link rel="import" href="gr-patch-set-behavior.html">
 
 <script>
-  suite('gr-patch-set-behavior tests', () => {
+  suite('gr-patch-set-behavior tests', async () => {
+    await readyToTest();
     test('getRevisionByPatchNum', () => {
       const get = Gerrit.PatchSetBehavior.getRevisionByPatchNum;
       const revisions = [
diff --git a/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior_test.html b/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior_test.html
index 12b981c..740a8c8 100644
--- a/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior_test.html
@@ -17,6 +17,7 @@
 <!-- Polymer included for the html import polyfill. -->
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../test/common-test-setup.html"/>
 <title>gr-path-list-behavior</title>
 
@@ -25,7 +26,8 @@
 <link rel="import" href="gr-path-list-behavior.html">
 
 <script>
-  suite('gr-path-list-behavior tests', () => {
+  suite('gr-path-list-behavior tests', async () => {
+    await readyToTest();
     test('special sort', () => {
       const sort = Gerrit.PathListBehavior.specialFilePathCompare;
       const testFiles = [
diff --git a/polygerrit-ui/app/behaviors/gr-tooltip-behavior/gr-tooltip-behavior_test.html b/polygerrit-ui/app/behaviors/gr-tooltip-behavior/gr-tooltip-behavior_test.html
index f3354a4..53fea10 100644
--- a/polygerrit-ui/app/behaviors/gr-tooltip-behavior/gr-tooltip-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/gr-tooltip-behavior/gr-tooltip-behavior_test.html
@@ -22,6 +22,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../test/common-test-setup.html"/>
 <link rel="import" href="gr-tooltip-behavior.html">
 
@@ -34,7 +35,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-tooltip-behavior tests', () => {
+  suite('gr-tooltip-behavior tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/behaviors/gr-url-encoding-behavior/gr-url-encoding-behavior_test.html b/polygerrit-ui/app/behaviors/gr-url-encoding-behavior/gr-url-encoding-behavior_test.html
index 6cf2c68..b7a1d92 100644
--- a/polygerrit-ui/app/behaviors/gr-url-encoding-behavior/gr-url-encoding-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/gr-url-encoding-behavior/gr-url-encoding-behavior_test.html
@@ -22,6 +22,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../test/common-test-setup.html"/>
 <link rel="import" href="gr-url-encoding-behavior.html">
 
@@ -34,7 +35,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-url-encoding-behavior tests', () => {
+  suite('gr-url-encoding-behavior tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html b/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html
index 97c792a..a22c3ba 100644
--- a/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html
+++ b/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html
@@ -98,6 +98,7 @@
 -->
 <link rel="import" href="/bower_components/polymer/polymer.html">
 <link rel="import" href="/bower_components/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
+<script src="../../types/polymer-behaviors.js"></script>
 
 <script>
 (function(window) {
@@ -182,6 +183,7 @@
     SEARCH: 'SEARCH',
     SEND_REPLY: 'SEND_REPLY',
     EMOJI_DROPDOWN: 'EMOJI_DROPDOWN',
+    TOGGLE_BLAME: 'TOGGLE_BLAME',
   };
 
   const _help = new Map();
@@ -268,6 +270,7 @@
       'Toggle unified/side-by-side diff');
   _describe(Shortcut.NEXT_UNREVIEWED_FILE, ShortcutSection.DIFFS,
       'Mark file as reviewed and go to next unreviewed file');
+  _describe(Shortcut.TOGGLE_BLAME, ShortcutSection.DIFFS, 'Toggle blame');
 
   _describe(Shortcut.NEXT_FILE, ShortcutSection.NAVIGATION, 'Go to next file');
   _describe(Shortcut.PREV_FILE, ShortcutSection.NAVIGATION,
diff --git a/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior_test.html b/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior_test.html
index f1bbcb0..e7407f7 100644
--- a/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../test/common-test-setup.html"/>
 <link rel="import" href="keyboard-shortcut-behavior.html">
 
@@ -41,7 +42,8 @@
 </test-fixture>
 
 <script>
-  suite('keyboard-shortcut-behavior tests', () => {
+  suite('keyboard-shortcut-behavior tests', async () => {
+    await readyToTest();
     const kb = window.Gerrit.KeyboardShortcutBinder;
 
     let element;
diff --git a/polygerrit-ui/app/behaviors/rest-client-behavior/rest-client-behavior_test.html b/polygerrit-ui/app/behaviors/rest-client-behavior/rest-client-behavior_test.html
index cfcc11e..4bcd928 100644
--- a/polygerrit-ui/app/behaviors/rest-client-behavior/rest-client-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/rest-client-behavior/rest-client-behavior_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../test/common-test-setup.html"/>
 <script>
   /** @type {string} */
@@ -47,7 +48,8 @@
 </test-fixture>
 
 <script>
-  suite('rest-client-behavior tests', () => {
+  suite('rest-client-behavior tests', async () => {
+    await readyToTest();
     let element;
     // eslint-disable-next-line no-unused-vars
     let overlay;
diff --git a/polygerrit-ui/app/behaviors/safe-types-behavior/safe-types-behavior_test.html b/polygerrit-ui/app/behaviors/safe-types-behavior/safe-types-behavior_test.html
index 7351647..e123c96 100644
--- a/polygerrit-ui/app/behaviors/safe-types-behavior/safe-types-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/safe-types-behavior/safe-types-behavior_test.html
@@ -22,6 +22,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../test/common-test-setup.html"/>
 <link rel="import" href="safe-types-behavior.html">
 
@@ -34,7 +35,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-tooltip-behavior tests', () => {
+  suite('gr-tooltip-behavior tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_test.html b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_test.html
index e0c1f92d..78694b7 100644
--- a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_test.html
@@ -24,6 +24,7 @@
 <script src="/bower_components/page/page.js"></script>
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-access-section.html">
 
@@ -36,7 +37,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-access-section tests', () => {
+  suite('gr-access-section tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list_test.html b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list_test.html
index 51fa2e0..098ef14 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list_test.html
@@ -25,6 +25,7 @@
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
 
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 
 <link rel="import" href="gr-admin-group-list.html">
@@ -54,7 +55,8 @@
     };
   };
 
-  suite('gr-admin-group-list tests', () => {
+  suite('gr-admin-group-list tests', async () => {
+    await readyToTest();
     let element;
     let groups;
     let sandbox;
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.html b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.html
index 7b0c723..8436cf1 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-admin-view.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-admin-view tests', () => {
+  suite('gr-admin-view tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog_test.html b/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog_test.html
index c83349b..6919d3c 100644
--- a/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-confirm-delete-item-dialog.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-confirm-delete-item-dialog tests', () => {
+  suite('gr-confirm-delete-item-dialog tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_test.html b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_test.html
index 67c8537..aad2428f 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-create-change-dialog.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-create-change-dialog tests', () => {
+  suite('gr-create-change-dialog tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog_test.html b/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog_test.html
index 3a99526..d630556 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog_test.html
@@ -24,6 +24,7 @@
 <script src="/bower_components/page/page.js"></script>
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-create-group-dialog.html">
 
@@ -36,7 +37,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-create-group-dialog tests', () => {
+  suite('gr-create-group-dialog tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
     const GROUP_NAME = 'test-group';
diff --git a/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog_test.html b/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog_test.html
index 43d5fbe..db33587 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-create-pointer-dialog.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-create-pointer-dialog tests', () => {
+  suite('gr-create-pointer-dialog tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.html b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.html
index 80f953b..578c074 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-create-repo-dialog.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-create-repo-dialog tests', () => {
+  suite('gr-create-repo-dialog tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_test.html b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_test.html
index d517242..3a75611 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-group-audit-log.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-group-audit-log tests', () => {
+  suite('gr-group-audit-log tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_test.html b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_test.html
index 1df2a41..ec9a80c 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-group-members.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-group-members tests', () => {
+  suite('gr-group-members tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
     let groups;
diff --git a/polygerrit-ui/app/elements/admin/gr-group/gr-group_test.html b/polygerrit-ui/app/elements/admin/gr-group/gr-group_test.html
index 5534cde..a6aebbf 100644
--- a/polygerrit-ui/app/elements/admin/gr-group/gr-group_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-group/gr-group_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-group.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-group tests', () => {
+  suite('gr-group tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
     let groupStub;
diff --git a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_test.html b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_test.html
index 9928b9e..80c05d3 100644
--- a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_test.html
@@ -24,6 +24,7 @@
 <script src="/bower_components/page/page.js"></script>
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-permission.html">
 
@@ -36,7 +37,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-permission tests', () => {
+  suite('gr-permission tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/admin/gr-plugin-config-array-editor/gr-plugin-config-array-editor_test.html b/polygerrit-ui/app/elements/admin/gr-plugin-config-array-editor/gr-plugin-config-array-editor_test.html
index 5198ad0..3342967 100644
--- a/polygerrit-ui/app/elements/admin/gr-plugin-config-array-editor/gr-plugin-config-array-editor_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-plugin-config-array-editor/gr-plugin-config-array-editor_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-plugin-config-array-editor.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-plugin-config-array-editor tests', () => {
+  suite('gr-plugin-config-array-editor tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
     let dispatchStub;
diff --git a/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list_test.html b/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list_test.html
index a80e575..67a6c3f 100644
--- a/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list_test.html
@@ -24,6 +24,7 @@
 <script src="/bower_components/page/page.js"></script>
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-plugin-list.html">
 
@@ -50,7 +51,8 @@
     return plugin;
   };
 
-  suite('gr-plugin-list tests', () => {
+  suite('gr-plugin-list tests', async () => {
+    await readyToTest();
     let element;
     let plugins;
     let sandbox;
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.html b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.html
index e0e25e0..8b3fd82 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.html
@@ -24,6 +24,7 @@
 <script src="/bower_components/page/page.js"></script>
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-repo-access.html">
 
@@ -36,7 +37,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-repo-access tests', () => {
+  suite('gr-repo-access tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
     let repoStub;
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-command/gr-repo-command_test.html b/polygerrit-ui/app/elements/admin/gr-repo-command/gr-repo-command_test.html
index b8ec7e8..f4988a5 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-command/gr-repo-command_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo-command/gr-repo-command_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-repo-command.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-repo-command tests', () => {
+  suite('gr-repo-command tests', async () => {
+    await readyToTest();
     let element;
 
     setup(() => {
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_test.html b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_test.html
index fc6bd4b..830660b 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_test.html
@@ -24,6 +24,7 @@
 <script src="/bower_components/page/page.js"></script>
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-repo-commands.html">
 
@@ -36,7 +37,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-repo-commands tests', () => {
+  suite('gr-repo-commands tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
     let repoStub;
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards_test.html b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards_test.html
index 06496de..681ee19 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-repo-dashboards.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-repo-dashboards tests', () => {
+  suite('gr-repo-dashboards tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_test.html b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_test.html
index 0a99e60..4a99afc 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_test.html
@@ -24,6 +24,7 @@
 <script src="/bower_components/page/page.js"></script>
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-repo-detail-list.html">
 
@@ -69,495 +70,498 @@
     };
   };
 
-  suite('Branches', () => {
-    let element;
-    let branches;
-    let sandbox;
+  suite('gr-repo-detail-list', async () => {
+    await readyToTest();
+    suite('Branches', () => {
+      let element;
+      let branches;
+      let sandbox;
 
-    setup(() => {
-      sandbox = sinon.sandbox.create();
-      element = fixture('basic');
-      element.detailType = 'branches';
-      counter = 0;
-      sandbox.stub(page, 'show');
-    });
-
-    teardown(() => {
-      sandbox.restore();
-    });
-
-    suite('list of repo branches', () => {
-      setup(done => {
-        branches = [{
-          ref: 'HEAD',
-          revision: 'master',
-        }].concat(_.times(25, branchGenerator));
-
-        stub('gr-rest-api-interface', {
-          getRepoBranches(num, project, offset) {
-            return Promise.resolve(branches);
-          },
-        });
-
-        const params = {
-          repo: 'test',
-          detail: 'branches',
-        };
-
-        element._paramsChanged(params).then(() => { flush(done); });
+      setup(() => {
+        sandbox = sinon.sandbox.create();
+        element = fixture('basic');
+        element.detailType = 'branches';
+        counter = 0;
+        sandbox.stub(page, 'show');
       });
 
-      test('test for branch in the list', done => {
-        flush(() => {
-          assert.equal(element._items[2].ref, 'refs/heads/test2');
-          done();
+      teardown(() => {
+        sandbox.restore();
+      });
+
+      suite('list of repo branches', () => {
+        setup(done => {
+          branches = [{
+            ref: 'HEAD',
+            revision: 'master',
+          }].concat(_.times(25, branchGenerator));
+
+          stub('gr-rest-api-interface', {
+            getRepoBranches(num, project, offset) {
+              return Promise.resolve(branches);
+            },
+          });
+
+          const params = {
+            repo: 'test',
+            detail: 'branches',
+          };
+
+          element._paramsChanged(params).then(() => { flush(done); });
+        });
+
+        test('test for branch in the list', done => {
+          flush(() => {
+            assert.equal(element._items[2].ref, 'refs/heads/test2');
+            done();
+          });
+        });
+
+        test('test for web links in the branches list', done => {
+          flush(() => {
+            assert.equal(element._items[2].web_links[0].url,
+                'https://git.example.org/branch/test;refs/heads/test2');
+            done();
+          });
+        });
+
+        test('test for refs/heads/ being striped from ref', done => {
+          flush(() => {
+            assert.equal(element._stripRefs(element._items[2].ref,
+                element.detailType), 'test2');
+            done();
+          });
+        });
+
+        test('_shownItems', () => {
+          assert.equal(element._shownItems.length, 25);
+        });
+
+        test('Edit HEAD button not admin', done => {
+          sandbox.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
+          sandbox.stub(element.$.restAPI, 'getRepoAccess').returns(
+              Promise.resolve({
+                test: {is_owner: false},
+              }));
+          element._determineIfOwner('test').then(() => {
+            assert.equal(element._isOwner, false);
+            assert.equal(getComputedStyle(Polymer.dom(element.root)
+                .querySelector('.revisionNoEditing')).display, 'inline');
+            assert.equal(getComputedStyle(Polymer.dom(element.root)
+                .querySelector('.revisionEdit')).display, 'none');
+            done();
+          });
+        });
+
+        test('Edit HEAD button admin', done => {
+          const saveBtn = Polymer.dom(element.root).querySelector('.saveBtn');
+          const cancelBtn = Polymer.dom(element.root).querySelector('.cancelBtn');
+          const editBtn = Polymer.dom(element.root).querySelector('.editBtn');
+          const revisionNoEditing = Polymer.dom(element.root)
+              .querySelector('.revisionNoEditing');
+          const revisionWithEditing = Polymer.dom(element.root)
+              .querySelector('.revisionWithEditing');
+
+          sandbox.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
+          sandbox.stub(element.$.restAPI, 'getRepoAccess').returns(
+              Promise.resolve({
+                test: {is_owner: true},
+              }));
+          sandbox.stub(element, '_handleSaveRevision');
+          element._determineIfOwner('test').then(() => {
+            assert.equal(element._isOwner, true);
+            // The revision container for non-editing enabled row is not visible.
+            assert.equal(getComputedStyle(revisionNoEditing).display, 'none');
+
+            // The revision container for editing enabled row is visible.
+            assert.notEqual(getComputedStyle(Polymer.dom(element.root)
+                .querySelector('.revisionEdit')).display, 'none');
+
+            // The revision and edit button are visible.
+            assert.notEqual(getComputedStyle(revisionWithEditing).display,
+                'none');
+            assert.notEqual(getComputedStyle(editBtn).display, 'none');
+
+            // The input, cancel, and save buttons are not visible.
+            const hiddenElements = Polymer.dom(element.root)
+                .querySelectorAll('.canEdit .editItem');
+
+            for (const item of hiddenElements) {
+              assert.equal(getComputedStyle(item).display, 'none');
+            }
+
+            MockInteractions.tap(editBtn);
+            flushAsynchronousOperations();
+            // The revision and edit button are not visible.
+            assert.equal(getComputedStyle(revisionWithEditing).display, 'none');
+            assert.equal(getComputedStyle(editBtn).display, 'none');
+
+            // The input, cancel, and save buttons are not visible.
+            for (item of hiddenElements) {
+              assert.notEqual(getComputedStyle(item).display, 'none');
+            }
+
+            // The revised ref was set correctly
+            assert.equal(element._revisedRef, 'master');
+
+            assert.isFalse(saveBtn.disabled);
+
+            // Delete the ref.
+            element._revisedRef = '';
+            assert.isTrue(saveBtn.disabled);
+
+            // Change the ref to something else
+            element._revisedRef = 'newRef';
+            element._repo = 'test';
+            assert.isFalse(saveBtn.disabled);
+
+            // Save button calls handleSave. since this is stubbed, the edit
+            // section remains open.
+            MockInteractions.tap(saveBtn);
+            assert.isTrue(element._handleSaveRevision.called);
+
+            // When cancel is tapped, the edit secion closes.
+            MockInteractions.tap(cancelBtn);
+            flushAsynchronousOperations();
+
+            // The revision and edit button are visible.
+            assert.notEqual(getComputedStyle(revisionWithEditing).display,
+                'none');
+            assert.notEqual(getComputedStyle(editBtn).display, 'none');
+
+            // The input, cancel, and save buttons are not visible.
+            for (const item of hiddenElements) {
+              assert.equal(getComputedStyle(item).display, 'none');
+            }
+            done();
+          });
+        });
+
+        test('_handleSaveRevision with invalid rev', done => {
+          const event = {model: {set: sandbox.stub()}};
+          element._isEditing = true;
+          sandbox.stub(element.$.restAPI, 'setRepoHead').returns(
+              Promise.resolve({
+                status: 400,
+              })
+          );
+
+          element._setRepoHead('test', 'newRef', event).then(() => {
+            assert.isTrue(element._isEditing);
+            assert.isFalse(event.model.set.called);
+            done();
+          });
+        });
+
+        test('_handleSaveRevision with valid rev', done => {
+          const event = {model: {set: sandbox.stub()}};
+          element._isEditing = true;
+          sandbox.stub(element.$.restAPI, 'setRepoHead').returns(
+              Promise.resolve({
+                status: 200,
+              })
+          );
+
+          element._setRepoHead('test', 'newRef', event).then(() => {
+            assert.isFalse(element._isEditing);
+            assert.isTrue(event.model.set.called);
+            done();
+          });
+        });
+
+        test('test _computeItemName', () => {
+          assert.deepEqual(element._computeItemName('branches'), 'Branch');
+          assert.deepEqual(element._computeItemName('tags'), 'Tag');
         });
       });
 
-      test('test for web links in the branches list', done => {
-        flush(() => {
-          assert.equal(element._items[2].web_links[0].url,
-              'https://git.example.org/branch/test;refs/heads/test2');
-          done();
+      suite('list with less then 25 branches', () => {
+        setup(done => {
+          branches = _.times(25, branchGenerator);
+
+          stub('gr-rest-api-interface', {
+            getRepoBranches(num, repo, offset) {
+              return Promise.resolve(branches);
+            },
+          });
+
+          const params = {
+            repo: 'test',
+            detail: 'branches',
+          };
+
+          element._paramsChanged(params).then(() => { flush(done); });
+        });
+
+        test('_shownItems', () => {
+          assert.equal(element._shownItems.length, 25);
         });
       });
 
-      test('test for refs/heads/ being striped from ref', done => {
-        flush(() => {
-          assert.equal(element._stripRefs(element._items[2].ref,
-              element.detailType), 'test2');
-          done();
+      suite('filter', () => {
+        test('_paramsChanged', done => {
+          sandbox.stub(
+              element.$.restAPI,
+              'getRepoBranches',
+              () => Promise.resolve(branches));
+          const params = {
+            detail: 'branches',
+            repo: 'test',
+            filter: 'test',
+            offset: 25,
+          };
+          element._paramsChanged(params).then(() => {
+            assert.equal(element.$.restAPI.getRepoBranches.lastCall.args[0],
+                'test');
+            assert.equal(element.$.restAPI.getRepoBranches.lastCall.args[1],
+                'test');
+            assert.equal(element.$.restAPI.getRepoBranches.lastCall.args[2],
+                25);
+            assert.equal(element.$.restAPI.getRepoBranches.lastCall.args[3],
+                25);
+            done();
+          });
         });
       });
 
-      test('_shownItems', () => {
-        assert.equal(element._shownItems.length, 25);
-      });
+      suite('404', () => {
+        test('fires page-error', done => {
+          const response = {status: 404};
+          sandbox.stub(element.$.restAPI, 'getRepoBranches',
+              (filter, repo, reposBranchesPerPage, opt_offset, errFn) => {
+                errFn(response);
+              });
 
-      test('Edit HEAD button not admin', done => {
-        sandbox.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
-        sandbox.stub(element.$.restAPI, 'getRepoAccess').returns(
-            Promise.resolve({
-              test: {is_owner: false},
-            }));
-        element._determineIfOwner('test').then(() => {
-          assert.equal(element._isOwner, false);
-          assert.equal(getComputedStyle(Polymer.dom(element.root)
-              .querySelector('.revisionNoEditing')).display, 'inline');
-          assert.equal(getComputedStyle(Polymer.dom(element.root)
-              .querySelector('.revisionEdit')).display, 'none');
-          done();
-        });
-      });
+          element.addEventListener('page-error', e => {
+            assert.deepEqual(e.detail.response, response);
+            done();
+          });
 
-      test('Edit HEAD button admin', done => {
-        const saveBtn = Polymer.dom(element.root).querySelector('.saveBtn');
-        const cancelBtn = Polymer.dom(element.root).querySelector('.cancelBtn');
-        const editBtn = Polymer.dom(element.root).querySelector('.editBtn');
-        const revisionNoEditing = Polymer.dom(element.root)
-            .querySelector('.revisionNoEditing');
-        const revisionWithEditing = Polymer.dom(element.root)
-            .querySelector('.revisionWithEditing');
-
-        sandbox.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
-        sandbox.stub(element.$.restAPI, 'getRepoAccess').returns(
-            Promise.resolve({
-              test: {is_owner: true},
-            }));
-        sandbox.stub(element, '_handleSaveRevision');
-        element._determineIfOwner('test').then(() => {
-          assert.equal(element._isOwner, true);
-          // The revision container for non-editing enabled row is not visible.
-          assert.equal(getComputedStyle(revisionNoEditing).display, 'none');
-
-          // The revision container for editing enabled row is visible.
-          assert.notEqual(getComputedStyle(Polymer.dom(element.root)
-              .querySelector('.revisionEdit')).display, 'none');
-
-          // The revision and edit button are visible.
-          assert.notEqual(getComputedStyle(revisionWithEditing).display,
-              'none');
-          assert.notEqual(getComputedStyle(editBtn).display, 'none');
-
-          // The input, cancel, and save buttons are not visible.
-          const hiddenElements = Polymer.dom(element.root)
-              .querySelectorAll('.canEdit .editItem');
-
-          for (const item of hiddenElements) {
-            assert.equal(getComputedStyle(item).display, 'none');
-          }
-
-          MockInteractions.tap(editBtn);
-          flushAsynchronousOperations();
-          // The revision and edit button are not visible.
-          assert.equal(getComputedStyle(revisionWithEditing).display, 'none');
-          assert.equal(getComputedStyle(editBtn).display, 'none');
-
-          // The input, cancel, and save buttons are not visible.
-          for (item of hiddenElements) {
-            assert.notEqual(getComputedStyle(item).display, 'none');
-          }
-
-          // The revised ref was set correctly
-          assert.equal(element._revisedRef, 'master');
-
-          assert.isFalse(saveBtn.disabled);
-
-          // Delete the ref.
-          element._revisedRef = '';
-          assert.isTrue(saveBtn.disabled);
-
-          // Change the ref to something else
-          element._revisedRef = 'newRef';
-          element._repo = 'test';
-          assert.isFalse(saveBtn.disabled);
-
-          // Save button calls handleSave. since this is stubbed, the edit
-          // section remains open.
-          MockInteractions.tap(saveBtn);
-          assert.isTrue(element._handleSaveRevision.called);
-
-          // When cancel is tapped, the edit secion closes.
-          MockInteractions.tap(cancelBtn);
-          flushAsynchronousOperations();
-
-          // The revision and edit button are visible.
-          assert.notEqual(getComputedStyle(revisionWithEditing).display,
-              'none');
-          assert.notEqual(getComputedStyle(editBtn).display, 'none');
-
-          // The input, cancel, and save buttons are not visible.
-          for (const item of hiddenElements) {
-            assert.equal(getComputedStyle(item).display, 'none');
-          }
-          done();
-        });
-      });
-
-      test('_handleSaveRevision with invalid rev', done => {
-        const event = {model: {set: sandbox.stub()}};
-        element._isEditing = true;
-        sandbox.stub(element.$.restAPI, 'setRepoHead').returns(
-            Promise.resolve({
-              status: 400,
-            })
-        );
-
-        element._setRepoHead('test', 'newRef', event).then(() => {
-          assert.isTrue(element._isEditing);
-          assert.isFalse(event.model.set.called);
-          done();
-        });
-      });
-
-      test('_handleSaveRevision with valid rev', done => {
-        const event = {model: {set: sandbox.stub()}};
-        element._isEditing = true;
-        sandbox.stub(element.$.restAPI, 'setRepoHead').returns(
-            Promise.resolve({
-              status: 200,
-            })
-        );
-
-        element._setRepoHead('test', 'newRef', event).then(() => {
-          assert.isFalse(element._isEditing);
-          assert.isTrue(event.model.set.called);
-          done();
-        });
-      });
-
-      test('test _computeItemName', () => {
-        assert.deepEqual(element._computeItemName('branches'), 'Branch');
-        assert.deepEqual(element._computeItemName('tags'), 'Tag');
-      });
-    });
-
-    suite('list with less then 25 branches', () => {
-      setup(done => {
-        branches = _.times(25, branchGenerator);
-
-        stub('gr-rest-api-interface', {
-          getRepoBranches(num, repo, offset) {
-            return Promise.resolve(branches);
-          },
-        });
-
-        const params = {
-          repo: 'test',
-          detail: 'branches',
-        };
-
-        element._paramsChanged(params).then(() => { flush(done); });
-      });
-
-      test('_shownItems', () => {
-        assert.equal(element._shownItems.length, 25);
-      });
-    });
-
-    suite('filter', () => {
-      test('_paramsChanged', done => {
-        sandbox.stub(
-            element.$.restAPI,
-            'getRepoBranches',
-            () => Promise.resolve(branches));
-        const params = {
-          detail: 'branches',
-          repo: 'test',
-          filter: 'test',
-          offset: 25,
-        };
-        element._paramsChanged(params).then(() => {
-          assert.equal(element.$.restAPI.getRepoBranches.lastCall.args[0],
-              'test');
-          assert.equal(element.$.restAPI.getRepoBranches.lastCall.args[1],
-              'test');
-          assert.equal(element.$.restAPI.getRepoBranches.lastCall.args[2],
-              25);
-          assert.equal(element.$.restAPI.getRepoBranches.lastCall.args[3],
-              25);
-          done();
+          const params = {
+            detail: 'branches',
+            repo: 'test',
+            filter: 'test',
+            offset: 25,
+          };
+          element._paramsChanged(params);
         });
       });
     });
 
-    suite('404', () => {
-      test('fires page-error', done => {
-        const response = {status: 404};
-        sandbox.stub(element.$.restAPI, 'getRepoBranches',
-            (filter, repo, reposBranchesPerPage, opt_offset, errFn) => {
-              errFn(response);
-            });
+    suite('Tags', () => {
+      let element;
+      let tags;
+      let sandbox;
 
-        element.addEventListener('page-error', e => {
-          assert.deepEqual(e.detail.response, response);
-          done();
-        });
-
-        const params = {
-          detail: 'branches',
-          repo: 'test',
-          filter: 'test',
-          offset: 25,
-        };
-        element._paramsChanged(params);
-      });
-    });
-  });
-
-  suite('Tags', () => {
-    let element;
-    let tags;
-    let sandbox;
-
-    setup(() => {
-      sandbox = sinon.sandbox.create();
-      element = fixture('basic');
-      element.detailType = 'tags';
-      counter = 0;
-      sandbox.stub(page, 'show');
-    });
-
-    teardown(() => {
-      sandbox.restore();
-    });
-
-    test('_computeMessage', () => {
-      let message = 'v2.15-rc1↵-----BEGIN PGP SIGNATURE-----↵Version: GnuPG v' +
-      '1↵↵iQIcBAABAgAGBQJZ27O7AAoJEF/XxZqaEoiMy6kQAMoQCpGr3J6JITI4BVWsr7QM↵xy' +
-      'EcWH5YPUko5EPTbkABHmaVyFmKGkuIQdn6c+NIbqJOk+5XT4oUyRSo1T569HPJ↵3kyxEJi' +
-      'T1ryvp5BIHwdvHx58fjw1+YkiWLZuZq1FFkUYqnWTYCrkv7Fok98pdOmV↵CL1Hgugi5uK8' +
-      '/kxf1M7+Nv6piaZ140pwSb1h6QdAjaZVfaBCnoxlG4LRUqHvEYay↵f4QYgFT67auHIGkZ4' +
-      'moUcsp2Du/1jSsCWL/CPwjPFGbbckVAjLCMT9yD3NKwpEZF↵pfsiZyHI9dL0M+QjVrM+RD' +
-      'HwIIJwra8R0IMkDlQ6MDrFlKNqNBbo588S6UPrm71L↵YuiwWlcrK9ZIybxT6LzbR65Rvez' +
-      'DSitQ+xeIfpZE19/X6BCnvlARLE8k/tC2JksI↵lEZi7Lf3FQdIcwwyt98tJkS9HX9v9jbC' +
-      '5QXifnoj3Li8tHSLuQ1dJCxHQiis6ojI↵OWUFkm0IHBXVNHA2dqYBdM+pL12mlI3wp6Ica' +
-      '4cdEVDwzu+j1xnVSFUa+d+Y2xJF↵7mytuyhHiKG4hm+zbhMv6WD8Q3FoDsJZeLY99l0hYQ' +
-      'SnnkMduFVroIs45pAs8gUA↵RvYla8mm9w/543IJAPzzFarPVLSsSyQ7tJl3UBzjKRNH/rX' +
-      'W+F22qyWD1zyHPUIR↵C00ItmwlAvveImYKpQAH↵=L+K9↵-----END PGP SIGNATURE---' +
-      '--';
-      assert.equal(element._computeMessage(message), 'v2.15-rc1↵');
-      message = 'v2.15-rc1';
-      assert.equal(element._computeMessage(message), 'v2.15-rc1');
-    });
-
-    suite('list of repo tags', () => {
-      setup(done => {
-        tags = _.times(26, tagGenerator);
-
-        stub('gr-rest-api-interface', {
-          getRepoTags(num, repo, offset) {
-            return Promise.resolve(tags);
-          },
-        });
-
-        const params = {
-          repo: 'test',
-          detail: 'tags',
-        };
-
-        element._paramsChanged(params).then(() => { flush(done); });
+      setup(() => {
+        sandbox = sinon.sandbox.create();
+        element = fixture('basic');
+        element.detailType = 'tags';
+        counter = 0;
+        sandbox.stub(page, 'show');
       });
 
-      test('test for tag in the list', done => {
-        flush(() => {
-          assert.equal(element._items[1].ref, 'refs/tags/test2');
-          done();
+      teardown(() => {
+        sandbox.restore();
+      });
+
+      test('_computeMessage', () => {
+        let message = 'v2.15-rc1↵-----BEGIN PGP SIGNATURE-----↵Version: GnuPG v' +
+        '1↵↵iQIcBAABAgAGBQJZ27O7AAoJEF/XxZqaEoiMy6kQAMoQCpGr3J6JITI4BVWsr7QM↵xy' +
+        'EcWH5YPUko5EPTbkABHmaVyFmKGkuIQdn6c+NIbqJOk+5XT4oUyRSo1T569HPJ↵3kyxEJi' +
+        'T1ryvp5BIHwdvHx58fjw1+YkiWLZuZq1FFkUYqnWTYCrkv7Fok98pdOmV↵CL1Hgugi5uK8' +
+        '/kxf1M7+Nv6piaZ140pwSb1h6QdAjaZVfaBCnoxlG4LRUqHvEYay↵f4QYgFT67auHIGkZ4' +
+        'moUcsp2Du/1jSsCWL/CPwjPFGbbckVAjLCMT9yD3NKwpEZF↵pfsiZyHI9dL0M+QjVrM+RD' +
+        'HwIIJwra8R0IMkDlQ6MDrFlKNqNBbo588S6UPrm71L↵YuiwWlcrK9ZIybxT6LzbR65Rvez' +
+        'DSitQ+xeIfpZE19/X6BCnvlARLE8k/tC2JksI↵lEZi7Lf3FQdIcwwyt98tJkS9HX9v9jbC' +
+        '5QXifnoj3Li8tHSLuQ1dJCxHQiis6ojI↵OWUFkm0IHBXVNHA2dqYBdM+pL12mlI3wp6Ica' +
+        '4cdEVDwzu+j1xnVSFUa+d+Y2xJF↵7mytuyhHiKG4hm+zbhMv6WD8Q3FoDsJZeLY99l0hYQ' +
+        'SnnkMduFVroIs45pAs8gUA↵RvYla8mm9w/543IJAPzzFarPVLSsSyQ7tJl3UBzjKRNH/rX' +
+        'W+F22qyWD1zyHPUIR↵C00ItmwlAvveImYKpQAH↵=L+K9↵-----END PGP SIGNATURE---' +
+        '--';
+        assert.equal(element._computeMessage(message), 'v2.15-rc1↵');
+        message = 'v2.15-rc1';
+        assert.equal(element._computeMessage(message), 'v2.15-rc1');
+      });
+
+      suite('list of repo tags', () => {
+        setup(done => {
+          tags = _.times(26, tagGenerator);
+
+          stub('gr-rest-api-interface', {
+            getRepoTags(num, repo, offset) {
+              return Promise.resolve(tags);
+            },
+          });
+
+          const params = {
+            repo: 'test',
+            detail: 'tags',
+          };
+
+          element._paramsChanged(params).then(() => { flush(done); });
+        });
+
+        test('test for tag in the list', done => {
+          flush(() => {
+            assert.equal(element._items[1].ref, 'refs/tags/test2');
+            done();
+          });
+        });
+
+        test('test for tag message in the list', done => {
+          flush(() => {
+            assert.equal(element._items[1].message, 'Annotated tag');
+            done();
+          });
+        });
+
+        test('test for tagger in the tag list', done => {
+          const tagger = {
+            name: 'Test User',
+            email: 'test.user@gmail.com',
+            date: '2017-09-19 14:54:00.000000000',
+            tz: 540,
+          };
+          flush(() => {
+            assert.deepEqual(element._items[1].tagger, tagger);
+            done();
+          });
+        });
+
+        test('test for web links in the tags list', done => {
+          flush(() => {
+            assert.equal(element._items[1].web_links[0].url,
+                'https://git.example.org/tag/test;refs/tags/test2');
+            done();
+          });
+        });
+
+        test('test for refs/tags/ being striped from ref', done => {
+          flush(() => {
+            assert.equal(element._stripRefs(element._items[1].ref,
+                element.detailType), 'test2');
+            done();
+          });
+        });
+
+        test('_shownItems', () => {
+          assert.equal(element._shownItems.length, 25);
+        });
+
+        test('_computeHideTagger', () => {
+          const testObject1 = {
+            tagger: 'test',
+          };
+          assert.equal(element._computeHideTagger(testObject1), '');
+
+          assert.equal(element._computeHideTagger(undefined), 'hide');
         });
       });
 
-      test('test for tag message in the list', done => {
-        flush(() => {
-          assert.equal(element._items[1].message, 'Annotated tag');
-          done();
+      suite('list with less then 25 tags', () => {
+        setup(done => {
+          tags = _.times(25, tagGenerator);
+
+          stub('gr-rest-api-interface', {
+            getRepoTags(num, project, offset) {
+              return Promise.resolve(tags);
+            },
+          });
+
+          const params = {
+            repo: 'test',
+            detail: 'tags',
+          };
+
+          element._paramsChanged(params).then(() => { flush(done); });
+        });
+
+        test('_shownItems', () => {
+          assert.equal(element._shownItems.length, 25);
         });
       });
 
-      test('test for tagger in the tag list', done => {
-        const tagger = {
-          name: 'Test User',
-          email: 'test.user@gmail.com',
-          date: '2017-09-19 14:54:00.000000000',
-          tz: 540,
-        };
-        flush(() => {
-          assert.deepEqual(element._items[1].tagger, tagger);
-          done();
+      suite('filter', () => {
+        test('_paramsChanged', done => {
+          sandbox.stub(
+              element.$.restAPI,
+              'getRepoTags',
+              () => Promise.resolve(tags));
+          const params = {
+            repo: 'test',
+            detail: 'tags',
+            filter: 'test',
+            offset: 25,
+          };
+          element._paramsChanged(params).then(() => {
+            assert.equal(element.$.restAPI.getRepoTags.lastCall.args[0],
+                'test');
+            assert.equal(element.$.restAPI.getRepoTags.lastCall.args[1],
+                'test');
+            assert.equal(element.$.restAPI.getRepoTags.lastCall.args[2],
+                25);
+            assert.equal(element.$.restAPI.getRepoTags.lastCall.args[3],
+                25);
+            done();
+          });
         });
       });
 
-      test('test for web links in the tags list', done => {
-        flush(() => {
-          assert.equal(element._items[1].web_links[0].url,
-              'https://git.example.org/tag/test;refs/tags/test2');
-          done();
+      suite('create new', () => {
+        test('_handleCreateClicked called when create-click fired', () => {
+          sandbox.stub(element, '_handleCreateClicked');
+          element.$$('gr-list-view').fire('create-clicked');
+          assert.isTrue(element._handleCreateClicked.called);
+        });
+
+        test('_handleCreateClicked opens modal', () => {
+          const openStub = sandbox.stub(element.$.createOverlay, 'open');
+          element._handleCreateClicked();
+          assert.isTrue(openStub.called);
+        });
+
+        test('_handleCreateItem called when confirm fired', () => {
+          sandbox.stub(element, '_handleCreateItem');
+          element.$.createDialog.fire('confirm');
+          assert.isTrue(element._handleCreateItem.called);
+        });
+
+        test('_handleCloseCreate called when cancel fired', () => {
+          sandbox.stub(element, '_handleCloseCreate');
+          element.$.createDialog.fire('cancel');
+          assert.isTrue(element._handleCloseCreate.called);
         });
       });
 
-      test('test for refs/tags/ being striped from ref', done => {
-        flush(() => {
-          assert.equal(element._stripRefs(element._items[1].ref,
-              element.detailType), 'test2');
-          done();
+      suite('404', () => {
+        test('fires page-error', done => {
+          const response = {status: 404};
+          sandbox.stub(element.$.restAPI, 'getRepoTags',
+              (filter, repo, reposTagsPerPage, opt_offset, errFn) => {
+                errFn(response);
+              });
+
+          element.addEventListener('page-error', e => {
+            assert.deepEqual(e.detail.response, response);
+            done();
+          });
+
+          const params = {
+            repo: 'test',
+            detail: 'tags',
+            filter: 'test',
+            offset: 25,
+          };
+          element._paramsChanged(params);
         });
       });
 
-      test('_shownItems', () => {
-        assert.equal(element._shownItems.length, 25);
+      test('test _computeHideDeleteClass', () => {
+        assert.deepEqual(element._computeHideDeleteClass(true, false), 'show');
+        assert.deepEqual(element._computeHideDeleteClass(false, true), 'show');
+        assert.deepEqual(element._computeHideDeleteClass(false, false), '');
       });
-
-      test('_computeHideTagger', () => {
-        const testObject1 = {
-          tagger: 'test',
-        };
-        assert.equal(element._computeHideTagger(testObject1), '');
-
-        assert.equal(element._computeHideTagger(undefined), 'hide');
-      });
-    });
-
-    suite('list with less then 25 tags', () => {
-      setup(done => {
-        tags = _.times(25, tagGenerator);
-
-        stub('gr-rest-api-interface', {
-          getRepoTags(num, project, offset) {
-            return Promise.resolve(tags);
-          },
-        });
-
-        const params = {
-          repo: 'test',
-          detail: 'tags',
-        };
-
-        element._paramsChanged(params).then(() => { flush(done); });
-      });
-
-      test('_shownItems', () => {
-        assert.equal(element._shownItems.length, 25);
-      });
-    });
-
-    suite('filter', () => {
-      test('_paramsChanged', done => {
-        sandbox.stub(
-            element.$.restAPI,
-            'getRepoTags',
-            () => Promise.resolve(tags));
-        const params = {
-          repo: 'test',
-          detail: 'tags',
-          filter: 'test',
-          offset: 25,
-        };
-        element._paramsChanged(params).then(() => {
-          assert.equal(element.$.restAPI.getRepoTags.lastCall.args[0],
-              'test');
-          assert.equal(element.$.restAPI.getRepoTags.lastCall.args[1],
-              'test');
-          assert.equal(element.$.restAPI.getRepoTags.lastCall.args[2],
-              25);
-          assert.equal(element.$.restAPI.getRepoTags.lastCall.args[3],
-              25);
-          done();
-        });
-      });
-    });
-
-    suite('create new', () => {
-      test('_handleCreateClicked called when create-click fired', () => {
-        sandbox.stub(element, '_handleCreateClicked');
-        element.$$('gr-list-view').fire('create-clicked');
-        assert.isTrue(element._handleCreateClicked.called);
-      });
-
-      test('_handleCreateClicked opens modal', () => {
-        const openStub = sandbox.stub(element.$.createOverlay, 'open');
-        element._handleCreateClicked();
-        assert.isTrue(openStub.called);
-      });
-
-      test('_handleCreateItem called when confirm fired', () => {
-        sandbox.stub(element, '_handleCreateItem');
-        element.$.createDialog.fire('confirm');
-        assert.isTrue(element._handleCreateItem.called);
-      });
-
-      test('_handleCloseCreate called when cancel fired', () => {
-        sandbox.stub(element, '_handleCloseCreate');
-        element.$.createDialog.fire('cancel');
-        assert.isTrue(element._handleCloseCreate.called);
-      });
-    });
-
-    suite('404', () => {
-      test('fires page-error', done => {
-        const response = {status: 404};
-        sandbox.stub(element.$.restAPI, 'getRepoTags',
-            (filter, repo, reposTagsPerPage, opt_offset, errFn) => {
-              errFn(response);
-            });
-
-        element.addEventListener('page-error', e => {
-          assert.deepEqual(e.detail.response, response);
-          done();
-        });
-
-        const params = {
-          repo: 'test',
-          detail: 'tags',
-          filter: 'test',
-          offset: 25,
-        };
-        element._paramsChanged(params);
-      });
-    });
-
-    test('test _computeHideDeleteClass', () => {
-      assert.deepEqual(element._computeHideDeleteClass(true, false), 'show');
-      assert.deepEqual(element._computeHideDeleteClass(false, true), 'show');
-      assert.deepEqual(element._computeHideDeleteClass(false, false), '');
     });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_test.html b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_test.html
index aed5c77..b31544b 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_test.html
@@ -24,6 +24,7 @@
 <script src="/bower_components/page/page.js"></script>
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-repo-list.html">
 
@@ -50,7 +51,8 @@
     };
   };
 
-  suite('gr-repo-list tests', () => {
+  suite('gr-repo-list tests', async () => {
+    await readyToTest();
     let element;
     let repos;
     let sandbox;
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config_test.html b/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config_test.html
index ff0e522..d0a7a66 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-repo-plugin-config.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-repo-plugin-config tests', () => {
+  suite('gr-repo-plugin-config tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_test.html b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_test.html
index 7b79a7e3..da0c271 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-repo.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-repo tests', () => {
+  suite('gr-repo tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
     let repoStub;
diff --git a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_test.html b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_test.html
index dbf5bb0..af0a4e23 100644
--- a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_test.html
@@ -24,6 +24,7 @@
 <script src="/bower_components/page/page.js"></script>
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-rule-editor.html">
 
@@ -36,7 +37,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-rule-editor tests', () => {
+  suite('gr-rule-editor tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.html b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.html
index 77c4791..41f422a 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.html
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="../../../scripts/util.js"></script>
 
@@ -37,7 +38,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-change-list-item tests', () => {
+  suite('gr-change-list-item tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view_test.html b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view_test.html
index 08a83af..0360d00 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view_test.html
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view_test.html
@@ -24,6 +24,7 @@
 <script src="/bower_components/page/page.js"></script>
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-change-list-view.html">
 
@@ -39,7 +40,8 @@
   const CHANGE_ID = 'IcA3dAB3edAB9f60B8dcdA6ef71A75980e4B7127';
   const COMMIT_HASH = '12345678';
 
-  suite('gr-change-list-view tests', () => {
+  suite('gr-change-list-view tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html
index 75fd167..b5e785e 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="/bower_components/page/page.js"></script>
 
@@ -43,7 +44,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-change-list basic tests', () => {
+  suite('gr-change-list basic tests', async () => {
+    await readyToTest();
     // Define keybindings before attaching other fixtures.
     const kb = window.Gerrit.KeyboardShortcutBinder;
     kb.bindShortcut(kb.Shortcut.CURSOR_NEXT_CHANGE, 'j');
@@ -431,192 +433,192 @@
         assert.isNotOk(element.$$(elementClass));
       });
     });
-  });
 
-  suite('dashboard queries', () => {
-    let element;
-    let sandbox;
+    suite('dashboard queries', () => {
+      let element;
+      let sandbox;
 
-    setup(() => {
-      sandbox = sinon.sandbox.create();
-      element = fixture('basic');
-    });
+      setup(() => {
+        sandbox = sinon.sandbox.create();
+        element = fixture('basic');
+      });
 
-    teardown(() => { sandbox.restore(); });
+      teardown(() => { sandbox.restore(); });
 
-    test('query without age and limit unchanged', () => {
-      const query = 'status:closed owner:me';
-      assert.deepEqual(element._processQuery(query), query);
-    });
+      test('query without age and limit unchanged', () => {
+        const query = 'status:closed owner:me';
+        assert.deepEqual(element._processQuery(query), query);
+      });
 
-    test('query with age and limit', () => {
-      const query = 'status:closed age:1week limit:10 owner:me';
-      const expectedQuery = 'status:closed owner:me';
-      assert.deepEqual(element._processQuery(query), expectedQuery);
-    });
+      test('query with age and limit', () => {
+        const query = 'status:closed age:1week limit:10 owner:me';
+        const expectedQuery = 'status:closed owner:me';
+        assert.deepEqual(element._processQuery(query), expectedQuery);
+      });
 
-    test('query with age', () => {
-      const query = 'status:closed age:1week owner:me';
-      const expectedQuery = 'status:closed owner:me';
-      assert.deepEqual(element._processQuery(query), expectedQuery);
-    });
+      test('query with age', () => {
+        const query = 'status:closed age:1week owner:me';
+        const expectedQuery = 'status:closed owner:me';
+        assert.deepEqual(element._processQuery(query), expectedQuery);
+      });
 
-    test('query with limit', () => {
-      const query = 'status:closed limit:10 owner:me';
-      const expectedQuery = 'status:closed owner:me';
-      assert.deepEqual(element._processQuery(query), expectedQuery);
-    });
+      test('query with limit', () => {
+        const query = 'status:closed limit:10 owner:me';
+        const expectedQuery = 'status:closed owner:me';
+        assert.deepEqual(element._processQuery(query), expectedQuery);
+      });
 
-    test('query with age as value and not key', () => {
-      const query = 'status:closed random:age';
-      const expectedQuery = 'status:closed random:age';
-      assert.deepEqual(element._processQuery(query), expectedQuery);
-    });
+      test('query with age as value and not key', () => {
+        const query = 'status:closed random:age';
+        const expectedQuery = 'status:closed random:age';
+        assert.deepEqual(element._processQuery(query), expectedQuery);
+      });
 
-    test('query with limit as value and not key', () => {
-      const query = 'status:closed random:limit';
-      const expectedQuery = 'status:closed random:limit';
-      assert.deepEqual(element._processQuery(query), expectedQuery);
-    });
+      test('query with limit as value and not key', () => {
+        const query = 'status:closed random:limit';
+        const expectedQuery = 'status:closed random:limit';
+        assert.deepEqual(element._processQuery(query), expectedQuery);
+      });
 
-    test('query with -age key', () => {
-      const query = 'status:closed -age:1week';
-      const expectedQuery = 'status:closed';
-      assert.deepEqual(element._processQuery(query), expectedQuery);
-    });
-  });
-
-  suite('gr-change-list sections', () => {
-    let element;
-    let sandbox;
-
-    setup(() => {
-      sandbox = sinon.sandbox.create();
-      element = fixture('basic');
-    });
-
-    teardown(() => { sandbox.restore(); });
-
-    test('keyboard shortcuts', done => {
-      element.selectedIndex = 0;
-      element.sections = [
-        {
-          results: [
-            {_number: 0},
-            {_number: 1},
-            {_number: 2},
-          ],
-        },
-        {
-          results: [
-            {_number: 3},
-            {_number: 4},
-            {_number: 5},
-          ],
-        },
-        {
-          results: [
-            {_number: 6},
-            {_number: 7},
-            {_number: 8},
-          ],
-        },
-      ];
-      flushAsynchronousOperations();
-      Polymer.RenderStatus.afterNextRender(element, () => {
-        const elementItems = Polymer.dom(element.root).querySelectorAll(
-            'gr-change-list-item');
-        assert.equal(elementItems.length, 9);
-
-        MockInteractions.pressAndReleaseKeyOn(element, 74); // 'j'
-        assert.equal(element.selectedIndex, 1);
-        MockInteractions.pressAndReleaseKeyOn(element, 74); // 'j'
-
-        const navStub = sandbox.stub(Gerrit.Nav, 'navigateToChange');
-        assert.equal(element.selectedIndex, 2);
-
-        MockInteractions.pressAndReleaseKeyOn(element, 13); // 'enter'
-        assert.deepEqual(navStub.lastCall.args[0], {_number: 2},
-            'Should navigate to /c/2/');
-
-        MockInteractions.pressAndReleaseKeyOn(element, 75); // 'k'
-        assert.equal(element.selectedIndex, 1);
-        MockInteractions.pressAndReleaseKeyOn(element, 13); // 'enter'
-        assert.deepEqual(navStub.lastCall.args[0], {_number: 1},
-            'Should navigate to /c/1/');
-
-        MockInteractions.pressAndReleaseKeyOn(element, 74); // 'j'
-        MockInteractions.pressAndReleaseKeyOn(element, 74); // 'j'
-        MockInteractions.pressAndReleaseKeyOn(element, 74); // 'j'
-        assert.equal(element.selectedIndex, 4);
-        MockInteractions.pressAndReleaseKeyOn(element, 13); // 'enter'
-        assert.deepEqual(navStub.lastCall.args[0], {_number: 4},
-            'Should navigate to /c/4/');
-
-        MockInteractions.pressAndReleaseKeyOn(element, 82); // 'r'
-        const change = element._changeForIndex(element.selectedIndex);
-        assert.equal(change.reviewed, true,
-            'Should mark change as reviewed');
-        MockInteractions.pressAndReleaseKeyOn(element, 82); // 'r'
-        assert.equal(change.reviewed, false,
-            'Should mark change as unreviewed');
-        done();
+      test('query with -age key', () => {
+        const query = 'status:closed -age:1week';
+        const expectedQuery = 'status:closed';
+        assert.deepEqual(element._processQuery(query), expectedQuery);
       });
     });
 
-    test('highlight attribute is updated correctly', () => {
-      element.changes = [
-        {
-          _number: 0,
-          status: 'NEW',
-          owner: {_account_id: 0},
-        },
-        {
-          _number: 1,
-          status: 'ABANDONED',
-          owner: {_account_id: 0},
-        },
-      ];
-      element.account = {_account_id: 42};
-      flushAsynchronousOperations();
-      let items = element._getListItems();
-      assert.equal(items.length, 2);
-      assert.isFalse(items[0].hasAttribute('highlight'));
-      assert.isFalse(items[1].hasAttribute('highlight'));
+    suite('gr-change-list sections', () => {
+      let element;
+      let sandbox;
 
-      // Assign all issues to the user, but only the first one is highlighted
-      // because the second one is abandoned.
-      element.set(['changes', 0, 'assignee'], {_account_id: 12});
-      element.set(['changes', 1, 'assignee'], {_account_id: 12});
-      element.account = {_account_id: 12};
-      flushAsynchronousOperations();
-      items = element._getListItems();
-      assert.isTrue(items[0].hasAttribute('highlight'));
-      assert.isFalse(items[1].hasAttribute('highlight'));
-    });
+      setup(() => {
+        sandbox = sinon.sandbox.create();
+        element = fixture('basic');
+      });
 
-    test('_computeItemHighlight gives false for null account', () => {
-      assert.isFalse(
-          element._computeItemHighlight(null, {assignee: {_account_id: 42}}));
-    });
+      teardown(() => { sandbox.restore(); });
 
-    test('_computeItemAbsoluteIndex', () => {
-      sandbox.stub(element, '_computeLabelNames');
-      element.sections = [
-        {results: new Array(1)},
-        {results: new Array(2)},
-        {results: new Array(3)},
-      ];
+      test('keyboard shortcuts', done => {
+        element.selectedIndex = 0;
+        element.sections = [
+          {
+            results: [
+              {_number: 0},
+              {_number: 1},
+              {_number: 2},
+            ],
+          },
+          {
+            results: [
+              {_number: 3},
+              {_number: 4},
+              {_number: 5},
+            ],
+          },
+          {
+            results: [
+              {_number: 6},
+              {_number: 7},
+              {_number: 8},
+            ],
+          },
+        ];
+        flushAsynchronousOperations();
+        Polymer.RenderStatus.afterNextRender(element, () => {
+          const elementItems = Polymer.dom(element.root).querySelectorAll(
+              'gr-change-list-item');
+          assert.equal(elementItems.length, 9);
 
-      assert.equal(element._computeItemAbsoluteIndex(0, 0), 0);
-      // Out of range but no matter.
-      assert.equal(element._computeItemAbsoluteIndex(0, 1), 1);
+          MockInteractions.pressAndReleaseKeyOn(element, 74); // 'j'
+          assert.equal(element.selectedIndex, 1);
+          MockInteractions.pressAndReleaseKeyOn(element, 74); // 'j'
 
-      assert.equal(element._computeItemAbsoluteIndex(1, 0), 1);
-      assert.equal(element._computeItemAbsoluteIndex(1, 1), 2);
-      assert.equal(element._computeItemAbsoluteIndex(1, 2), 3);
-      assert.equal(element._computeItemAbsoluteIndex(2, 0), 3);
-      assert.equal(element._computeItemAbsoluteIndex(3, 0), 6);
+          const navStub = sandbox.stub(Gerrit.Nav, 'navigateToChange');
+          assert.equal(element.selectedIndex, 2);
+
+          MockInteractions.pressAndReleaseKeyOn(element, 13); // 'enter'
+          assert.deepEqual(navStub.lastCall.args[0], {_number: 2},
+              'Should navigate to /c/2/');
+
+          MockInteractions.pressAndReleaseKeyOn(element, 75); // 'k'
+          assert.equal(element.selectedIndex, 1);
+          MockInteractions.pressAndReleaseKeyOn(element, 13); // 'enter'
+          assert.deepEqual(navStub.lastCall.args[0], {_number: 1},
+              'Should navigate to /c/1/');
+
+          MockInteractions.pressAndReleaseKeyOn(element, 74); // 'j'
+          MockInteractions.pressAndReleaseKeyOn(element, 74); // 'j'
+          MockInteractions.pressAndReleaseKeyOn(element, 74); // 'j'
+          assert.equal(element.selectedIndex, 4);
+          MockInteractions.pressAndReleaseKeyOn(element, 13); // 'enter'
+          assert.deepEqual(navStub.lastCall.args[0], {_number: 4},
+              'Should navigate to /c/4/');
+
+          MockInteractions.pressAndReleaseKeyOn(element, 82); // 'r'
+          const change = element._changeForIndex(element.selectedIndex);
+          assert.equal(change.reviewed, true,
+              'Should mark change as reviewed');
+          MockInteractions.pressAndReleaseKeyOn(element, 82); // 'r'
+          assert.equal(change.reviewed, false,
+              'Should mark change as unreviewed');
+          done();
+        });
+      });
+
+      test('highlight attribute is updated correctly', () => {
+        element.changes = [
+          {
+            _number: 0,
+            status: 'NEW',
+            owner: {_account_id: 0},
+          },
+          {
+            _number: 1,
+            status: 'ABANDONED',
+            owner: {_account_id: 0},
+          },
+        ];
+        element.account = {_account_id: 42};
+        flushAsynchronousOperations();
+        let items = element._getListItems();
+        assert.equal(items.length, 2);
+        assert.isFalse(items[0].hasAttribute('highlight'));
+        assert.isFalse(items[1].hasAttribute('highlight'));
+
+        // Assign all issues to the user, but only the first one is highlighted
+        // because the second one is abandoned.
+        element.set(['changes', 0, 'assignee'], {_account_id: 12});
+        element.set(['changes', 1, 'assignee'], {_account_id: 12});
+        element.account = {_account_id: 12};
+        flushAsynchronousOperations();
+        items = element._getListItems();
+        assert.isTrue(items[0].hasAttribute('highlight'));
+        assert.isFalse(items[1].hasAttribute('highlight'));
+      });
+
+      test('_computeItemHighlight gives false for null account', () => {
+        assert.isFalse(
+            element._computeItemHighlight(null, {assignee: {_account_id: 42}}));
+      });
+
+      test('_computeItemAbsoluteIndex', () => {
+        sandbox.stub(element, '_computeLabelNames');
+        element.sections = [
+          {results: new Array(1)},
+          {results: new Array(2)},
+          {results: new Array(3)},
+        ];
+
+        assert.equal(element._computeItemAbsoluteIndex(0, 0), 0);
+        // Out of range but no matter.
+        assert.equal(element._computeItemAbsoluteIndex(0, 1), 1);
+
+        assert.equal(element._computeItemAbsoluteIndex(1, 0), 1);
+        assert.equal(element._computeItemAbsoluteIndex(1, 1), 2);
+        assert.equal(element._computeItemAbsoluteIndex(1, 2), 3);
+        assert.equal(element._computeItemAbsoluteIndex(2, 0), 3);
+        assert.equal(element._computeItemAbsoluteIndex(3, 0), 6);
+      });
     });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help_test.html b/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help_test.html
index f10fbf2..fd8efe2 100644
--- a/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help_test.html
+++ b/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="../../../scripts/util.js"></script>
 
@@ -37,7 +38,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-create-change-help tests', () => {
+  suite('gr-create-change-help tests', async () => {
+    await readyToTest();
     let element;
 
     setup(() => {
diff --git a/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog_test.html b/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog_test.html
index 2228b50..41709a6 100644
--- a/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog_test.html
+++ b/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-create-commands-dialog.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-create-commands-dialog tests', () => {
+  suite('gr-create-commands-dialog tests', async () => {
+    await readyToTest();
     let element;
 
     setup(() => {
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.html b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.html
index 0d15d13..26175dc 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.html
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-dashboard-view.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-dashboard-view tests', () => {
+  suite('gr-dashboard-view tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
     let paramsChangedPromise;
diff --git a/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header_test.html b/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header_test.html
index 85eb509..d9cd75e 100644
--- a/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header_test.html
+++ b/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-repo-header.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-repo-header tests', () => {
+  suite('gr-repo-header tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header_test.html b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header_test.html
index 9e04ecd..26ebeb2 100644
--- a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header_test.html
+++ b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-user-header.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-user-header tests', () => {
+  suite('gr-user-header tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html
index 088bebd..de6817d 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="../../../scripts/util.js"></script>
 
@@ -38,1584 +39,814 @@
 
 <script>
   // TODO(dhruvsri): remove use of _populateRevertMessage as it's private
-  suite('gr-change-actions tests', () => {
+  suite('gr-change-actions tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
-    setup(() => {
-      stub('gr-rest-api-interface', {
-        getChangeRevisionActions() {
-          return Promise.resolve({
-            cherrypick: {
-              method: 'POST',
-              label: 'Cherry Pick',
-              title: 'Cherry pick change to a different branch',
-              enabled: true,
-            },
-            rebase: {
-              method: 'POST',
-              label: 'Rebase',
-              title: 'Rebase onto tip of branch or parent change',
-              enabled: true,
-            },
-            submit: {
-              method: 'POST',
-              label: 'Submit',
-              title: 'Submit patch set 2 into master',
-              enabled: true,
-            },
-          });
-        },
-        send(method, url, payload) {
-          if (method !== 'POST') {
-            return Promise.reject(new Error('bad method'));
-          }
-
-          if (url === '/changes/test~42/revisions/2/submit') {
+    suite('basic tests', () => {
+      setup(() => {
+        stub('gr-rest-api-interface', {
+          getChangeRevisionActions() {
             return Promise.resolve({
-              ok: true,
-              text() { return Promise.resolve(')]}\'\n{}'); },
+              cherrypick: {
+                method: 'POST',
+                label: 'Cherry Pick',
+                title: 'Cherry pick change to a different branch',
+                enabled: true,
+              },
+              rebase: {
+                method: 'POST',
+                label: 'Rebase',
+                title: 'Rebase onto tip of branch or parent change',
+                enabled: true,
+              },
+              submit: {
+                method: 'POST',
+                label: 'Submit',
+                title: 'Submit patch set 2 into master',
+                enabled: true,
+              },
             });
-          } else if (url === '/changes/test~42/revisions/2/rebase') {
-            return Promise.resolve({
-              ok: true,
-              text() { return Promise.resolve(')]}\'\n{}'); },
-            });
-          }
+          },
+          send(method, url, payload) {
+            if (method !== 'POST') {
+              return Promise.reject(new Error('bad method'));
+            }
 
-          return Promise.reject(new Error('bad url'));
-        },
-        getProjectConfig() { return Promise.resolve({}); },
+            if (url === '/changes/test~42/revisions/2/submit') {
+              return Promise.resolve({
+                ok: true,
+                text() { return Promise.resolve(')]}\'\n{}'); },
+              });
+            } else if (url === '/changes/test~42/revisions/2/rebase') {
+              return Promise.resolve({
+                ok: true,
+                text() { return Promise.resolve(')]}\'\n{}'); },
+              });
+            }
+
+            return Promise.reject(new Error('bad url'));
+          },
+          getProjectConfig() { return Promise.resolve({}); },
+        });
+
+        sandbox = sinon.sandbox.create();
+        sandbox.stub(Gerrit, 'awaitPluginsLoaded').returns(Promise.resolve());
+
+        element = fixture('basic');
+        element.change = {};
+        element.changeNum = '42';
+        element.latestPatchNum = '2';
+        element.actions = {
+          '/': {
+            method: 'DELETE',
+            label: 'Delete Change',
+            title: 'Delete change X_X',
+            enabled: true,
+          },
+        };
+        sandbox.stub(element.$.confirmCherrypick.$.restAPI,
+            'getRepoBranches').returns(Promise.resolve([]));
+        sandbox.stub(element.$.confirmMove.$.restAPI,
+            'getRepoBranches').returns(Promise.resolve([]));
+
+        return element.reload();
       });
 
-      sandbox = sinon.sandbox.create();
-      sandbox.stub(Gerrit, 'awaitPluginsLoaded').returns(Promise.resolve());
-
-      element = fixture('basic');
-      element.change = {};
-      element.changeNum = '42';
-      element.latestPatchNum = '2';
-      element.actions = {
-        '/': {
-          method: 'DELETE',
-          label: 'Delete Change',
-          title: 'Delete change X_X',
-          enabled: true,
-        },
-      };
-      sandbox.stub(element.$.confirmCherrypick.$.restAPI,
-          'getRepoBranches').returns(Promise.resolve([]));
-      sandbox.stub(element.$.confirmMove.$.restAPI,
-          'getRepoBranches').returns(Promise.resolve([]));
-
-      return element.reload();
-    });
-
-    teardown(() => {
-      sandbox.restore();
-    });
-
-    test('primary and secondary actions split properly', () => {
-      // Submit should be the only primary action.
-      assert.equal(element._topLevelPrimaryActions.length, 1);
-      assert.equal(element._topLevelPrimaryActions[0].label, 'Submit');
-      assert.equal(element._topLevelSecondaryActions.length,
-          element._topLevelActions.length - 1);
-    });
-
-    test('_shouldHideActions', () => {
-      assert.isTrue(element._shouldHideActions(undefined, true));
-      assert.isTrue(element._shouldHideActions({base: {}}, false));
-      assert.isFalse(element._shouldHideActions({base: ['test']}, false));
-    });
-
-    test('plugin revision actions', done => {
-      sandbox.stub(element.$.restAPI, 'getChangeActionURL').returns(
-          Promise.resolve('the-url'));
-      element.revisionActions = {
-        'plugin~action': {},
-      };
-      assert.isOk(element.revisionActions['plugin~action']);
-      flush(() => {
-        assert.isTrue(element.$.restAPI.getChangeActionURL.calledWith(
-            element.changeNum, element.latestPatchNum, '/plugin~action'));
-        assert.equal(element.revisionActions['plugin~action'].__url, 'the-url');
-        done();
+      teardown(() => {
+        sandbox.restore();
       });
-    });
 
-    test('plugin change actions', done => {
-      sandbox.stub(element.$.restAPI, 'getChangeActionURL').returns(
-          Promise.resolve('the-url'));
-      element.actions = {
-        'plugin~action': {},
-      };
-      assert.isOk(element.actions['plugin~action']);
-      flush(() => {
-        assert.isTrue(element.$.restAPI.getChangeActionURL.calledWith(
-            element.changeNum, null, '/plugin~action'));
-        assert.equal(element.actions['plugin~action'].__url, 'the-url');
-        done();
+      test('primary and secondary actions split properly', () => {
+        // Submit should be the only primary action.
+        assert.equal(element._topLevelPrimaryActions.length, 1);
+        assert.equal(element._topLevelPrimaryActions[0].label, 'Submit');
+        assert.equal(element._topLevelSecondaryActions.length,
+            element._topLevelActions.length - 1);
       });
-    });
 
-    test('not supported actions are filtered out', () => {
-      element.revisionActions = {followup: {}};
-      assert.equal(element.querySelectorAll(
-          'section gr-button[data-action-type="revision"]').length, 0);
-    });
+      test('_shouldHideActions', () => {
+        assert.isTrue(element._shouldHideActions(undefined, true));
+        assert.isTrue(element._shouldHideActions({base: {}}, false));
+        assert.isFalse(element._shouldHideActions({base: ['test']}, false));
+      });
 
-    test('getActionDetails', () => {
-      element.revisionActions = Object.assign({
-        'plugin~action': {},
-      }, element.revisionActions);
-      assert.isUndefined(element.getActionDetails('rubbish'));
-      assert.strictEqual(element.revisionActions['plugin~action'],
-          element.getActionDetails('plugin~action'));
-      assert.strictEqual(element.revisionActions['rebase'],
-          element.getActionDetails('rebase'));
-    });
+      test('plugin revision actions', done => {
+        sandbox.stub(element.$.restAPI, 'getChangeActionURL').returns(
+            Promise.resolve('the-url'));
+        element.revisionActions = {
+          'plugin~action': {},
+        };
+        assert.isOk(element.revisionActions['plugin~action']);
+        flush(() => {
+          assert.isTrue(element.$.restAPI.getChangeActionURL.calledWith(
+              element.changeNum, element.latestPatchNum, '/plugin~action'));
+          assert.equal(element.revisionActions['plugin~action'].__url, 'the-url');
+          done();
+        });
+      });
 
-    test('hide revision action', done => {
-      flush(() => {
-        const buttonEl = element.$$('[data-action-key="submit"]');
-        assert.isOk(buttonEl);
-        assert.throws(element.setActionHidden.bind(element, 'invalid type'));
-        element.setActionHidden(element.ActionType.REVISION,
-            element.RevisionActions.SUBMIT, true);
-        assert.lengthOf(element._hiddenActions, 1);
-        element.setActionHidden(element.ActionType.REVISION,
-            element.RevisionActions.SUBMIT, true);
-        assert.lengthOf(element._hiddenActions, 1);
+      test('plugin change actions', done => {
+        sandbox.stub(element.$.restAPI, 'getChangeActionURL').returns(
+            Promise.resolve('the-url'));
+        element.actions = {
+          'plugin~action': {},
+        };
+        assert.isOk(element.actions['plugin~action']);
+        flush(() => {
+          assert.isTrue(element.$.restAPI.getChangeActionURL.calledWith(
+              element.changeNum, null, '/plugin~action'));
+          assert.equal(element.actions['plugin~action'].__url, 'the-url');
+          done();
+        });
+      });
+
+      test('not supported actions are filtered out', () => {
+        element.revisionActions = {followup: {}};
+        assert.equal(element.querySelectorAll(
+            'section gr-button[data-action-type="revision"]').length, 0);
+      });
+
+      test('getActionDetails', () => {
+        element.revisionActions = Object.assign({
+          'plugin~action': {},
+        }, element.revisionActions);
+        assert.isUndefined(element.getActionDetails('rubbish'));
+        assert.strictEqual(element.revisionActions['plugin~action'],
+            element.getActionDetails('plugin~action'));
+        assert.strictEqual(element.revisionActions['rebase'],
+            element.getActionDetails('rebase'));
+      });
+
+      test('hide revision action', done => {
         flush(() => {
           const buttonEl = element.$$('[data-action-key="submit"]');
-          assert.isNotOk(buttonEl);
-
+          assert.isOk(buttonEl);
+          assert.throws(element.setActionHidden.bind(element, 'invalid type'));
           element.setActionHidden(element.ActionType.REVISION,
-              element.RevisionActions.SUBMIT, false);
+              element.RevisionActions.SUBMIT, true);
+          assert.lengthOf(element._hiddenActions, 1);
+          element.setActionHidden(element.ActionType.REVISION,
+              element.RevisionActions.SUBMIT, true);
+          assert.lengthOf(element._hiddenActions, 1);
           flush(() => {
             const buttonEl = element.$$('[data-action-key="submit"]');
-            assert.isOk(buttonEl);
-            assert.isFalse(buttonEl.hasAttribute('hidden'));
-            done();
+            assert.isNotOk(buttonEl);
+
+            element.setActionHidden(element.ActionType.REVISION,
+                element.RevisionActions.SUBMIT, false);
+            flush(() => {
+              const buttonEl = element.$$('[data-action-key="submit"]');
+              assert.isOk(buttonEl);
+              assert.isFalse(buttonEl.hasAttribute('hidden'));
+              done();
+            });
           });
         });
       });
-    });
 
-    test('buttons exist', done => {
-      element._loading = false;
-      flush(() => {
-        const buttonEls = Polymer.dom(element.root)
-            .querySelectorAll('gr-button');
-        const menuItems = element.$.moreActions.items;
+      test('buttons exist', done => {
+        element._loading = false;
+        flush(() => {
+          const buttonEls = Polymer.dom(element.root)
+              .querySelectorAll('gr-button');
+          const menuItems = element.$.moreActions.items;
 
-        // Total button number is one greater than the number of total actions
-        // due to the existence of the overflow menu trigger.
-        assert.equal(buttonEls.length + menuItems.length,
-            element._allActionValues.length + 1);
-        assert.isFalse(element.hidden);
-        done();
+          // Total button number is one greater than the number of total actions
+          // due to the existence of the overflow menu trigger.
+          assert.equal(buttonEls.length + menuItems.length,
+              element._allActionValues.length + 1);
+          assert.isFalse(element.hidden);
+          done();
+        });
       });
-    });
 
-    test('delete buttons have explicit labels', done => {
-      flush(() => {
-        const deleteItems = element.$.moreActions.items
-            .filter(item => item.id.startsWith('delete'));
-        assert.equal(deleteItems.length, 1);
-        assert.notEqual(deleteItems[0].name);
-        assert.equal(deleteItems[0].name, 'Delete change');
-        done();
+      test('delete buttons have explicit labels', done => {
+        flush(() => {
+          const deleteItems = element.$.moreActions.items
+              .filter(item => item.id.startsWith('delete'));
+          assert.equal(deleteItems.length, 1);
+          assert.notEqual(deleteItems[0].name);
+          assert.equal(deleteItems[0].name, 'Delete change');
+          done();
+        });
       });
-    });
 
-    test('get revision object from change', () => {
-      const revObj = {_number: 2, foo: 'bar'};
-      const change = {
-        revisions: {
-          rev1: {_number: 1},
-          rev2: revObj,
-        },
-      };
-      assert.deepEqual(element._getRevision(change, '2'), revObj);
-    });
+      test('get revision object from change', () => {
+        const revObj = {_number: 2, foo: 'bar'};
+        const change = {
+          revisions: {
+            rev1: {_number: 1},
+            rev2: revObj,
+          },
+        };
+        assert.deepEqual(element._getRevision(change, '2'), revObj);
+      });
 
-    test('_actionComparator sort order', () => {
-      const actions = [
-        {label: '123', __type: 'change', __key: 'review'},
-        {label: 'abc-ro', __type: 'revision'},
-        {label: 'abc', __type: 'change'},
-        {label: 'def', __type: 'change'},
-        {label: 'def-p', __type: 'change', __primary: true},
-      ];
+      test('_actionComparator sort order', () => {
+        const actions = [
+          {label: '123', __type: 'change', __key: 'review'},
+          {label: 'abc-ro', __type: 'revision'},
+          {label: 'abc', __type: 'change'},
+          {label: 'def', __type: 'change'},
+          {label: 'def-p', __type: 'change', __primary: true},
+        ];
 
-      const result = actions.slice();
-      result.reverse();
-      result.sort(element._actionComparator.bind(element));
-      assert.deepEqual(result, actions);
-    });
+        const result = actions.slice();
+        result.reverse();
+        result.sort(element._actionComparator.bind(element));
+        assert.deepEqual(result, actions);
+      });
 
-    test('submit change', () => {
-      const showSpy = sandbox.spy(element, '_showActionDialog');
-      sandbox.stub(element.$.restAPI, 'getFromProjectLookup')
-          .returns(Promise.resolve('test'));
-      sandbox.stub(element, 'fetchChangeUpdates',
-          () => Promise.resolve({isLatest: true}));
-      sandbox.stub(element.$.overlay, 'open').returns(Promise.resolve());
-      element.change = {
-        revisions: {
-          rev1: {_number: 1},
-          rev2: {_number: 2},
-        },
-      };
-      element.latestPatchNum = '2';
+      test('submit change', () => {
+        const showSpy = sandbox.spy(element, '_showActionDialog');
+        sandbox.stub(element.$.restAPI, 'getFromProjectLookup')
+            .returns(Promise.resolve('test'));
+        sandbox.stub(element, 'fetchChangeUpdates',
+            () => Promise.resolve({isLatest: true}));
+        sandbox.stub(element.$.overlay, 'open').returns(Promise.resolve());
+        element.change = {
+          revisions: {
+            rev1: {_number: 1},
+            rev2: {_number: 2},
+          },
+        };
+        element.latestPatchNum = '2';
 
-      const submitButton = element.$$('gr-button[data-action-key="submit"]');
-      assert.ok(submitButton);
-      MockInteractions.tap(submitButton);
-
-      flushAsynchronousOperations();
-      assert.isTrue(showSpy.calledWith(element.$.confirmSubmitDialog));
-    });
-
-    test('submit change, tap on icon', done => {
-      sandbox.stub(element.$.confirmSubmitDialog, 'resetFocus', done);
-      sandbox.stub(element.$.restAPI, 'getFromProjectLookup')
-          .returns(Promise.resolve('test'));
-      sandbox.stub(element, 'fetchChangeUpdates',
-          () => Promise.resolve({isLatest: true}));
-      sandbox.stub(element.$.overlay, 'open').returns(Promise.resolve());
-      element.change = {
-        revisions: {
-          rev1: {_number: 1},
-          rev2: {_number: 2},
-        },
-      };
-      element.latestPatchNum = '2';
-
-      const submitIcon =
-          element.$$('gr-button[data-action-key="submit"] iron-icon');
-      assert.ok(submitIcon);
-      MockInteractions.tap(submitIcon);
-    });
-
-    test('_handleSubmitConfirm', () => {
-      const fireStub = sandbox.stub(element, '_fireAction');
-      sandbox.stub(element, '_canSubmitChange').returns(true);
-      element._handleSubmitConfirm();
-      assert.isTrue(fireStub.calledOnce);
-      assert.deepEqual(fireStub.lastCall.args,
-          ['/submit', element.revisionActions.submit, true]);
-    });
-
-    test('_handleSubmitConfirm when not able to submit', () => {
-      const fireStub = sandbox.stub(element, '_fireAction');
-      sandbox.stub(element, '_canSubmitChange').returns(false);
-      element._handleSubmitConfirm();
-      assert.isFalse(fireStub.called);
-    });
-
-    test('submit change with plugin hook', done => {
-      sandbox.stub(element, '_canSubmitChange',
-          () => false);
-      const fireActionStub = sandbox.stub(element, '_fireAction');
-      flush(() => {
         const submitButton = element.$$('gr-button[data-action-key="submit"]');
         assert.ok(submitButton);
         MockInteractions.tap(submitButton);
-        assert.equal(fireActionStub.callCount, 0);
 
-        done();
-      });
-    });
-
-    test('chain state', () => {
-      assert.equal(element._hasKnownChainState, false);
-      element.hasParent = true;
-      assert.equal(element._hasKnownChainState, true);
-      element.hasParent = false;
-    });
-
-    test('_calculateDisabled', () => {
-      let hasKnownChainState = false;
-      const action = {__key: 'rebase', enabled: true};
-      assert.equal(
-          element._calculateDisabled(action, hasKnownChainState), true);
-
-      action.__key = 'delete';
-      assert.equal(
-          element._calculateDisabled(action, hasKnownChainState), false);
-
-      action.__key = 'rebase';
-      hasKnownChainState = true;
-      assert.equal(
-          element._calculateDisabled(action, hasKnownChainState), false);
-
-      action.enabled = false;
-      assert.equal(
-          element._calculateDisabled(action, hasKnownChainState), true);
-    });
-
-    test('rebase change', done => {
-      const fireActionStub = sandbox.stub(element, '_fireAction');
-      const fetchChangesStub = sandbox.stub(element.$.confirmRebase,
-          'fetchRecentChanges').returns(Promise.resolve([]));
-      element._hasKnownChainState = true;
-      flush(() => {
-        const rebaseButton = element.$$('gr-button[data-action-key="rebase"]');
-        MockInteractions.tap(rebaseButton);
-        const rebaseAction = {
-          __key: 'rebase',
-          __type: 'revision',
-          __primary: false,
-          enabled: true,
-          label: 'Rebase',
-          method: 'POST',
-          title: 'Rebase onto tip of branch or parent change',
-        };
-        assert.isTrue(fetchChangesStub.called);
-        element._handleRebaseConfirm({detail: {base: '1234'}});
-        rebaseAction.rebaseOnCurrent = true;
-        assert.deepEqual(fireActionStub.lastCall.args,
-            ['/rebase', rebaseAction, true, {base: '1234'}]);
-        done();
-      });
-    });
-
-    test(`rebase dialog gets recent changes each time it's opened`, done => {
-      const fetchChangesStub = sandbox.stub(element.$.confirmRebase,
-          'fetchRecentChanges').returns(Promise.resolve([]));
-      element._hasKnownChainState = true;
-      const rebaseButton = element.$$('gr-button[data-action-key="rebase"]');
-      MockInteractions.tap(rebaseButton);
-      assert.isTrue(fetchChangesStub.calledOnce);
-
-      flush(() => {
-        element.$.confirmRebase.fire('cancel');
-        MockInteractions.tap(rebaseButton);
-        assert.isTrue(fetchChangesStub.calledTwice);
-        done();
-      });
-    });
-
-    test('two dialogs are not shown at the same time', done => {
-      element._hasKnownChainState = true;
-      flush(() => {
-        const rebaseButton = element.$$('gr-button[data-action-key="rebase"]');
-        assert.ok(rebaseButton);
-        MockInteractions.tap(rebaseButton);
         flushAsynchronousOperations();
-        assert.isFalse(element.$.confirmRebase.hidden);
-
-        element._handleCherrypickTap();
-        flushAsynchronousOperations();
-        assert.isTrue(element.$.confirmRebase.hidden);
-        assert.isFalse(element.$.confirmCherrypick.hidden);
-        done();
-      });
-    });
-
-    test('fullscreen-overlay-opened hides content', () => {
-      sandbox.spy(element, '_handleHideBackgroundContent');
-      element.$.overlay.fire('fullscreen-overlay-opened');
-      assert.isTrue(element._handleHideBackgroundContent.called);
-      assert.isTrue(element.$.mainContent.classList.contains('overlayOpen'));
-    });
-
-    test('fullscreen-overlay-closed shows content', () => {
-      sandbox.spy(element, '_handleShowBackgroundContent');
-      element.$.overlay.fire('fullscreen-overlay-closed');
-      assert.isTrue(element._handleShowBackgroundContent.called);
-      assert.isFalse(element.$.mainContent.classList.contains('overlayOpen'));
-    });
-
-    test('_setLabelValuesOnRevert', () => {
-      const labels = {'Foo': 1, 'Bar-Baz': -2};
-      const changeId = 1234;
-      sandbox.stub(element.$.jsAPI, 'getLabelValuesPostRevert').returns(labels);
-      const saveStub = sandbox.stub(element.$.restAPI, 'saveChangeReview')
-          .returns(Promise.resolve());
-      return element._setLabelValuesOnRevert(changeId).then(() => {
-        assert.isTrue(saveStub.calledOnce);
-        assert.equal(saveStub.lastCall.args[0], changeId);
-        assert.deepEqual(saveStub.lastCall.args[2], {labels});
-      });
-    });
-
-    suite('change edits', () => {
-      test('disableEdit', () => {
-        element.set('editMode', false);
-        element.set('editPatchsetLoaded', false);
-        element.change = {status: 'NEW'};
-        element.set('disableEdit', true);
-        flushAsynchronousOperations();
-
-        assert.isNotOk(element.$$('gr-button[data-action-key="publishEdit"]'));
-        assert.isNotOk(element.$$('gr-button[data-action-key="rebaseEdit"]'));
-        assert.isNotOk(element.$$('gr-button[data-action-key="deleteEdit"]'));
-        assert.isNotOk(element.$$('gr-button[data-action-key="edit"]'));
-        assert.isNotOk(element.$$('gr-button[data-action-key="stopEdit"]'));
+        assert.isTrue(showSpy.calledWith(element.$.confirmSubmitDialog));
       });
 
-      test('shows confirm dialog for delete edit', () => {
-        element.set('editMode', true);
-        element.set('editPatchsetLoaded', true);
-
-        const fireActionStub = sandbox.stub(element, '_fireAction');
-        element._handleDeleteEditTap();
-        assert.isFalse(element.$.confirmDeleteEditDialog.hidden);
-        MockInteractions.tap(
-            element.shadowRoot
-                .querySelector('#confirmDeleteEditDialog')
-                .$$('gr-button[primary]'));
-        flushAsynchronousOperations();
-
-        assert.equal(fireActionStub.lastCall.args[0], '/edit');
-      });
-
-      test('hide publishEdit and rebaseEdit if change is not open', () => {
-        element.set('editMode', true);
-        element.set('editPatchsetLoaded', true);
-        element.change = {status: 'MERGED'};
-        flushAsynchronousOperations();
-
-        assert.isNotOk(element.$$('gr-button[data-action-key="publishEdit"]'));
-        assert.isNotOk(element.$$('gr-button[data-action-key="rebaseEdit"]'));
-        assert.isOk(element.$$('gr-button[data-action-key="deleteEdit"]'));
-        assert.isNotOk(element.$$('gr-button[data-action-key="edit"]'));
-      });
-
-      test('edit patchset is loaded, needs rebase', () => {
-        element.set('editMode', true);
-        element.set('editPatchsetLoaded', true);
-        element.change = {status: 'NEW'};
-        element.editBasedOnCurrentPatchSet = false;
-        flushAsynchronousOperations();
-
-        assert.isNotOk(element.$$('gr-button[data-action-key="publishEdit"]'));
-        assert.isOk(element.$$('gr-button[data-action-key="rebaseEdit"]'));
-        assert.isOk(element.$$('gr-button[data-action-key="deleteEdit"]'));
-        assert.isNotOk(element.$$('gr-button[data-action-key="edit"]'));
-        assert.isNotOk(element.$$('gr-button[data-action-key="stopEdit"]'));
-      });
-
-      test('edit patchset is loaded, does not need rebase', () => {
-        element.set('editMode', true);
-        element.set('editPatchsetLoaded', true);
-        element.change = {status: 'NEW'};
-        element.editBasedOnCurrentPatchSet = true;
-        flushAsynchronousOperations();
-
-        assert.isOk(element.$$('gr-button[data-action-key="publishEdit"]'));
-        assert.isNotOk(element.$$('gr-button[data-action-key="rebaseEdit"]'));
-        assert.isOk(element.$$('gr-button[data-action-key="deleteEdit"]'));
-        assert.isNotOk(element.$$('gr-button[data-action-key="edit"]'));
-        assert.isNotOk(element.$$('gr-button[data-action-key="stopEdit"]'));
-      });
-
-      test('edit mode is loaded, no edit patchset', () => {
-        element.set('editMode', true);
-        element.set('editPatchsetLoaded', false);
-        element.change = {status: 'NEW'};
-        flushAsynchronousOperations();
-
-        assert.isNotOk(element.$$('gr-button[data-action-key="publishEdit"]'));
-        assert.isNotOk(element.$$('gr-button[data-action-key="rebaseEdit"]'));
-        assert.isNotOk(element.$$('gr-button[data-action-key="deleteEdit"]'));
-        assert.isNotOk(element.$$('gr-button[data-action-key="edit"]'));
-        assert.isOk(element.$$('gr-button[data-action-key="stopEdit"]'));
-      });
-
-      test('normal patch set', () => {
-        element.set('editMode', false);
-        element.set('editPatchsetLoaded', false);
-        element.change = {status: 'NEW'};
-        flushAsynchronousOperations();
-
-        assert.isNotOk(element.$$('gr-button[data-action-key="publishEdit"]'));
-        assert.isNotOk(element.$$('gr-button[data-action-key="rebaseEdit"]'));
-        assert.isNotOk(element.$$('gr-button[data-action-key="deleteEdit"]'));
-        assert.isOk(element.$$('gr-button[data-action-key="edit"]'));
-        assert.isNotOk(element.$$('gr-button[data-action-key="stopEdit"]'));
-      });
-
-      test('edit action', done => {
-        element.addEventListener('edit-tap', () => { done(); });
-        element.set('editMode', true);
-        element.change = {status: 'NEW'};
-        flushAsynchronousOperations();
-
-        assert.isNotOk(element.$$('gr-button[data-action-key="edit"]'));
-        assert.isOk(element.$$('gr-button[data-action-key="stopEdit"]'));
-        element.change = {status: 'MERGED'};
-        flushAsynchronousOperations();
-
-        assert.isNotOk(element.$$('gr-button[data-action-key="edit"]'));
-        element.change = {status: 'NEW'};
-        element.set('editMode', false);
-        flushAsynchronousOperations();
-
-        const editButton = element.$$('gr-button[data-action-key="edit"]');
-        assert.isOk(editButton);
-        MockInteractions.tap(editButton);
-      });
-    });
-
-    suite('cherry-pick', () => {
-      let fireActionStub;
-
-      setup(() => {
-        fireActionStub = sandbox.stub(element, '_fireAction');
-        sandbox.stub(window, 'alert');
-      });
-
-      test('works', () => {
-        element._handleCherrypickTap();
-        const action = {
-          __key: 'cherrypick',
-          __type: 'revision',
-          __primary: false,
-          enabled: true,
-          label: 'Cherry pick',
-          method: 'POST',
-          title: 'Cherry pick change to a different branch',
-        };
-
-        element._handleCherrypickConfirm();
-        assert.equal(fireActionStub.callCount, 0);
-
-        element.$.confirmCherrypick.branch = 'master';
-        element._handleCherrypickConfirm();
-        assert.equal(fireActionStub.callCount, 0); // Still needs a message.
-
-        // Add attributes that are used to determine the message.
-        element.$.confirmCherrypick.commitMessage = 'foo message';
-        element.$.confirmCherrypick.changeStatus = 'OPEN';
-        element.$.confirmCherrypick.commitNum = '123';
-
-        element._handleCherrypickConfirm();
-
-        assert.equal(element.$.confirmCherrypick.$.messageInput.value,
-            'foo message');
-
-        assert.deepEqual(fireActionStub.lastCall.args, [
-          '/cherrypick', action, true, {
-            destination: 'master',
-            base: null,
-            message: 'foo message',
-            allow_conflicts: false,
-          },
-        ]);
-      });
-
-      test('cherry pick even with conflicts', () => {
-        element._handleCherrypickTap();
-        const action = {
-          __key: 'cherrypick',
-          __type: 'revision',
-          __primary: false,
-          enabled: true,
-          label: 'Cherry pick',
-          method: 'POST',
-          title: 'Cherry pick change to a different branch',
-        };
-
-        element.$.confirmCherrypick.branch = 'master';
-
-        // Add attributes that are used to determine the message.
-        element.$.confirmCherrypick.commitMessage = 'foo message';
-        element.$.confirmCherrypick.changeStatus = 'OPEN';
-        element.$.confirmCherrypick.commitNum = '123';
-
-        element._handleCherrypickConflictConfirm();
-
-        assert.deepEqual(fireActionStub.lastCall.args, [
-          '/cherrypick', action, true, {
-            destination: 'master',
-            base: null,
-            message: 'foo message',
-            allow_conflicts: true,
-          },
-        ]);
-      });
-
-      test('branch name cleared when re-open cherrypick', () => {
-        const emptyBranchName = '';
-        element.$.confirmCherrypick.branch = 'master';
-
-        element._handleCherrypickTap();
-        assert.equal(element.$.confirmCherrypick.branch, emptyBranchName);
-      });
-    });
-
-    suite('move change', () => {
-      let fireActionStub;
-
-      setup(() => {
-        fireActionStub = sandbox.stub(element, '_fireAction');
-        sandbox.stub(window, 'alert');
-      });
-
-      test('works', () => {
-        element._handleMoveTap();
-
-        element._handleMoveConfirm();
-        assert.equal(fireActionStub.callCount, 0);
-
-        element.$.confirmMove.branch = 'master';
-        element._handleMoveConfirm();
-        assert.equal(fireActionStub.callCount, 1);
-      });
-
-      test('branch name cleared when re-open move', () => {
-        const emptyBranchName = '';
-        element.$.confirmMove.branch = 'master';
-
-        element._handleMoveTap();
-        assert.equal(element.$.confirmMove.branch, emptyBranchName);
-      });
-    });
-
-    test('custom actions', done => {
-      // Add a button with the same key as a server-based one to ensure
-      // collisions are taken care of.
-      const key = element.addActionButton(element.ActionType.REVISION, 'Bork!');
-      element.addEventListener(key + '-tap', e => {
-        assert.equal(e.detail.node.getAttribute('data-action-key'), key);
-        element.removeActionButton(key);
-        flush(() => {
-          assert.notOk(element.$$('[data-action-key="' + key + '"]'));
-          done();
-        });
-      });
-      flush(() => {
-        MockInteractions.tap(element.$$('[data-action-key="' + key + '"]'));
-      });
-    });
-
-    test('_setLoadingOnButtonWithKey top-level', () => {
-      const key = 'rebase';
-      const type = 'revision';
-      const cleanup = element._setLoadingOnButtonWithKey(type, key);
-      assert.equal(element._actionLoadingMessage, 'Rebasing...');
-
-      const button = element.$$('[data-action-key="' + key + '"]');
-      assert.isTrue(button.hasAttribute('loading'));
-      assert.isTrue(button.disabled);
-
-      assert.isOk(cleanup);
-      assert.isFunction(cleanup);
-      cleanup();
-
-      assert.isFalse(button.hasAttribute('loading'));
-      assert.isFalse(button.disabled);
-      assert.isNotOk(element._actionLoadingMessage);
-    });
-
-    test('_setLoadingOnButtonWithKey overflow menu', () => {
-      const key = 'cherrypick';
-      const type = 'revision';
-      const cleanup = element._setLoadingOnButtonWithKey(type, key);
-      assert.equal(element._actionLoadingMessage, 'Cherry-picking...');
-      assert.include(element._disabledMenuActions, 'cherrypick');
-      assert.isFunction(cleanup);
-
-      cleanup();
-
-      assert.notOk(element._actionLoadingMessage);
-      assert.notInclude(element._disabledMenuActions, 'cherrypick');
-    });
-
-    suite('abandon change', () => {
-      let alertStub;
-      let fireActionStub;
-
-      setup(() => {
-        fireActionStub = sandbox.stub(element, '_fireAction');
-        alertStub = sandbox.stub(window, 'alert');
-        element.actions = {
-          abandon: {
-            method: 'POST',
-            label: 'Abandon',
-            title: 'Abandon the change',
-            enabled: true,
-          },
-        };
-        return element.reload();
-      });
-
-      test('abandon change with message', done => {
-        const newAbandonMsg = 'Test Abandon Message';
-        element.$.confirmAbandonDialog.message = newAbandonMsg;
-        flush(() => {
-          const abandonButton =
-              element.$$('gr-button[data-action-key="abandon"]');
-          MockInteractions.tap(abandonButton);
-
-          assert.equal(element.$.confirmAbandonDialog.message, newAbandonMsg);
-          done();
-        });
-      });
-
-      test('abandon change with no message', done => {
-        flush(() => {
-          const abandonButton =
-              element.$$('gr-button[data-action-key="abandon"]');
-          MockInteractions.tap(abandonButton);
-
-          assert.isUndefined(element.$.confirmAbandonDialog.message);
-          done();
-        });
-      });
-
-      test('works', () => {
-        element.$.confirmAbandonDialog.message = 'original message';
-        const restoreButton =
-            element.$$('gr-button[data-action-key="abandon"]');
-        MockInteractions.tap(restoreButton);
-
-        element.$.confirmAbandonDialog.message = 'foo message';
-        element._handleAbandonDialogConfirm();
-        assert.notOk(alertStub.called);
-
-        const action = {
-          __key: 'abandon',
-          __type: 'change',
-          __primary: false,
-          enabled: true,
-          label: 'Abandon',
-          method: 'POST',
-          title: 'Abandon the change',
-        };
-        assert.deepEqual(fireActionStub.lastCall.args, [
-          '/abandon', action, false, {
-            message: 'foo message',
-          }]);
-      });
-    });
-
-    suite('revert change', () => {
-      let fireActionStub;
-
-      setup(() => {
-        fireActionStub = sandbox.stub(element, '_fireAction');
-        element.commitMessage = 'random commit message';
-        element.change.current_revision = 'abcdef';
-        element.actions = {
-          revert: {
-            method: 'POST',
-            label: 'Revert',
-            title: 'Revert the change',
-            enabled: true,
-          },
-        };
-        return element.reload();
-      });
-
-      test('revert change with plugin hook', done => {
-        const newRevertMsg = 'Modified revert msg';
-        sandbox.stub(element.$.confirmRevertDialog, '_modifyRevertMsg',
-            () => newRevertMsg);
+      test('submit change, tap on icon', done => {
+        sandbox.stub(element.$.confirmSubmitDialog, 'resetFocus', done);
+        sandbox.stub(element.$.restAPI, 'getFromProjectLookup')
+            .returns(Promise.resolve('test'));
+        sandbox.stub(element, 'fetchChangeUpdates',
+            () => Promise.resolve({isLatest: true}));
+        sandbox.stub(element.$.overlay, 'open').returns(Promise.resolve());
         element.change = {
-          current_revision: 'abc1234',
+          revisions: {
+            rev1: {_number: 1},
+            rev2: {_number: 2},
+          },
         };
-        sandbox.stub(element.$.restAPI, 'getChanges')
-            .returns(Promise.resolve([
-              {change_id: '12345678901234', topic: 'T', subject: 'random'},
-              {change_id: '23456', topic: 'T', subject: 'a'.repeat(100)},
-            ]));
-        sandbox.stub(element.$.confirmRevertDialog,
-            '_populateRevertSubmissionMessage', () => 'original msg');
+        element.latestPatchNum = '2';
+
+        const submitIcon =
+            element.$$('gr-button[data-action-key="submit"] iron-icon');
+        assert.ok(submitIcon);
+        MockInteractions.tap(submitIcon);
+      });
+
+      test('_handleSubmitConfirm', () => {
+        const fireStub = sandbox.stub(element, '_fireAction');
+        sandbox.stub(element, '_canSubmitChange').returns(true);
+        element._handleSubmitConfirm();
+        assert.isTrue(fireStub.calledOnce);
+        assert.deepEqual(fireStub.lastCall.args,
+            ['/submit', element.revisionActions.submit, true]);
+      });
+
+      test('_handleSubmitConfirm when not able to submit', () => {
+        const fireStub = sandbox.stub(element, '_fireAction');
+        sandbox.stub(element, '_canSubmitChange').returns(false);
+        element._handleSubmitConfirm();
+        assert.isFalse(fireStub.called);
+      });
+
+      test('submit change with plugin hook', done => {
+        sandbox.stub(element, '_canSubmitChange',
+            () => false);
+        const fireActionStub = sandbox.stub(element, '_fireAction');
         flush(() => {
-          const revertButton = element.shadowRoot
-              .querySelector('gr-button[data-action-key="revert"]');
-          MockInteractions.tap(revertButton);
+          const submitButton = element.$$('gr-button[data-action-key="submit"]');
+          assert.ok(submitButton);
+          MockInteractions.tap(submitButton);
+          assert.equal(fireActionStub.callCount, 0);
+
+          done();
+        });
+      });
+
+      test('chain state', () => {
+        assert.equal(element._hasKnownChainState, false);
+        element.hasParent = true;
+        assert.equal(element._hasKnownChainState, true);
+        element.hasParent = false;
+      });
+
+      test('_calculateDisabled', () => {
+        let hasKnownChainState = false;
+        const action = {__key: 'rebase', enabled: true};
+        assert.equal(
+            element._calculateDisabled(action, hasKnownChainState), true);
+
+        action.__key = 'delete';
+        assert.equal(
+            element._calculateDisabled(action, hasKnownChainState), false);
+
+        action.__key = 'rebase';
+        hasKnownChainState = true;
+        assert.equal(
+            element._calculateDisabled(action, hasKnownChainState), false);
+
+        action.enabled = false;
+        assert.equal(
+            element._calculateDisabled(action, hasKnownChainState), true);
+      });
+
+      test('rebase change', done => {
+        const fireActionStub = sandbox.stub(element, '_fireAction');
+        const fetchChangesStub = sandbox.stub(element.$.confirmRebase,
+            'fetchRecentChanges').returns(Promise.resolve([]));
+        element._hasKnownChainState = true;
+        flush(() => {
+          const rebaseButton = element.$$('gr-button[data-action-key="rebase"]');
+          MockInteractions.tap(rebaseButton);
+          const rebaseAction = {
+            __key: 'rebase',
+            __type: 'revision',
+            __primary: false,
+            enabled: true,
+            label: 'Rebase',
+            method: 'POST',
+            title: 'Rebase onto tip of branch or parent change',
+          };
+          assert.isTrue(fetchChangesStub.called);
+          element._handleRebaseConfirm({detail: {base: '1234'}});
+          rebaseAction.rebaseOnCurrent = true;
+          assert.deepEqual(fireActionStub.lastCall.args,
+              ['/rebase', rebaseAction, true, {base: '1234'}]);
+          done();
+        });
+      });
+
+      test(`rebase dialog gets recent changes each time it's opened`, done => {
+        const fetchChangesStub = sandbox.stub(element.$.confirmRebase,
+            'fetchRecentChanges').returns(Promise.resolve([]));
+        element._hasKnownChainState = true;
+        const rebaseButton = element.$$('gr-button[data-action-key="rebase"]');
+        MockInteractions.tap(rebaseButton);
+        assert.isTrue(fetchChangesStub.calledOnce);
+
+        flush(() => {
+          element.$.confirmRebase.fire('cancel');
+          MockInteractions.tap(rebaseButton);
+          assert.isTrue(fetchChangesStub.calledTwice);
+          done();
+        });
+      });
+
+      test('two dialogs are not shown at the same time', done => {
+        element._hasKnownChainState = true;
+        flush(() => {
+          const rebaseButton = element.$$('gr-button[data-action-key="rebase"]');
+          assert.ok(rebaseButton);
+          MockInteractions.tap(rebaseButton);
+          flushAsynchronousOperations();
+          assert.isFalse(element.$.confirmRebase.hidden);
+
+          element._handleCherrypickTap();
+          flushAsynchronousOperations();
+          assert.isTrue(element.$.confirmRebase.hidden);
+          assert.isFalse(element.$.confirmCherrypick.hidden);
+          done();
+        });
+      });
+
+      test('fullscreen-overlay-opened hides content', () => {
+        sandbox.spy(element, '_handleHideBackgroundContent');
+        element.$.overlay.fire('fullscreen-overlay-opened');
+        assert.isTrue(element._handleHideBackgroundContent.called);
+        assert.isTrue(element.$.mainContent.classList.contains('overlayOpen'));
+      });
+
+      test('fullscreen-overlay-closed shows content', () => {
+        sandbox.spy(element, '_handleShowBackgroundContent');
+        element.$.overlay.fire('fullscreen-overlay-closed');
+        assert.isTrue(element._handleShowBackgroundContent.called);
+        assert.isFalse(element.$.mainContent.classList.contains('overlayOpen'));
+      });
+
+      test('_setLabelValuesOnRevert', () => {
+        const labels = {'Foo': 1, 'Bar-Baz': -2};
+        const changeId = 1234;
+        sandbox.stub(element.$.jsAPI, 'getLabelValuesPostRevert').returns(labels);
+        const saveStub = sandbox.stub(element.$.restAPI, 'saveChangeReview')
+            .returns(Promise.resolve());
+        return element._setLabelValuesOnRevert(changeId).then(() => {
+          assert.isTrue(saveStub.calledOnce);
+          assert.equal(saveStub.lastCall.args[0], changeId);
+          assert.deepEqual(saveStub.lastCall.args[2], {labels});
+        });
+      });
+
+      suite('change edits', () => {
+        test('disableEdit', () => {
+          element.set('editMode', false);
+          element.set('editPatchsetLoaded', false);
+          element.change = {status: 'NEW'};
+          element.set('disableEdit', true);
+          flushAsynchronousOperations();
+
+          assert.isNotOk(element.$$('gr-button[data-action-key="publishEdit"]'));
+          assert.isNotOk(element.$$('gr-button[data-action-key="rebaseEdit"]'));
+          assert.isNotOk(element.$$('gr-button[data-action-key="deleteEdit"]'));
+          assert.isNotOk(element.$$('gr-button[data-action-key="edit"]'));
+          assert.isNotOk(element.$$('gr-button[data-action-key="stopEdit"]'));
+        });
+
+        test('shows confirm dialog for delete edit', () => {
+          element.set('editMode', true);
+          element.set('editPatchsetLoaded', true);
+
+          const fireActionStub = sandbox.stub(element, '_fireAction');
+          element._handleDeleteEditTap();
+          assert.isFalse(element.$.confirmDeleteEditDialog.hidden);
+          MockInteractions.tap(
+              element.shadowRoot
+                  .querySelector('#confirmDeleteEditDialog')
+                  .$$('gr-button[primary]'));
+          flushAsynchronousOperations();
+
+          assert.equal(fireActionStub.lastCall.args[0], '/edit');
+        });
+
+        test('hide publishEdit and rebaseEdit if change is not open', () => {
+          element.set('editMode', true);
+          element.set('editPatchsetLoaded', true);
+          element.change = {status: 'MERGED'};
+          flushAsynchronousOperations();
+
+          assert.isNotOk(element.$$('gr-button[data-action-key="publishEdit"]'));
+          assert.isNotOk(element.$$('gr-button[data-action-key="rebaseEdit"]'));
+          assert.isOk(element.$$('gr-button[data-action-key="deleteEdit"]'));
+          assert.isNotOk(element.$$('gr-button[data-action-key="edit"]'));
+        });
+
+        test('edit patchset is loaded, needs rebase', () => {
+          element.set('editMode', true);
+          element.set('editPatchsetLoaded', true);
+          element.change = {status: 'NEW'};
+          element.editBasedOnCurrentPatchSet = false;
+          flushAsynchronousOperations();
+
+          assert.isNotOk(element.$$('gr-button[data-action-key="publishEdit"]'));
+          assert.isOk(element.$$('gr-button[data-action-key="rebaseEdit"]'));
+          assert.isOk(element.$$('gr-button[data-action-key="deleteEdit"]'));
+          assert.isNotOk(element.$$('gr-button[data-action-key="edit"]'));
+          assert.isNotOk(element.$$('gr-button[data-action-key="stopEdit"]'));
+        });
+
+        test('edit patchset is loaded, does not need rebase', () => {
+          element.set('editMode', true);
+          element.set('editPatchsetLoaded', true);
+          element.change = {status: 'NEW'};
+          element.editBasedOnCurrentPatchSet = true;
+          flushAsynchronousOperations();
+
+          assert.isOk(element.$$('gr-button[data-action-key="publishEdit"]'));
+          assert.isNotOk(element.$$('gr-button[data-action-key="rebaseEdit"]'));
+          assert.isOk(element.$$('gr-button[data-action-key="deleteEdit"]'));
+          assert.isNotOk(element.$$('gr-button[data-action-key="edit"]'));
+          assert.isNotOk(element.$$('gr-button[data-action-key="stopEdit"]'));
+        });
+
+        test('edit mode is loaded, no edit patchset', () => {
+          element.set('editMode', true);
+          element.set('editPatchsetLoaded', false);
+          element.change = {status: 'NEW'};
+          flushAsynchronousOperations();
+
+          assert.isNotOk(element.$$('gr-button[data-action-key="publishEdit"]'));
+          assert.isNotOk(element.$$('gr-button[data-action-key="rebaseEdit"]'));
+          assert.isNotOk(element.$$('gr-button[data-action-key="deleteEdit"]'));
+          assert.isNotOk(element.$$('gr-button[data-action-key="edit"]'));
+          assert.isOk(element.$$('gr-button[data-action-key="stopEdit"]'));
+        });
+
+        test('normal patch set', () => {
+          element.set('editMode', false);
+          element.set('editPatchsetLoaded', false);
+          element.change = {status: 'NEW'};
+          flushAsynchronousOperations();
+
+          assert.isNotOk(element.$$('gr-button[data-action-key="publishEdit"]'));
+          assert.isNotOk(element.$$('gr-button[data-action-key="rebaseEdit"]'));
+          assert.isNotOk(element.$$('gr-button[data-action-key="deleteEdit"]'));
+          assert.isOk(element.$$('gr-button[data-action-key="edit"]'));
+          assert.isNotOk(element.$$('gr-button[data-action-key="stopEdit"]'));
+        });
+
+        test('edit action', done => {
+          element.addEventListener('edit-tap', () => { done(); });
+          element.set('editMode', true);
+          element.change = {status: 'NEW'};
+          flushAsynchronousOperations();
+
+          assert.isNotOk(element.$$('gr-button[data-action-key="edit"]'));
+          assert.isOk(element.$$('gr-button[data-action-key="stopEdit"]'));
+          element.change = {status: 'MERGED'};
+          flushAsynchronousOperations();
+
+          assert.isNotOk(element.$$('gr-button[data-action-key="edit"]'));
+          element.change = {status: 'NEW'};
+          element.set('editMode', false);
+          flushAsynchronousOperations();
+
+          const editButton = element.$$('gr-button[data-action-key="edit"]');
+          assert.isOk(editButton);
+          MockInteractions.tap(editButton);
+        });
+      });
+
+      suite('cherry-pick', () => {
+        let fireActionStub;
+
+        setup(() => {
+          fireActionStub = sandbox.stub(element, '_fireAction');
+          sandbox.stub(window, 'alert');
+        });
+
+        test('works', () => {
+          element._handleCherrypickTap();
+          const action = {
+            __key: 'cherrypick',
+            __type: 'revision',
+            __primary: false,
+            enabled: true,
+            label: 'Cherry pick',
+            method: 'POST',
+            title: 'Cherry pick change to a different branch',
+          };
+
+          element._handleCherrypickConfirm();
+          assert.equal(fireActionStub.callCount, 0);
+
+          element.$.confirmCherrypick.branch = 'master';
+          element._handleCherrypickConfirm();
+          assert.equal(fireActionStub.callCount, 0); // Still needs a message.
+
+          // Add attributes that are used to determine the message.
+          element.$.confirmCherrypick.commitMessage = 'foo message';
+          element.$.confirmCherrypick.changeStatus = 'OPEN';
+          element.$.confirmCherrypick.commitNum = '123';
+
+          element._handleCherrypickConfirm();
+
+          assert.equal(element.$.confirmCherrypick.$.messageInput.value,
+              'foo message');
+
+          assert.deepEqual(fireActionStub.lastCall.args, [
+            '/cherrypick', action, true, {
+              destination: 'master',
+              base: null,
+              message: 'foo message',
+              allow_conflicts: false,
+            },
+          ]);
+        });
+
+        test('cherry pick even with conflicts', () => {
+          element._handleCherrypickTap();
+          const action = {
+            __key: 'cherrypick',
+            __type: 'revision',
+            __primary: false,
+            enabled: true,
+            label: 'Cherry pick',
+            method: 'POST',
+            title: 'Cherry pick change to a different branch',
+          };
+
+          element.$.confirmCherrypick.branch = 'master';
+
+          // Add attributes that are used to determine the message.
+          element.$.confirmCherrypick.commitMessage = 'foo message';
+          element.$.confirmCherrypick.changeStatus = 'OPEN';
+          element.$.confirmCherrypick.commitNum = '123';
+
+          element._handleCherrypickConflictConfirm();
+
+          assert.deepEqual(fireActionStub.lastCall.args, [
+            '/cherrypick', action, true, {
+              destination: 'master',
+              base: null,
+              message: 'foo message',
+              allow_conflicts: true,
+            },
+          ]);
+        });
+
+        test('branch name cleared when re-open cherrypick', () => {
+          const emptyBranchName = '';
+          element.$.confirmCherrypick.branch = 'master';
+
+          element._handleCherrypickTap();
+          assert.equal(element.$.confirmCherrypick.branch, emptyBranchName);
+        });
+      });
+
+      suite('move change', () => {
+        let fireActionStub;
+
+        setup(() => {
+          fireActionStub = sandbox.stub(element, '_fireAction');
+          sandbox.stub(window, 'alert');
+        });
+
+        test('works', () => {
+          element._handleMoveTap();
+
+          element._handleMoveConfirm();
+          assert.equal(fireActionStub.callCount, 0);
+
+          element.$.confirmMove.branch = 'master';
+          element._handleMoveConfirm();
+          assert.equal(fireActionStub.callCount, 1);
+        });
+
+        test('branch name cleared when re-open move', () => {
+          const emptyBranchName = '';
+          element.$.confirmMove.branch = 'master';
+
+          element._handleMoveTap();
+          assert.equal(element.$.confirmMove.branch, emptyBranchName);
+        });
+      });
+
+      test('custom actions', done => {
+        // Add a button with the same key as a server-based one to ensure
+        // collisions are taken care of.
+        const key = element.addActionButton(element.ActionType.REVISION, 'Bork!');
+        element.addEventListener(key + '-tap', e => {
+          assert.equal(e.detail.node.getAttribute('data-action-key'), key);
+          element.removeActionButton(key);
           flush(() => {
-            assert.equal(element.$.confirmRevertDialog._message, newRevertMsg);
+            assert.notOk(element.$$('[data-action-key="' + key + '"]'));
             done();
           });
         });
+        flush(() => {
+          MockInteractions.tap(element.$$('[data-action-key="' + key + '"]'));
+        });
       });
 
-      suite('revert change submitted together', () => {
+      test('_setLoadingOnButtonWithKey top-level', () => {
+        const key = 'rebase';
+        const type = 'revision';
+        const cleanup = element._setLoadingOnButtonWithKey(type, key);
+        assert.equal(element._actionLoadingMessage, 'Rebasing...');
+
+        const button = element.$$('[data-action-key="' + key + '"]');
+        assert.isTrue(button.hasAttribute('loading'));
+        assert.isTrue(button.disabled);
+
+        assert.isOk(cleanup);
+        assert.isFunction(cleanup);
+        cleanup();
+
+        assert.isFalse(button.hasAttribute('loading'));
+        assert.isFalse(button.disabled);
+        assert.isNotOk(element._actionLoadingMessage);
+      });
+
+      test('_setLoadingOnButtonWithKey overflow menu', () => {
+        const key = 'cherrypick';
+        const type = 'revision';
+        const cleanup = element._setLoadingOnButtonWithKey(type, key);
+        assert.equal(element._actionLoadingMessage, 'Cherry-picking...');
+        assert.include(element._disabledMenuActions, 'cherrypick');
+        assert.isFunction(cleanup);
+
+        cleanup();
+
+        assert.notOk(element._actionLoadingMessage);
+        assert.notInclude(element._disabledMenuActions, 'cherrypick');
+      });
+
+      suite('abandon change', () => {
+        let alertStub;
+        let fireActionStub;
+
         setup(() => {
+          fireActionStub = sandbox.stub(element, '_fireAction');
+          alertStub = sandbox.stub(window, 'alert');
+          element.actions = {
+            abandon: {
+              method: 'POST',
+              label: 'Abandon',
+              title: 'Abandon the change',
+              enabled: true,
+            },
+          };
+          return element.reload();
+        });
+
+        test('abandon change with message', done => {
+          const newAbandonMsg = 'Test Abandon Message';
+          element.$.confirmAbandonDialog.message = newAbandonMsg;
+          flush(() => {
+            const abandonButton =
+                element.$$('gr-button[data-action-key="abandon"]');
+            MockInteractions.tap(abandonButton);
+
+            assert.equal(element.$.confirmAbandonDialog.message, newAbandonMsg);
+            done();
+          });
+        });
+
+        test('abandon change with no message', done => {
+          flush(() => {
+            const abandonButton =
+                element.$$('gr-button[data-action-key="abandon"]');
+            MockInteractions.tap(abandonButton);
+
+            assert.isUndefined(element.$.confirmAbandonDialog.message);
+            done();
+          });
+        });
+
+        test('works', () => {
+          element.$.confirmAbandonDialog.message = 'original message';
+          const restoreButton =
+              element.$$('gr-button[data-action-key="abandon"]');
+          MockInteractions.tap(restoreButton);
+
+          element.$.confirmAbandonDialog.message = 'foo message';
+          element._handleAbandonDialogConfirm();
+          assert.notOk(alertStub.called);
+
+          const action = {
+            __key: 'abandon',
+            __type: 'change',
+            __primary: false,
+            enabled: true,
+            label: 'Abandon',
+            method: 'POST',
+            title: 'Abandon the change',
+          };
+          assert.deepEqual(fireActionStub.lastCall.args, [
+            '/abandon', action, false, {
+              message: 'foo message',
+            }]);
+        });
+      });
+
+      suite('revert change', () => {
+        let fireActionStub;
+
+        setup(() => {
+          fireActionStub = sandbox.stub(element, '_fireAction');
+          element.commitMessage = 'random commit message';
+          element.change.current_revision = 'abcdef';
+          element.actions = {
+            revert: {
+              method: 'POST',
+              label: 'Revert',
+              title: 'Revert the change',
+              enabled: true,
+            },
+          };
+          return element.reload();
+        });
+
+        test('revert change with plugin hook', done => {
+          const newRevertMsg = 'Modified revert msg';
+          sandbox.stub(element.$.confirmRevertDialog, '_modifyRevertMsg',
+              () => newRevertMsg);
           element.change = {
-            submission_id: '199',
-            current_revision: '2000',
+            current_revision: 'abc1234',
           };
           sandbox.stub(element.$.restAPI, 'getChanges')
               .returns(Promise.resolve([
                 {change_id: '12345678901234', topic: 'T', subject: 'random'},
                 {change_id: '23456', topic: 'T', subject: 'a'.repeat(100)},
               ]));
-        });
-
-        test('confirm revert dialog shows both options', done => {
-          const revertButton = element.shadowRoot
-              .querySelector('gr-button[data-action-key="revert"]');
-          MockInteractions.tap(revertButton);
+          sandbox.stub(element.$.confirmRevertDialog,
+              '_populateRevertSubmissionMessage', () => 'original msg');
           flush(() => {
-            const confirmRevertDialog = element.$.confirmRevertDialog;
-            const revertSingleChangeLabel = confirmRevertDialog
-                .shadowRoot.querySelector('.revertSingleChange');
-            const revertSubmissionLabel = confirmRevertDialog.
-                shadowRoot.querySelector('.revertSubmission');
-            assert(revertSingleChangeLabel.innerText.trim() ===
-                'Revert single change');
-            assert(revertSubmissionLabel.innerText.trim() ===
-                'Revert entire submission (2 Changes)');
-            let expectedMsg = 'Revert submission 199' + '\n\n' +
-              'Reason for revert: <INSERT REASONING HERE>' + '\n' +
-              'Reverted Changes:' + '\n' +
-              '1234567890:random' + '\n' +
-              '23456:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...' +
-              '\n';
-            assert.equal(confirmRevertDialog._message, expectedMsg);
-            const radioInputs = confirmRevertDialog.shadowRoot
-                .querySelectorAll('input[name="revertOptions"]');
-            MockInteractions.tap(radioInputs[0]);
+            const revertButton = element.shadowRoot
+                .querySelector('gr-button[data-action-key="revert"]');
+            MockInteractions.tap(revertButton);
             flush(() => {
-              expectedMsg = 'Revert "random commit message"\n\nThis reverts '
-               + 'commit 2000.\n\nReason'
-               + ' for revert: <INSERT REASONING HERE>\n';
-              assert.equal(confirmRevertDialog._message, expectedMsg);
+              assert.equal(element.$.confirmRevertDialog._message, newRevertMsg);
               done();
             });
           });
         });
 
-        test('submit fails if message is not edited', done => {
-          const revertButton = element.shadowRoot
-              .querySelector('gr-button[data-action-key="revert"]');
-          const confirmRevertDialog = element.$.confirmRevertDialog;
-          MockInteractions.tap(revertButton);
-          const fireStub = sandbox.stub(confirmRevertDialog, 'fire');
-          flush(() => {
-            const confirmButton = element.$.confirmRevertDialog.shadowRoot
-                .querySelector('gr-dialog')
-                .shadowRoot.querySelector('#confirm');
-            MockInteractions.tap(confirmButton);
-            flush(() => {
-              assert.isTrue(confirmRevertDialog._showErrorMessage);
-              assert.isFalse(fireStub.called);
-              done();
-            });
-          });
-        });
-
-        test('message modification is retained on switching', done => {
-          const revertButton = element.shadowRoot
-              .querySelector('gr-button[data-action-key="revert"]');
-          const confirmRevertDialog = element.$.confirmRevertDialog;
-          MockInteractions.tap(revertButton);
-          flush(() => {
-            const radioInputs = confirmRevertDialog.shadowRoot
-                .querySelectorAll('input[name="revertOptions"]');
-            const revertSubmissionMsg = 'Revert submission 199' + '\n\n' +
-            'Reason for revert: <INSERT REASONING HERE>' + '\n' +
-            'Reverted Changes:' + '\n' +
-            '1234567890:random' + '\n' +
-            '23456:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...' +
-            '\n';
-            const singleChangeMsg =
-            'Revert "random commit message"\n\nThis reverts '
-              + 'commit 2000.\n\nReason'
-              + ' for revert: <INSERT REASONING HERE>\n';
-            assert.equal(confirmRevertDialog._message, revertSubmissionMsg);
-            const newRevertMsg = revertSubmissionMsg + 'random';
-            const newSingleChangeMsg = singleChangeMsg + 'random';
-            confirmRevertDialog._message = newRevertMsg;
-            MockInteractions.tap(radioInputs[0]);
-            flush(() => {
-              assert.equal(confirmRevertDialog._message, singleChangeMsg);
-              confirmRevertDialog._message = newSingleChangeMsg;
-              MockInteractions.tap(radioInputs[1]);
-              flush(() => {
-                assert.equal(confirmRevertDialog._message, newRevertMsg);
-                MockInteractions.tap(radioInputs[0]);
-                flush(() => {
-                  assert.equal(confirmRevertDialog._message, newSingleChangeMsg);
-                  done();
-                });
-              });
-            });
-          });
-        });
-      });
-
-      suite('revert single change', () => {
-        setup(() => {
-          element.change = {
-            submission_id: '199',
-            current_revision: '2000',
-          };
-          sandbox.stub(element.$.restAPI, 'getChanges')
-              .returns(Promise.resolve([
-                {change_id: '12345678901234', topic: 'T', subject: 'random'},
-              ]));
-        });
-
-        test('submit fails if message is not edited', done => {
-          const revertButton = element.shadowRoot
-              .querySelector('gr-button[data-action-key="revert"]');
-          const confirmRevertDialog = element.$.confirmRevertDialog;
-          MockInteractions.tap(revertButton);
-          const fireStub = sandbox.stub(confirmRevertDialog, 'fire');
-          flush(() => {
-            const confirmButton = element.$.confirmRevertDialog.shadowRoot
-                .querySelector('gr-dialog')
-                .shadowRoot.querySelector('#confirm');
-            MockInteractions.tap(confirmButton);
-            flush(() => {
-              assert.isTrue(confirmRevertDialog._showErrorMessage);
-              assert.isFalse(fireStub.called);
-              done();
-            });
-          });
-        });
-
-        test('confirm revert dialog shows no radio button', done => {
-          const revertButton = element.shadowRoot
-              .querySelector('gr-button[data-action-key="revert"]');
-          MockInteractions.tap(revertButton);
-          flush(() => {
-            const confirmRevertDialog = element.$.confirmRevertDialog;
-            const radioInputs = confirmRevertDialog.shadowRoot
-                .querySelectorAll('input[name="revertOptions"]');
-            assert.equal(radioInputs.length, 0);
-            const msg = 'Revert "random commit message"\n\n'
-              + 'This reverts commit 2000.\n\nReason '
-              + 'for revert: <INSERT REASONING HERE>\n';
-            assert.equal(confirmRevertDialog._message, msg);
-            const editedMsg = msg + 'hello';
-            confirmRevertDialog._message += 'hello';
-            const confirmButton = element.$.confirmRevertDialog.shadowRoot
-                .querySelector('gr-dialog')
-                .shadowRoot.querySelector('#confirm');
-            MockInteractions.tap(confirmButton);
-            flush(() => {
-              assert.equal(fireActionStub.getCall(0).args[0], '/revert');
-              assert.equal(fireActionStub.getCall(0).args[1].__key, 'revert');
-              assert.equal(fireActionStub.getCall(0).args[3].message,
-                  editedMsg);
-              done();
-            });
-          });
-        });
-      });
-    });
-
-    suite('mark change private', () => {
-      setup(() => {
-        const privateAction = {
-          __key: 'private',
-          __type: 'change',
-          __primary: false,
-          method: 'POST',
-          label: 'Mark private',
-          title: 'Working...',
-          enabled: true,
-        };
-
-        element.actions = {
-          private: privateAction,
-        };
-
-        element.change.is_private = false;
-
-        element.changeNum = '2';
-        element.latestPatchNum = '2';
-
-        return element.reload();
-      });
-
-      test('make sure the mark private change button is not outside of the ' +
-           'overflow menu', done => {
-        flush(() => {
-          assert.isNotOk(element.$$('[data-action-key="private"]'));
-          done();
-        });
-      });
-
-      test('private change', done => {
-        flush(() => {
-          assert.isOk(
-              element.$.moreActions.$$('span[data-id="private-change"]'));
-          element.setActionOverflow('change', 'private', false);
-          flushAsynchronousOperations();
-          assert.isOk(element.$$('[data-action-key="private"]'));
-          assert.isNotOk(
-              element.$.moreActions.$$('span[data-id="private-change"]'));
-          done();
-        });
-      });
-    });
-
-    suite('unmark private change', () => {
-      setup(() => {
-        const unmarkPrivateAction = {
-          __key: 'private.delete',
-          __type: 'change',
-          __primary: false,
-          method: 'POST',
-          label: 'Unmark private',
-          title: 'Working...',
-          enabled: true,
-        };
-
-        element.actions = {
-          'private.delete': unmarkPrivateAction,
-        };
-
-        element.change.is_private = true;
-
-        element.changeNum = '2';
-        element.latestPatchNum = '2';
-
-        return element.reload();
-      });
-
-      test('make sure the unmark private change button is not outside of the ' +
-           'overflow menu', done => {
-        flush(() => {
-          assert.isNotOk(element.$$('[data-action-key="private.delete"]'));
-          done();
-        });
-      });
-
-      test('unmark the private change', done => {
-        flush(() => {
-          assert.isOk(
-              element.$.moreActions.$$('span[data-id="private.delete-change"]')
-          );
-          element.setActionOverflow('change', 'private.delete', false);
-          flushAsynchronousOperations();
-          assert.isOk(element.$$('[data-action-key="private.delete"]'));
-          assert.isNotOk(
-              element.$.moreActions.$$('span[data-id="private.delete-change"]')
-          );
-          done();
-        });
-      });
-    });
-
-    suite('delete change', () => {
-      let fireActionStub;
-      let deleteAction;
-
-      setup(() => {
-        fireActionStub = sandbox.stub(element, '_fireAction');
-        element.change = {
-          current_revision: 'abc1234',
-        };
-        deleteAction = {
-          method: 'DELETE',
-          label: 'Delete Change',
-          title: 'Delete change X_X',
-          enabled: true,
-        };
-        element.actions = {
-          '/': deleteAction,
-        };
-      });
-
-      test('does not delete on action', () => {
-        element._handleDeleteTap();
-        assert.isFalse(fireActionStub.called);
-      });
-
-      test('shows confirm dialog', () => {
-        element._handleDeleteTap();
-        assert.isFalse(element.shadowRoot
-            .querySelector('#confirmDeleteDialog').hidden);
-        MockInteractions.tap(
-            element.shadowRoot
-                .querySelector('#confirmDeleteDialog')
-                .$$('gr-button[primary]'));
-        flushAsynchronousOperations();
-        assert.isTrue(fireActionStub.calledWith('/', deleteAction, false));
-      });
-
-      test('hides delete confirm on cancel', () => {
-        element._handleDeleteTap();
-        MockInteractions.tap(
-            element.shadowRoot
-                .querySelector('#confirmDeleteDialog')
-                .$$('gr-button:not([primary])'));
-        flushAsynchronousOperations();
-        assert.isTrue(element.shadowRoot
-            .querySelector('#confirmDeleteDialog').hidden);
-        assert.isFalse(fireActionStub.called);
-      });
-    });
-
-    suite('ignore change', () => {
-      setup(done => {
-        sandbox.stub(element, '_fireAction');
-
-        const IgnoreAction = {
-          __key: 'ignore',
-          __type: 'change',
-          __primary: false,
-          method: 'PUT',
-          label: 'Ignore',
-          title: 'Working...',
-          enabled: true,
-        };
-
-        element.actions = {
-          ignore: IgnoreAction,
-        };
-
-        element.changeNum = '2';
-        element.latestPatchNum = '2';
-
-        element.reload().then(() => { flush(done); });
-      });
-
-      test('make sure the ignore button is not outside of the overflow menu',
-          () => {
-            assert.isNotOk(element.$$('[data-action-key="ignore"]'));
-          });
-
-      test('ignoring change', () => {
-        assert.isOk(element.$.moreActions.$$('span[data-id="ignore-change"]'));
-        element.setActionOverflow('change', 'ignore', false);
-        flushAsynchronousOperations();
-        assert.isOk(element.$$('[data-action-key="ignore"]'));
-        assert.isNotOk(
-            element.$.moreActions.$$('span[data-id="ignore-change"]'));
-      });
-    });
-
-    suite('unignore change', () => {
-      setup(done => {
-        sandbox.stub(element, '_fireAction');
-
-        const UnignoreAction = {
-          __key: 'unignore',
-          __type: 'change',
-          __primary: false,
-          method: 'PUT',
-          label: 'Unignore',
-          title: 'Working...',
-          enabled: true,
-        };
-
-        element.actions = {
-          unignore: UnignoreAction,
-        };
-
-        element.changeNum = '2';
-        element.latestPatchNum = '2';
-
-        element.reload().then(() => { flush(done); });
-      });
-
-      test('unignore button is not outside of the overflow menu', () => {
-        assert.isNotOk(element.$$('[data-action-key="unignore"]'));
-      });
-
-      test('unignoring change', () => {
-        assert.isOk(
-            element.$.moreActions.$$('span[data-id="unignore-change"]'));
-        element.setActionOverflow('change', 'unignore', false);
-        flushAsynchronousOperations();
-        assert.isOk(element.$$('[data-action-key="unignore"]'));
-        assert.isNotOk(
-            element.$.moreActions.$$('span[data-id="unignore-change"]'));
-      });
-    });
-
-    suite('reviewed change', () => {
-      setup(done => {
-        sandbox.stub(element, '_fireAction');
-
-        const ReviewedAction = {
-          __key: 'reviewed',
-          __type: 'change',
-          __primary: false,
-          method: 'PUT',
-          label: 'Mark reviewed',
-          title: 'Working...',
-          enabled: true,
-        };
-
-        element.actions = {
-          reviewed: ReviewedAction,
-        };
-
-        element.changeNum = '2';
-        element.latestPatchNum = '2';
-
-        element.reload().then(() => { flush(done); });
-      });
-
-      test('make sure the reviewed button is not outside of the overflow menu',
-          () => {
-            assert.isNotOk(element.$$('[data-action-key="reviewed"]'));
-          });
-
-      test('reviewing change', () => {
-        assert.isOk(
-            element.$.moreActions.$$('span[data-id="reviewed-change"]'));
-        element.setActionOverflow('change', 'reviewed', false);
-        flushAsynchronousOperations();
-        assert.isOk(element.$$('[data-action-key="reviewed"]'));
-        assert.isNotOk(
-            element.$.moreActions.$$('span[data-id="reviewed-change"]'));
-      });
-    });
-
-    suite('unreviewed change', () => {
-      setup(done => {
-        sandbox.stub(element, '_fireAction');
-
-        const UnreviewedAction = {
-          __key: 'unreviewed',
-          __type: 'change',
-          __primary: false,
-          method: 'PUT',
-          label: 'Mark unreviewed',
-          title: 'Working...',
-          enabled: true,
-        };
-
-        element.actions = {
-          unreviewed: UnreviewedAction,
-        };
-
-        element.changeNum = '2';
-        element.latestPatchNum = '2';
-
-        element.reload().then(() => { flush(done); });
-      });
-
-      test('unreviewed button not outside of the overflow menu', () => {
-        assert.isNotOk(element.$$('[data-action-key="unreviewed"]'));
-      });
-
-      test('unreviewed change', () => {
-        assert.isOk(
-            element.$.moreActions.$$('span[data-id="unreviewed-change"]'));
-        element.setActionOverflow('change', 'unreviewed', false);
-        flushAsynchronousOperations();
-        assert.isOk(element.$$('[data-action-key="unreviewed"]'));
-        assert.isNotOk(
-            element.$.moreActions.$$('span[data-id="unreviewed-change"]'));
-      });
-    });
-
-    suite('quick approve', () => {
-      setup(() => {
-        element.change = {
-          current_revision: 'abc1234',
-        };
-        element.change = {
-          current_revision: 'abc1234',
-          labels: {
-            foo: {
-              values: {
-                '-1': '',
-                ' 0': '',
-                '+1': '',
-              },
-            },
-          },
-          permitted_labels: {
-            foo: ['-1', ' 0', '+1'],
-          },
-        };
-        flushAsynchronousOperations();
-      });
-
-      test('added when can approve', () => {
-        const approveButton =
-            element.$$('gr-button[data-action-key=\'review\']');
-        assert.isNotNull(approveButton);
-      });
-
-      test('hide quick approve', () => {
-        const approveButton =
-            element.$$('gr-button[data-action-key=\'review\']');
-        assert.isNotNull(approveButton);
-        assert.isFalse(element._hideQuickApproveAction);
-
-        // Assert approve button gets removed from list of buttons.
-        element.hideQuickApproveAction();
-        flushAsynchronousOperations();
-        const approveButtonUpdated =
-            element.$$('gr-button[data-action-key=\'review\']');
-        assert.isNull(approveButtonUpdated);
-        assert.isTrue(element._hideQuickApproveAction);
-      });
-
-      test('is first in list of secondary actions', () => {
-        const approveButton = element.$.secondaryActions
-            .querySelector('gr-button');
-        assert.equal(approveButton.getAttribute('data-label'), 'foo+1');
-      });
-
-      test('not added when already approved', () => {
-        element.change = {
-          current_revision: 'abc1234',
-          labels: {
-            foo: {
-              approved: {},
-              values: {},
-            },
-          },
-          permitted_labels: {
-            foo: [' 0', '+1'],
-          },
-        };
-        flushAsynchronousOperations();
-        const approveButton =
-            element.$$('gr-button[data-action-key=\'review\']');
-        assert.isNull(approveButton);
-      });
-
-      test('not added when label not permitted', () => {
-        element.change = {
-          current_revision: 'abc1234',
-          labels: {
-            foo: {values: {}},
-          },
-          permitted_labels: {
-            bar: [],
-          },
-        };
-        flushAsynchronousOperations();
-        const approveButton =
-            element.$$('gr-button[data-action-key=\'review\']');
-        assert.isNull(approveButton);
-      });
-
-      test('approves when tapped', () => {
-        const fireActionStub = sandbox.stub(element, '_fireAction');
-        MockInteractions.tap(
-            element.$$('gr-button[data-action-key=\'review\']'));
-        flushAsynchronousOperations();
-        assert.isTrue(fireActionStub.called);
-        assert.isTrue(fireActionStub.calledWith('/review'));
-        const payload = fireActionStub.lastCall.args[3];
-        assert.deepEqual(payload.labels, {foo: '+1'});
-      });
-
-      test('not added when multiple labels are required', () => {
-        element.change = {
-          current_revision: 'abc1234',
-          labels: {
-            foo: {values: {}},
-            bar: {values: {}},
-          },
-          permitted_labels: {
-            foo: [' 0', '+1'],
-            bar: [' 0', '+1', '+2'],
-          },
-        };
-        flushAsynchronousOperations();
-        const approveButton =
-            element.$$('gr-button[data-action-key=\'review\']');
-        assert.isNull(approveButton);
-      });
-
-      test('button label for missing approval', () => {
-        element.change = {
-          current_revision: 'abc1234',
-          labels: {
-            foo: {
-              values: {
-                ' 0': '',
-                '+1': '',
-              },
-            },
-            bar: {approved: {}, values: {}},
-          },
-          permitted_labels: {
-            foo: [' 0', '+1'],
-            bar: [' 0', '+1', '+2'],
-          },
-        };
-        flushAsynchronousOperations();
-        const approveButton =
-            element.$$('gr-button[data-action-key=\'review\']');
-        assert.equal(approveButton.getAttribute('data-label'), 'foo+1');
-      });
-
-      test('no quick approve if score is not maximal for a label', () => {
-        element.change = {
-          current_revision: 'abc1234',
-          labels: {
-            bar: {
-              value: 1,
-              values: {
-                ' 0': '',
-                '+1': '',
-                '+2': '',
-              },
-            },
-          },
-          permitted_labels: {
-            bar: [' 0', '+1'],
-          },
-        };
-        flushAsynchronousOperations();
-        const approveButton =
-            element.$$('gr-button[data-action-key=\'review\']');
-        assert.isNull(approveButton);
-      });
-
-      test('approving label with a non-max score', () => {
-        element.change = {
-          current_revision: 'abc1234',
-          labels: {
-            bar: {
-              value: 1,
-              values: {
-                ' 0': '',
-                '+1': '',
-                '+2': '',
-              },
-            },
-          },
-          permitted_labels: {
-            bar: [' 0', '+1', '+2'],
-          },
-        };
-        flushAsynchronousOperations();
-        const approveButton =
-            element.$$('gr-button[data-action-key=\'review\']');
-        assert.equal(approveButton.getAttribute('data-label'), 'bar+2');
-      });
-    });
-
-    test('adds download revision action', () => {
-      const handler = sandbox.stub();
-      element.addEventListener('download-tap', handler);
-      assert.ok(element.revisionActions.download);
-      element._handleDownloadTap();
-      flushAsynchronousOperations();
-
-      assert.isTrue(handler.called);
-    });
-
-    test('changing changeNum or patchNum does not reload', () => {
-      const reloadStub = sandbox.stub(element, 'reload');
-      element.changeNum = 123;
-      assert.isFalse(reloadStub.called);
-      element.latestPatchNum = 456;
-      assert.isFalse(reloadStub.called);
-    });
-
-    test('_toSentenceCase', () => {
-      assert.equal(element._toSentenceCase('blah blah'), 'Blah blah');
-      assert.equal(element._toSentenceCase('BLAH BLAH'), 'Blah blah');
-      assert.equal(element._toSentenceCase('b'), 'B');
-      assert.equal(element._toSentenceCase(''), '');
-      assert.equal(element._toSentenceCase('!@#$%^&*()'), '!@#$%^&*()');
-    });
-
-    suite('setActionOverflow', () => {
-      test('move action from overflow', () => {
-        assert.isNotOk(element.$$('[data-action-key="cherrypick"]'));
-        assert.strictEqual(
-            element.$.moreActions.items[0].id, 'cherrypick-revision');
-        element.setActionOverflow('revision', 'cherrypick', false);
-        flushAsynchronousOperations();
-        assert.isOk(element.$$('[data-action-key="cherrypick"]'));
-        assert.notEqual(
-            element.$.moreActions.items[0].id, 'cherrypick-revision');
-      });
-
-      test('move action to overflow', () => {
-        assert.isOk(element.$$('[data-action-key="submit"]'));
-        element.setActionOverflow('revision', 'submit', true);
-        flushAsynchronousOperations();
-        assert.isNotOk(element.$$('[data-action-key="submit"]'));
-        assert.strictEqual(
-            element.$.moreActions.items[3].id, 'submit-revision');
-      });
-
-      suite('_waitForChangeReachable', () => {
-        setup(() => {
-          sandbox.stub(element, 'async', fn => fn());
-        });
-
-        const makeGetChange = numTries => () => {
-          if (numTries === 1) {
-            return Promise.resolve({_number: 123});
-          } else {
-            numTries--;
-            return Promise.resolve(undefined);
-          }
-        };
-
-        test('succeed', () => {
-          sandbox.stub(element.$.restAPI, 'getChange', makeGetChange(5));
-          return element._waitForChangeReachable(123).then(success => {
-            assert.isTrue(success);
-          });
-        });
-
-        test('fail', () => {
-          sandbox.stub(element.$.restAPI, 'getChange', makeGetChange(6));
-          return element._waitForChangeReachable(123).then(success => {
-            assert.isFalse(success);
-          });
-        });
-      });
-    });
-
-    suite('_send', () => {
-      let cleanup;
-      let payload;
-      let onShowError;
-      let onShowAlert;
-      let getResponseObjectStub;
-
-      setup(() => {
-        cleanup = sinon.stub();
-        element.changeNum = 42;
-        element.latestPatchNum = 12;
-        payload = {foo: 'bar'};
-
-        onShowError = sinon.stub();
-        element.addEventListener('show-error', onShowError);
-        onShowAlert = sinon.stub();
-        element.addEventListener('show-alert', onShowAlert);
-      });
-
-      suite('happy path', () => {
-        let sendStub;
-        setup(() => {
-          sandbox.stub(element, 'fetchChangeUpdates')
-              .returns(Promise.resolve({isLatest: true}));
-          sendStub = sandbox.stub(element.$.restAPI, 'executeChangeAction')
-              .returns(Promise.resolve({}));
-          getResponseObjectStub = sandbox.stub(element.$.restAPI,
-              'getResponseObject');
-          sandbox.stub(Gerrit.Nav,
-              'navigateToChange').returns(Promise.resolve(true));
-        });
-
-        test('change action', done => {
-          element
-              ._send('DELETE', payload, '/endpoint', false, cleanup)
-              .then(() => {
-                assert.isFalse(onShowError.called);
-                assert.isTrue(cleanup.calledOnce);
-                assert.isTrue(sendStub.calledWith(42, 'DELETE', '/endpoint',
-                    null, payload));
-                done();
-              });
-        });
-
-        suite('show revert submission dialog', () => {
+        suite('revert change submitted together', () => {
           setup(() => {
-            element.change.submission_id = '199';
-            element.change.current_revision = '2000';
+            element.change = {
+              submission_id: '199',
+              current_revision: '2000',
+            };
             sandbox.stub(element.$.restAPI, 'getChanges')
                 .returns(Promise.resolve([
                   {change_id: '12345678901234', topic: 'T', subject: 'random'},
@@ -1623,232 +854,1008 @@
                 ]));
           });
 
-          test('revert submission shows submissionId', done => {
-            const expectedMsg = 'Revert submission 199' + '\n\n' +
-              'Reason for revert: <INSERT REASONING HERE>' + '\n' +
-              'Reverted Changes:' + '\n' +
-              '1234567890: random' + '\n' +
-              '23456: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...' +
-              '\n';
-            const modifiedMsg = expectedMsg + 'abcd';
-            sandbox.stub(element.$.confirmRevertSubmissionDialog,
-                '_modifyRevertSubmissionMsg').returns(modifiedMsg);
-            element.showRevertSubmissionDialog();
+          test('confirm revert dialog shows both options', done => {
+            const revertButton = element.shadowRoot
+                .querySelector('gr-button[data-action-key="revert"]');
+            MockInteractions.tap(revertButton);
             flush(() => {
-              const msg = element.$.confirmRevertSubmissionDialog.message;
-              assert.equal(msg, modifiedMsg);
-              done();
-            });
-          });
-        });
-
-        suite('single changes revert', () => {
-          let navigateToSearchQueryStub;
-          setup(() => {
-            getResponseObjectStub
-                .returns(Promise.resolve({revert_changes: [
-                  {change_id: 12345},
-                ]}));
-            showActionDialogStub = sandbox.stub(element, '_showActionDialog');
-            navigateToSearchQueryStub = sandbox.stub(Gerrit.Nav,
-                'navigateToSearchQuery');
-          });
-
-          test('revert submission single change', done => {
-            element._send('POST', {message: 'Revert submission'},
-                '/revert_submission', false, cleanup).then(res => {
-              element._handleResponse({__key: 'revert_submission'}, {}).
-                  then(() => {
-                    assert.isTrue(navigateToSearchQueryStub.called);
-                    done();
-                  });
-            });
-          });
-        });
-
-        suite('multiple changes revert', () => {
-          let showActionDialogStub;
-          let navigateToSearchQueryStub;
-          setup(() => {
-            getResponseObjectStub
-                .returns(Promise.resolve({revert_changes: [
-                  {change_id: 12345, topic: 'T'},
-                  {change_id: 23456, topic: 'T'},
-                ]}));
-            showActionDialogStub = sandbox.stub(element, '_showActionDialog');
-            navigateToSearchQueryStub = sandbox.stub(Gerrit.Nav,
-                'navigateToSearchQuery');
-          });
-
-          test('revert submission multiple change', done => {
-            element._send('POST', {message: 'Revert submission'},
-                '/revert_submission', false, cleanup).then(res => {
-              element._handleResponse({__key: 'revert_submission'}, {}).then(
-                  () => {
-                    assert.isFalse(showActionDialogStub.called);
-                    assert.isTrue(navigateToSearchQueryStub.calledWith(
-                        'topic: T'));
-                    done();
-                  });
-            });
-          });
-        });
-
-        test('revision action', done => {
-          element
-              ._send('DELETE', payload, '/endpoint', true, cleanup)
-              .then(() => {
-                assert.isFalse(onShowError.called);
-                assert.isTrue(cleanup.calledOnce);
-                assert.isTrue(sendStub.calledWith(42, 'DELETE', '/endpoint',
-                    12, payload));
+              const confirmRevertDialog = element.$.confirmRevertDialog;
+              const revertSingleChangeLabel = confirmRevertDialog
+                  .shadowRoot.querySelector('.revertSingleChange');
+              const revertSubmissionLabel = confirmRevertDialog.
+                  shadowRoot.querySelector('.revertSubmission');
+              assert(revertSingleChangeLabel.innerText.trim() ===
+                  'Revert single change');
+              assert(revertSubmissionLabel.innerText.trim() ===
+                  'Revert entire submission (2 Changes)');
+              let expectedMsg = 'Revert submission 199' + '\n\n' +
+                'Reason for revert: <INSERT REASONING HERE>' + '\n' +
+                'Reverted Changes:' + '\n' +
+                '1234567890:random' + '\n' +
+                '23456:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...' +
+                '\n';
+              assert.equal(confirmRevertDialog._message, expectedMsg);
+              const radioInputs = confirmRevertDialog.shadowRoot
+                  .querySelectorAll('input[name="revertOptions"]');
+              MockInteractions.tap(radioInputs[0]);
+              flush(() => {
+                expectedMsg = 'Revert "random commit message"\n\nThis reverts '
+                 + 'commit 2000.\n\nReason'
+                 + ' for revert: <INSERT REASONING HERE>\n';
+                assert.equal(confirmRevertDialog._message, expectedMsg);
                 done();
               });
+            });
+          });
+
+          test('submit fails if message is not edited', done => {
+            const revertButton = element.shadowRoot
+                .querySelector('gr-button[data-action-key="revert"]');
+            const confirmRevertDialog = element.$.confirmRevertDialog;
+            MockInteractions.tap(revertButton);
+            const fireStub = sandbox.stub(confirmRevertDialog, 'fire');
+            flush(() => {
+              const confirmButton = element.$.confirmRevertDialog.shadowRoot
+                  .querySelector('gr-dialog')
+                  .shadowRoot.querySelector('#confirm');
+              MockInteractions.tap(confirmButton);
+              flush(() => {
+                assert.isTrue(confirmRevertDialog._showErrorMessage);
+                assert.isFalse(fireStub.called);
+                done();
+              });
+            });
+          });
+
+          test('message modification is retained on switching', done => {
+            const revertButton = element.shadowRoot
+                .querySelector('gr-button[data-action-key="revert"]');
+            const confirmRevertDialog = element.$.confirmRevertDialog;
+            MockInteractions.tap(revertButton);
+            flush(() => {
+              const radioInputs = confirmRevertDialog.shadowRoot
+                  .querySelectorAll('input[name="revertOptions"]');
+              const revertSubmissionMsg = 'Revert submission 199' + '\n\n' +
+              'Reason for revert: <INSERT REASONING HERE>' + '\n' +
+              'Reverted Changes:' + '\n' +
+              '1234567890:random' + '\n' +
+              '23456:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...' +
+              '\n';
+              const singleChangeMsg =
+              'Revert "random commit message"\n\nThis reverts '
+                + 'commit 2000.\n\nReason'
+                + ' for revert: <INSERT REASONING HERE>\n';
+              assert.equal(confirmRevertDialog._message, revertSubmissionMsg);
+              const newRevertMsg = revertSubmissionMsg + 'random';
+              const newSingleChangeMsg = singleChangeMsg + 'random';
+              confirmRevertDialog._message = newRevertMsg;
+              MockInteractions.tap(radioInputs[0]);
+              flush(() => {
+                assert.equal(confirmRevertDialog._message, singleChangeMsg);
+                confirmRevertDialog._message = newSingleChangeMsg;
+                MockInteractions.tap(radioInputs[1]);
+                flush(() => {
+                  assert.equal(confirmRevertDialog._message, newRevertMsg);
+                  MockInteractions.tap(radioInputs[0]);
+                  flush(() => {
+                    assert.equal(
+                        confirmRevertDialog._message,
+                        newSingleChangeMsg
+                    );
+                    done();
+                  });
+                });
+              });
+            });
+          });
+        });
+
+        suite('revert single change', () => {
+          setup(() => {
+            element.change = {
+              submission_id: '199',
+              current_revision: '2000',
+            };
+            sandbox.stub(element.$.restAPI, 'getChanges')
+                .returns(Promise.resolve([
+                  {change_id: '12345678901234', topic: 'T', subject: 'random'},
+                ]));
+          });
+
+          test('submit fails if message is not edited', done => {
+            const revertButton = element.shadowRoot
+                .querySelector('gr-button[data-action-key="revert"]');
+            const confirmRevertDialog = element.$.confirmRevertDialog;
+            MockInteractions.tap(revertButton);
+            const fireStub = sandbox.stub(confirmRevertDialog, 'fire');
+            flush(() => {
+              const confirmButton = element.$.confirmRevertDialog.shadowRoot
+                  .querySelector('gr-dialog')
+                  .shadowRoot.querySelector('#confirm');
+              MockInteractions.tap(confirmButton);
+              flush(() => {
+                assert.isTrue(confirmRevertDialog._showErrorMessage);
+                assert.isFalse(fireStub.called);
+                done();
+              });
+            });
+          });
+
+          test('confirm revert dialog shows no radio button', done => {
+            const revertButton = element.shadowRoot
+                .querySelector('gr-button[data-action-key="revert"]');
+            MockInteractions.tap(revertButton);
+            flush(() => {
+              const confirmRevertDialog = element.$.confirmRevertDialog;
+              const radioInputs = confirmRevertDialog.shadowRoot
+                  .querySelectorAll('input[name="revertOptions"]');
+              assert.equal(radioInputs.length, 0);
+              const msg = 'Revert "random commit message"\n\n'
+                + 'This reverts commit 2000.\n\nReason '
+                + 'for revert: <INSERT REASONING HERE>\n';
+              assert.equal(confirmRevertDialog._message, msg);
+              const editedMsg = msg + 'hello';
+              confirmRevertDialog._message += 'hello';
+              const confirmButton = element.$.confirmRevertDialog.shadowRoot
+                  .querySelector('gr-dialog')
+                  .shadowRoot.querySelector('#confirm');
+              MockInteractions.tap(confirmButton);
+              flush(() => {
+                assert.equal(fireActionStub.getCall(0).args[0], '/revert');
+                assert.equal(fireActionStub.getCall(0).args[1].__key, 'revert');
+                assert.equal(fireActionStub.getCall(0).args[3].message,
+                    editedMsg);
+                done();
+              });
+            });
+          });
         });
       });
 
-      suite('failure modes', () => {
-        test('non-latest', () => {
-          sandbox.stub(element, 'fetchChangeUpdates')
-              .returns(Promise.resolve({isLatest: false}));
-          const sendStub = sandbox.stub(element.$.restAPI,
-              'executeChangeAction');
+      suite('mark change private', () => {
+        setup(() => {
+          const privateAction = {
+            __key: 'private',
+            __type: 'change',
+            __primary: false,
+            method: 'POST',
+            label: 'Mark private',
+            title: 'Working...',
+            enabled: true,
+          };
 
-          return element._send('DELETE', payload, '/endpoint', true, cleanup)
-              .then(() => {
-                assert.isTrue(onShowAlert.calledOnce);
-                assert.isFalse(onShowError.called);
-                assert.isTrue(cleanup.calledOnce);
-                assert.isFalse(sendStub.called);
-              });
+          element.actions = {
+            private: privateAction,
+          };
+
+          element.change.is_private = false;
+
+          element.changeNum = '2';
+          element.latestPatchNum = '2';
+
+          return element.reload();
         });
 
-        test('send fails', () => {
-          sandbox.stub(element, 'fetchChangeUpdates')
-              .returns(Promise.resolve({isLatest: true}));
-          const sendStub = sandbox.stub(element.$.restAPI,
-              'executeChangeAction',
-              (num, method, patchNum, endpoint, payload, onErr) => {
-                onErr();
-                return Promise.resolve(null);
-              });
-          const handleErrorStub = sandbox.stub(element, '_handleResponseError');
-
-          return element._send('DELETE', payload, '/endpoint', true, cleanup)
-              .then(() => {
-                assert.isFalse(onShowError.called);
-                assert.isTrue(cleanup.called);
-                assert.isTrue(sendStub.calledOnce);
-                assert.isTrue(handleErrorStub.called);
-              });
+        test('make sure the mark private change button is not outside of the ' +
+             'overflow menu', done => {
+          flush(() => {
+            assert.isNotOk(element.$$('[data-action-key="private"]'));
+            done();
+          });
         });
+
+        test('private change', done => {
+          flush(() => {
+            assert.isOk(
+                element.$.moreActions.$$('span[data-id="private-change"]'));
+            element.setActionOverflow('change', 'private', false);
+            flushAsynchronousOperations();
+            assert.isOk(element.$$('[data-action-key="private"]'));
+            assert.isNotOk(
+                element.$.moreActions.$$('span[data-id="private-change"]'));
+            done();
+          });
+        });
+      });
+
+      suite('unmark private change', () => {
+        setup(() => {
+          const unmarkPrivateAction = {
+            __key: 'private.delete',
+            __type: 'change',
+            __primary: false,
+            method: 'POST',
+            label: 'Unmark private',
+            title: 'Working...',
+            enabled: true,
+          };
+
+          element.actions = {
+            'private.delete': unmarkPrivateAction,
+          };
+
+          element.change.is_private = true;
+
+          element.changeNum = '2';
+          element.latestPatchNum = '2';
+
+          return element.reload();
+        });
+
+        test('make sure the unmark private change button is not outside of the ' +
+             'overflow menu', done => {
+          flush(() => {
+            assert.isNotOk(element.$$('[data-action-key="private.delete"]'));
+            done();
+          });
+        });
+
+        test('unmark the private change', done => {
+          flush(() => {
+            assert.isOk(
+                element.$.moreActions.$$('span[data-id="private.delete-change"]')
+            );
+            element.setActionOverflow('change', 'private.delete', false);
+            flushAsynchronousOperations();
+            assert.isOk(element.$$('[data-action-key="private.delete"]'));
+            assert.isNotOk(
+                element.$.moreActions.$$('span[data-id="private.delete-change"]')
+            );
+            done();
+          });
+        });
+      });
+
+      suite('delete change', () => {
+        let fireActionStub;
+        let deleteAction;
+
+        setup(() => {
+          fireActionStub = sandbox.stub(element, '_fireAction');
+          element.change = {
+            current_revision: 'abc1234',
+          };
+          deleteAction = {
+            method: 'DELETE',
+            label: 'Delete Change',
+            title: 'Delete change X_X',
+            enabled: true,
+          };
+          element.actions = {
+            '/': deleteAction,
+          };
+        });
+
+        test('does not delete on action', () => {
+          element._handleDeleteTap();
+          assert.isFalse(fireActionStub.called);
+        });
+
+        test('shows confirm dialog', () => {
+          element._handleDeleteTap();
+          assert.isFalse(element.shadowRoot
+              .querySelector('#confirmDeleteDialog').hidden);
+          MockInteractions.tap(
+              element.shadowRoot
+                  .querySelector('#confirmDeleteDialog')
+                  .$$('gr-button[primary]'));
+          flushAsynchronousOperations();
+          assert.isTrue(fireActionStub.calledWith('/', deleteAction, false));
+        });
+
+        test('hides delete confirm on cancel', () => {
+          element._handleDeleteTap();
+          MockInteractions.tap(
+              element.shadowRoot
+                  .querySelector('#confirmDeleteDialog')
+                  .$$('gr-button:not([primary])'));
+          flushAsynchronousOperations();
+          assert.isTrue(element.shadowRoot
+              .querySelector('#confirmDeleteDialog').hidden);
+          assert.isFalse(fireActionStub.called);
+        });
+      });
+
+      suite('ignore change', () => {
+        setup(done => {
+          sandbox.stub(element, '_fireAction');
+
+          const IgnoreAction = {
+            __key: 'ignore',
+            __type: 'change',
+            __primary: false,
+            method: 'PUT',
+            label: 'Ignore',
+            title: 'Working...',
+            enabled: true,
+          };
+
+          element.actions = {
+            ignore: IgnoreAction,
+          };
+
+          element.changeNum = '2';
+          element.latestPatchNum = '2';
+
+          element.reload().then(() => { flush(done); });
+        });
+
+        test('make sure the ignore button is not outside of the overflow menu',
+            () => {
+              assert.isNotOk(element.$$('[data-action-key="ignore"]'));
+            });
+
+        test('ignoring change', () => {
+          assert.isOk(element.$.moreActions.$$('span[data-id="ignore-change"]'));
+          element.setActionOverflow('change', 'ignore', false);
+          flushAsynchronousOperations();
+          assert.isOk(element.$$('[data-action-key="ignore"]'));
+          assert.isNotOk(
+              element.$.moreActions.$$('span[data-id="ignore-change"]'));
+        });
+      });
+
+      suite('unignore change', () => {
+        setup(done => {
+          sandbox.stub(element, '_fireAction');
+
+          const UnignoreAction = {
+            __key: 'unignore',
+            __type: 'change',
+            __primary: false,
+            method: 'PUT',
+            label: 'Unignore',
+            title: 'Working...',
+            enabled: true,
+          };
+
+          element.actions = {
+            unignore: UnignoreAction,
+          };
+
+          element.changeNum = '2';
+          element.latestPatchNum = '2';
+
+          element.reload().then(() => { flush(done); });
+        });
+
+        test('unignore button is not outside of the overflow menu', () => {
+          assert.isNotOk(element.$$('[data-action-key="unignore"]'));
+        });
+
+        test('unignoring change', () => {
+          assert.isOk(
+              element.$.moreActions.$$('span[data-id="unignore-change"]'));
+          element.setActionOverflow('change', 'unignore', false);
+          flushAsynchronousOperations();
+          assert.isOk(element.$$('[data-action-key="unignore"]'));
+          assert.isNotOk(
+              element.$.moreActions.$$('span[data-id="unignore-change"]'));
+        });
+      });
+
+      suite('reviewed change', () => {
+        setup(done => {
+          sandbox.stub(element, '_fireAction');
+
+          const ReviewedAction = {
+            __key: 'reviewed',
+            __type: 'change',
+            __primary: false,
+            method: 'PUT',
+            label: 'Mark reviewed',
+            title: 'Working...',
+            enabled: true,
+          };
+
+          element.actions = {
+            reviewed: ReviewedAction,
+          };
+
+          element.changeNum = '2';
+          element.latestPatchNum = '2';
+
+          element.reload().then(() => { flush(done); });
+        });
+
+        test('make sure the reviewed button is not outside of the overflow menu',
+            () => {
+              assert.isNotOk(element.$$('[data-action-key="reviewed"]'));
+            });
+
+        test('reviewing change', () => {
+          assert.isOk(
+              element.$.moreActions.$$('span[data-id="reviewed-change"]'));
+          element.setActionOverflow('change', 'reviewed', false);
+          flushAsynchronousOperations();
+          assert.isOk(element.$$('[data-action-key="reviewed"]'));
+          assert.isNotOk(
+              element.$.moreActions.$$('span[data-id="reviewed-change"]'));
+        });
+      });
+
+      suite('unreviewed change', () => {
+        setup(done => {
+          sandbox.stub(element, '_fireAction');
+
+          const UnreviewedAction = {
+            __key: 'unreviewed',
+            __type: 'change',
+            __primary: false,
+            method: 'PUT',
+            label: 'Mark unreviewed',
+            title: 'Working...',
+            enabled: true,
+          };
+
+          element.actions = {
+            unreviewed: UnreviewedAction,
+          };
+
+          element.changeNum = '2';
+          element.latestPatchNum = '2';
+
+          element.reload().then(() => { flush(done); });
+        });
+
+        test('unreviewed button not outside of the overflow menu', () => {
+          assert.isNotOk(element.$$('[data-action-key="unreviewed"]'));
+        });
+
+        test('unreviewed change', () => {
+          assert.isOk(
+              element.$.moreActions.$$('span[data-id="unreviewed-change"]'));
+          element.setActionOverflow('change', 'unreviewed', false);
+          flushAsynchronousOperations();
+          assert.isOk(element.$$('[data-action-key="unreviewed"]'));
+          assert.isNotOk(
+              element.$.moreActions.$$('span[data-id="unreviewed-change"]'));
+        });
+      });
+
+      suite('quick approve', () => {
+        setup(() => {
+          element.change = {
+            current_revision: 'abc1234',
+          };
+          element.change = {
+            current_revision: 'abc1234',
+            labels: {
+              foo: {
+                values: {
+                  '-1': '',
+                  ' 0': '',
+                  '+1': '',
+                },
+              },
+            },
+            permitted_labels: {
+              foo: ['-1', ' 0', '+1'],
+            },
+          };
+          flushAsynchronousOperations();
+        });
+
+        test('added when can approve', () => {
+          const approveButton =
+              element.$$('gr-button[data-action-key=\'review\']');
+          assert.isNotNull(approveButton);
+        });
+
+        test('hide quick approve', () => {
+          const approveButton =
+              element.$$('gr-button[data-action-key=\'review\']');
+          assert.isNotNull(approveButton);
+          assert.isFalse(element._hideQuickApproveAction);
+
+          // Assert approve button gets removed from list of buttons.
+          element.hideQuickApproveAction();
+          flushAsynchronousOperations();
+          const approveButtonUpdated =
+              element.$$('gr-button[data-action-key=\'review\']');
+          assert.isNull(approveButtonUpdated);
+          assert.isTrue(element._hideQuickApproveAction);
+        });
+
+        test('is first in list of secondary actions', () => {
+          const approveButton = element.$.secondaryActions
+              .querySelector('gr-button');
+          assert.equal(approveButton.getAttribute('data-label'), 'foo+1');
+        });
+
+        test('not added when already approved', () => {
+          element.change = {
+            current_revision: 'abc1234',
+            labels: {
+              foo: {
+                approved: {},
+                values: {},
+              },
+            },
+            permitted_labels: {
+              foo: [' 0', '+1'],
+            },
+          };
+          flushAsynchronousOperations();
+          const approveButton =
+              element.$$('gr-button[data-action-key=\'review\']');
+          assert.isNull(approveButton);
+        });
+
+        test('not added when label not permitted', () => {
+          element.change = {
+            current_revision: 'abc1234',
+            labels: {
+              foo: {values: {}},
+            },
+            permitted_labels: {
+              bar: [],
+            },
+          };
+          flushAsynchronousOperations();
+          const approveButton =
+              element.$$('gr-button[data-action-key=\'review\']');
+          assert.isNull(approveButton);
+        });
+
+        test('approves when tapped', () => {
+          const fireActionStub = sandbox.stub(element, '_fireAction');
+          MockInteractions.tap(
+              element.$$('gr-button[data-action-key=\'review\']'));
+          flushAsynchronousOperations();
+          assert.isTrue(fireActionStub.called);
+          assert.isTrue(fireActionStub.calledWith('/review'));
+          const payload = fireActionStub.lastCall.args[3];
+          assert.deepEqual(payload.labels, {foo: '+1'});
+        });
+
+        test('not added when multiple labels are required', () => {
+          element.change = {
+            current_revision: 'abc1234',
+            labels: {
+              foo: {values: {}},
+              bar: {values: {}},
+            },
+            permitted_labels: {
+              foo: [' 0', '+1'],
+              bar: [' 0', '+1', '+2'],
+            },
+          };
+          flushAsynchronousOperations();
+          const approveButton =
+              element.$$('gr-button[data-action-key=\'review\']');
+          assert.isNull(approveButton);
+        });
+
+        test('button label for missing approval', () => {
+          element.change = {
+            current_revision: 'abc1234',
+            labels: {
+              foo: {
+                values: {
+                  ' 0': '',
+                  '+1': '',
+                },
+              },
+              bar: {approved: {}, values: {}},
+            },
+            permitted_labels: {
+              foo: [' 0', '+1'],
+              bar: [' 0', '+1', '+2'],
+            },
+          };
+          flushAsynchronousOperations();
+          const approveButton =
+              element.$$('gr-button[data-action-key=\'review\']');
+          assert.equal(approveButton.getAttribute('data-label'), 'foo+1');
+        });
+
+        test('no quick approve if score is not maximal for a label', () => {
+          element.change = {
+            current_revision: 'abc1234',
+            labels: {
+              bar: {
+                value: 1,
+                values: {
+                  ' 0': '',
+                  '+1': '',
+                  '+2': '',
+                },
+              },
+            },
+            permitted_labels: {
+              bar: [' 0', '+1'],
+            },
+          };
+          flushAsynchronousOperations();
+          const approveButton =
+              element.$$('gr-button[data-action-key=\'review\']');
+          assert.isNull(approveButton);
+        });
+
+        test('approving label with a non-max score', () => {
+          element.change = {
+            current_revision: 'abc1234',
+            labels: {
+              bar: {
+                value: 1,
+                values: {
+                  ' 0': '',
+                  '+1': '',
+                  '+2': '',
+                },
+              },
+            },
+            permitted_labels: {
+              bar: [' 0', '+1', '+2'],
+            },
+          };
+          flushAsynchronousOperations();
+          const approveButton =
+              element.$$('gr-button[data-action-key=\'review\']');
+          assert.equal(approveButton.getAttribute('data-label'), 'bar+2');
+        });
+      });
+
+      test('adds download revision action', () => {
+        const handler = sandbox.stub();
+        element.addEventListener('download-tap', handler);
+        assert.ok(element.revisionActions.download);
+        element._handleDownloadTap();
+        flushAsynchronousOperations();
+
+        assert.isTrue(handler.called);
+      });
+
+      test('changing changeNum or patchNum does not reload', () => {
+        const reloadStub = sandbox.stub(element, 'reload');
+        element.changeNum = 123;
+        assert.isFalse(reloadStub.called);
+        element.latestPatchNum = 456;
+        assert.isFalse(reloadStub.called);
+      });
+
+      test('_toSentenceCase', () => {
+        assert.equal(element._toSentenceCase('blah blah'), 'Blah blah');
+        assert.equal(element._toSentenceCase('BLAH BLAH'), 'Blah blah');
+        assert.equal(element._toSentenceCase('b'), 'B');
+        assert.equal(element._toSentenceCase(''), '');
+        assert.equal(element._toSentenceCase('!@#$%^&*()'), '!@#$%^&*()');
+      });
+
+      suite('setActionOverflow', () => {
+        test('move action from overflow', () => {
+          assert.isNotOk(element.$$('[data-action-key="cherrypick"]'));
+          assert.strictEqual(
+              element.$.moreActions.items[0].id, 'cherrypick-revision');
+          element.setActionOverflow('revision', 'cherrypick', false);
+          flushAsynchronousOperations();
+          assert.isOk(element.$$('[data-action-key="cherrypick"]'));
+          assert.notEqual(
+              element.$.moreActions.items[0].id, 'cherrypick-revision');
+        });
+
+        test('move action to overflow', () => {
+          assert.isOk(element.$$('[data-action-key="submit"]'));
+          element.setActionOverflow('revision', 'submit', true);
+          flushAsynchronousOperations();
+          assert.isNotOk(element.$$('[data-action-key="submit"]'));
+          assert.strictEqual(
+              element.$.moreActions.items[3].id, 'submit-revision');
+        });
+
+        suite('_waitForChangeReachable', () => {
+          setup(() => {
+            sandbox.stub(element, 'async', fn => fn());
+          });
+
+          const makeGetChange = numTries => () => {
+            if (numTries === 1) {
+              return Promise.resolve({_number: 123});
+            } else {
+              numTries--;
+              return Promise.resolve(undefined);
+            }
+          };
+
+          test('succeed', () => {
+            sandbox.stub(element.$.restAPI, 'getChange', makeGetChange(5));
+            return element._waitForChangeReachable(123).then(success => {
+              assert.isTrue(success);
+            });
+          });
+
+          test('fail', () => {
+            sandbox.stub(element.$.restAPI, 'getChange', makeGetChange(6));
+            return element._waitForChangeReachable(123).then(success => {
+              assert.isFalse(success);
+            });
+          });
+        });
+      });
+
+      suite('_send', () => {
+        let cleanup;
+        let payload;
+        let onShowError;
+        let onShowAlert;
+        let getResponseObjectStub;
+
+        setup(() => {
+          cleanup = sinon.stub();
+          element.changeNum = 42;
+          element.latestPatchNum = 12;
+          payload = {foo: 'bar'};
+
+          onShowError = sinon.stub();
+          element.addEventListener('show-error', onShowError);
+          onShowAlert = sinon.stub();
+          element.addEventListener('show-alert', onShowAlert);
+        });
+
+        suite('happy path', () => {
+          let sendStub;
+          setup(() => {
+            sandbox.stub(element, 'fetchChangeUpdates')
+                .returns(Promise.resolve({isLatest: true}));
+            sendStub = sandbox.stub(element.$.restAPI, 'executeChangeAction')
+                .returns(Promise.resolve({}));
+            getResponseObjectStub = sandbox.stub(element.$.restAPI,
+                'getResponseObject');
+            sandbox.stub(Gerrit.Nav,
+                'navigateToChange').returns(Promise.resolve(true));
+          });
+
+          test('change action', done => {
+            element
+                ._send('DELETE', payload, '/endpoint', false, cleanup)
+                .then(() => {
+                  assert.isFalse(onShowError.called);
+                  assert.isTrue(cleanup.calledOnce);
+                  assert.isTrue(sendStub.calledWith(42, 'DELETE', '/endpoint',
+                      null, payload));
+                  done();
+                });
+          });
+
+          suite('show revert submission dialog', () => {
+            setup(() => {
+              element.change.submission_id = '199';
+              element.change.current_revision = '2000';
+              sandbox.stub(element.$.restAPI, 'getChanges')
+                  .returns(Promise.resolve([
+                    {change_id: '12345678901234', topic: 'T', subject: 'random'},
+                    {change_id: '23456', topic: 'T', subject: 'a'.repeat(100)},
+                  ]));
+            });
+
+            test('revert submission shows submissionId', done => {
+              const expectedMsg = 'Revert submission 199' + '\n\n' +
+                'Reason for revert: <INSERT REASONING HERE>' + '\n' +
+                'Reverted Changes:' + '\n' +
+                '1234567890: random' + '\n' +
+                '23456: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...' +
+                '\n';
+              const modifiedMsg = expectedMsg + 'abcd';
+              sandbox.stub(element.$.confirmRevertSubmissionDialog,
+                  '_modifyRevertSubmissionMsg').returns(modifiedMsg);
+              element.showRevertSubmissionDialog();
+              flush(() => {
+                const msg = element.$.confirmRevertSubmissionDialog.message;
+                assert.equal(msg, modifiedMsg);
+                done();
+              });
+            });
+          });
+
+          suite('single changes revert', () => {
+            let navigateToSearchQueryStub;
+            setup(() => {
+              getResponseObjectStub
+                  .returns(Promise.resolve({revert_changes: [
+                    {change_id: 12345},
+                  ]}));
+              showActionDialogStub = sandbox.stub(element, '_showActionDialog');
+              navigateToSearchQueryStub = sandbox.stub(Gerrit.Nav,
+                  'navigateToSearchQuery');
+            });
+
+            test('revert submission single change', done => {
+              element._send('POST', {message: 'Revert submission'},
+                  '/revert_submission', false, cleanup).then(res => {
+                element._handleResponse({__key: 'revert_submission'}, {}).
+                    then(() => {
+                      assert.isTrue(navigateToSearchQueryStub.called);
+                      done();
+                    });
+              });
+            });
+          });
+
+          suite('multiple changes revert', () => {
+            let showActionDialogStub;
+            let navigateToSearchQueryStub;
+            setup(() => {
+              getResponseObjectStub
+                  .returns(Promise.resolve({revert_changes: [
+                    {change_id: 12345, topic: 'T'},
+                    {change_id: 23456, topic: 'T'},
+                  ]}));
+              showActionDialogStub = sandbox.stub(element, '_showActionDialog');
+              navigateToSearchQueryStub = sandbox.stub(Gerrit.Nav,
+                  'navigateToSearchQuery');
+            });
+
+            test('revert submission multiple change', done => {
+              element._send('POST', {message: 'Revert submission'},
+                  '/revert_submission', false, cleanup).then(res => {
+                element._handleResponse({__key: 'revert_submission'}, {}).then(
+                    () => {
+                      assert.isFalse(showActionDialogStub.called);
+                      assert.isTrue(navigateToSearchQueryStub.calledWith(
+                          'topic: T'));
+                      done();
+                    });
+              });
+            });
+          });
+
+          test('revision action', done => {
+            element
+                ._send('DELETE', payload, '/endpoint', true, cleanup)
+                .then(() => {
+                  assert.isFalse(onShowError.called);
+                  assert.isTrue(cleanup.calledOnce);
+                  assert.isTrue(sendStub.calledWith(42, 'DELETE', '/endpoint',
+                      12, payload));
+                  done();
+                });
+          });
+        });
+
+        suite('failure modes', () => {
+          test('non-latest', () => {
+            sandbox.stub(element, 'fetchChangeUpdates')
+                .returns(Promise.resolve({isLatest: false}));
+            const sendStub = sandbox.stub(element.$.restAPI,
+                'executeChangeAction');
+
+            return element._send('DELETE', payload, '/endpoint', true, cleanup)
+                .then(() => {
+                  assert.isTrue(onShowAlert.calledOnce);
+                  assert.isFalse(onShowError.called);
+                  assert.isTrue(cleanup.calledOnce);
+                  assert.isFalse(sendStub.called);
+                });
+          });
+
+          test('send fails', () => {
+            sandbox.stub(element, 'fetchChangeUpdates')
+                .returns(Promise.resolve({isLatest: true}));
+            const sendStub = sandbox.stub(element.$.restAPI,
+                'executeChangeAction',
+                (num, method, patchNum, endpoint, payload, onErr) => {
+                  onErr();
+                  return Promise.resolve(null);
+                });
+            const handleErrorStub = sandbox.stub(element, '_handleResponseError');
+
+            return element._send('DELETE', payload, '/endpoint', true, cleanup)
+                .then(() => {
+                  assert.isFalse(onShowError.called);
+                  assert.isTrue(cleanup.called);
+                  assert.isTrue(sendStub.calledOnce);
+                  assert.isTrue(handleErrorStub.called);
+                });
+          });
+        });
+      });
+
+      test('_handleAction reports', () => {
+        sandbox.stub(element, '_fireAction');
+        const reportStub = sandbox.stub(element.$.reporting, 'reportInteraction');
+        element._handleAction('type', 'key');
+        assert.isTrue(reportStub.called);
+        assert.equal(reportStub.lastCall.args[0], 'type-key');
       });
     });
 
-    test('_handleAction reports', () => {
-      sandbox.stub(element, '_fireAction');
-      const reportStub = sandbox.stub(element.$.reporting, 'reportInteraction');
-      element._handleAction('type', 'key');
-      assert.isTrue(reportStub.called);
-      assert.equal(reportStub.lastCall.args[0], 'type-key');
-    });
-  });
+    suite('getChangeRevisionActions returns only some actions', () => {
+      let element;
+      let sandbox;
+      let changeRevisionActions;
 
-  suite('getChangeRevisionActions returns only some actions', () => {
-    let element;
-    let sandbox;
-    let changeRevisionActions;
+      setup(() => {
+        stub('gr-rest-api-interface', {
+          getChangeRevisionActions() {
+            return Promise.resolve(changeRevisionActions);
+          },
+          send(method, url, payload) {
+            return Promise.reject(new Error('error'));
+          },
+          getProjectConfig() { return Promise.resolve({}); },
+        });
 
-    setup(() => {
-      stub('gr-rest-api-interface', {
-        getChangeRevisionActions() {
-          return Promise.resolve(changeRevisionActions);
-        },
-        send(method, url, payload) {
-          return Promise.reject(new Error('error'));
-        },
-        getProjectConfig() { return Promise.resolve({}); },
+        sandbox = sinon.sandbox.create();
+        sandbox.stub(Gerrit, 'awaitPluginsLoaded').returns(Promise.resolve());
+
+        element = fixture('basic');
+        // getChangeRevisionActions is not called without
+        // set the following properies
+        element.change = {};
+        element.changeNum = '42';
+        element.latestPatchNum = '2';
+
+        sandbox.stub(element.$.confirmCherrypick.$.restAPI,
+            'getRepoBranches').returns(Promise.resolve([]));
+        sandbox.stub(element.$.confirmMove.$.restAPI,
+            'getRepoBranches').returns(Promise.resolve([]));
+        return element.reload();
       });
 
-      sandbox = sinon.sandbox.create();
-      sandbox.stub(Gerrit, 'awaitPluginsLoaded').returns(Promise.resolve());
+      teardown(() => {
+        sandbox.restore();
+      });
 
-      element = fixture('basic');
-      // getChangeRevisionActions is not called without
-      // set the following properies
-      element.change = {};
-      element.changeNum = '42';
-      element.latestPatchNum = '2';
+      test('confirmSubmitDialog and confirmRebase properties are changed', () => {
+        changeRevisionActions = {};
+        element.reload();
+        assert.strictEqual(element.$.confirmSubmitDialog.action, null);
+        assert.strictEqual(element.$.confirmRebase.rebaseOnCurrent, null);
+      });
 
-      sandbox.stub(element.$.confirmCherrypick.$.restAPI,
-          'getRepoBranches').returns(Promise.resolve([]));
-      sandbox.stub(element.$.confirmMove.$.restAPI,
-          'getRepoBranches').returns(Promise.resolve([]));
-      return element.reload();
-    });
+      test('_updateRebaseAction sets _parentIsCurrent on no rebase', () => {
+        const currentRevisionActions = {
+          cherrypick: {
+            enabled: true,
+            label: 'Cherry Pick',
+            method: 'POST',
+            title: 'cherrypick',
+          },
+        };
+        element._parentIsCurrent = undefined;
+        element._updateRebaseAction(currentRevisionActions);
+        assert.isTrue(element._parentIsCurrent);
+      });
 
-    teardown(() => {
-      sandbox.restore();
-    });
+      test('_updateRebaseAction', () => {
+        const currentRevisionActions = {
+          cherrypick: {
+            enabled: true,
+            label: 'Cherry Pick',
+            method: 'POST',
+            title: 'cherrypick',
+          },
+          rebase: {
+            enabled: true,
+            label: 'Rebase',
+            method: 'POST',
+            title: 'Rebase onto tip of branch or parent change',
+          },
+        };
+        element._parentIsCurrent = undefined;
 
-    test('confirmSubmitDialog and confirmRebase properties are changed', () => {
-      changeRevisionActions = {};
-      element.reload();
-      assert.strictEqual(element.$.confirmSubmitDialog.action, null);
-      assert.strictEqual(element.$.confirmRebase.rebaseOnCurrent, null);
-    });
+        // Rebase enabled should always end up true.
+        // When rebase is enabled initially, rebaseOnCurrent should be set to
+        // true.
+        assert.equal(element._updateRebaseAction(currentRevisionActions),
+            currentRevisionActions);
 
-    test('_updateRebaseAction sets _parentIsCurrent on no rebase', () => {
-      const currentRevisionActions = {
-        cherrypick: {
-          enabled: true,
-          label: 'Cherry Pick',
-          method: 'POST',
-          title: 'cherrypick',
-        },
-      };
-      element._parentIsCurrent = undefined;
-      element._updateRebaseAction(currentRevisionActions);
-      assert.isTrue(element._parentIsCurrent);
-    });
+        assert.isTrue(currentRevisionActions.rebase.enabled);
+        assert.isTrue(currentRevisionActions.rebase.rebaseOnCurrent);
+        assert.isFalse(element._parentIsCurrent);
 
-    test('_updateRebaseAction', () => {
-      const currentRevisionActions = {
-        cherrypick: {
-          enabled: true,
-          label: 'Cherry Pick',
-          method: 'POST',
-          title: 'cherrypick',
-        },
-        rebase: {
-          enabled: true,
-          label: 'Rebase',
-          method: 'POST',
-          title: 'Rebase onto tip of branch or parent change',
-        },
-      };
-      element._parentIsCurrent = undefined;
+        delete currentRevisionActions.rebase.enabled;
 
-      // Rebase enabled should always end up true.
-      // When rebase is enabled initially, rebaseOnCurrent should be set to
-      // true.
-      assert.equal(element._updateRebaseAction(currentRevisionActions),
-          currentRevisionActions);
+        // When rebase is not enabled initially, rebaseOnCurrent should be set to
+        // false.
+        assert.equal(element._updateRebaseAction(currentRevisionActions),
+            currentRevisionActions);
 
-      assert.isTrue(currentRevisionActions.rebase.enabled);
-      assert.isTrue(currentRevisionActions.rebase.rebaseOnCurrent);
-      assert.isFalse(element._parentIsCurrent);
-
-      delete currentRevisionActions.rebase.enabled;
-
-      // When rebase is not enabled initially, rebaseOnCurrent should be set to
-      // false.
-      assert.equal(element._updateRebaseAction(currentRevisionActions),
-          currentRevisionActions);
-
-      assert.isTrue(currentRevisionActions.rebase.enabled);
-      assert.isFalse(currentRevisionActions.rebase.rebaseOnCurrent);
-      assert.isTrue(element._parentIsCurrent);
+        assert.isTrue(currentRevisionActions.rebase.enabled);
+        assert.isFalse(currentRevisionActions.rebase.rebaseOnCurrent);
+        assert.isTrue(element._parentIsCurrent);
+      });
     });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata-it_test.html b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata-it_test.html
index 8d85dce..3269dc0 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata-it_test.html
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata-it_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="../../plugins/gr-plugin-host/gr-plugin-host.html">
 <link rel="import" href="gr-change-metadata.html">
@@ -42,7 +43,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-change-metadata integration tests', () => {
+  suite('gr-change-metadata integration tests', async () => {
+    await readyToTest();
     let sandbox;
     let element;
 
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.html b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.html
index 6acf4fe..0ae0898 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.html
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="../../core/gr-router/gr-router.html">
 <link rel="import" href="gr-change-metadata.html">
@@ -36,7 +37,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-change-metadata tests', () => {
+  suite('gr-change-metadata tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements_test.html b/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements_test.html
index 242fe2c..6f0d0c7 100644
--- a/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements_test.html
+++ b/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-change-requirements.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-change-metadata tests', () => {
+  suite('gr-change-metadata tests', async () => {
+    await readyToTest();
     let element;
 
     setup(() => {
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
index d2f8c87..8402cad 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
@@ -413,6 +413,8 @@
       this.addEventListener('comment-refresh', this._reloadDrafts.bind(this));
       this.addEventListener('comment-discard',
           this._handleCommentDiscard.bind(this));
+      this.addEventListener('change-message-deleted',
+          () => this._reload());
       this.addEventListener('editable-content-save',
           this._handleCommitMessageSave.bind(this));
       this.addEventListener('editable-content-cancel',
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html
index f0ab218..365e87f 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="/bower_components/page/page.js"></script>
 
@@ -44,7 +45,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-change-view tests', () => {
+  suite('gr-change-view tests', async () => {
+    await readyToTest();
     const kb = window.Gerrit.KeyboardShortcutBinder;
     kb.bindShortcut(kb.Shortcut.SEND_REPLY, 'ctrl+enter');
     kb.bindShortcut(kb.Shortcut.REFRESH_CHANGE, 'shift+r');
diff --git a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list_test.html b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list_test.html
index 97be9b7..a91ec0e 100644
--- a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-comment-list.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-comment-list tests', () => {
+  suite('gr-comment-list tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info_test.html b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info_test.html
index 2c5b431..b063561 100644
--- a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info_test.html
+++ b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="../../core/gr-router/gr-router.html">
 <link rel="import" href="gr-commit-info.html">
@@ -36,7 +37,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-commit-info tests', () => {
+  suite('gr-commit-info tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog_test.html b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog_test.html
index e9964c5..2a14cc3 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-confirm-abandon-dialog.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-confirm-abandon-dialog tests', () => {
+  suite('gr-confirm-abandon-dialog tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog_test.html b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog_test.html
index 557972a..1dcc114 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-confirm-cherrypick-conflict-dialog.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-confirm-cherrypick-conflict-dialog tests', () => {
+  suite('gr-confirm-cherrypick-conflict-dialog tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_test.html b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_test.html
index 42310fb..12e6252 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-confirm-cherrypick-dialog.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-confirm-cherrypick-dialog tests', () => {
+  suite('gr-confirm-cherrypick-dialog tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_test.html b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_test.html
index 036950b..465ce73 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-confirm-move-dialog.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-confirm-move-dialog tests', () => {
+  suite('gr-confirm-move-dialog tests', async () => {
+    await readyToTest();
     let element;
 
     setup(() => {
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_test.html b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_test.html
index 09953ce..fe42cac 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-confirm-rebase-dialog.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-confirm-rebase-dialog tests', () => {
+  suite('gr-confirm-rebase-dialog tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_test.html b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_test.html
index 76f5ecd..29886dd 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-confirm-revert-dialog.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-confirm-revert-dialog tests', () => {
+  suite('gr-confirm-revert-dialog tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog_test.html b/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog_test.html
index af99c7e..2513986 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-confirm-revert-submission-dialog.html">
 
@@ -36,7 +37,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-confirm-revert-submission-dialog tests', () => {
+  suite('gr-confirm-revert-submission-dialog tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog_test.html b/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog_test.html
index 2ae58af..ae19e4f 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="/bower_components/page/page.js"></script>
 
@@ -37,7 +38,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-file-list-header tests', () => {
+  suite('gr-file-list-header tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html
index 0f1260f..3c98fff 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-download-dialog.html">
 
@@ -119,7 +120,8 @@
     };
   }
 
-  suite('gr-download-dialog', () => {
+  suite('gr-download-dialog', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.html b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.html
index 1b4b34d..4979c32 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="/bower_components/page/page.js"></script>
 
@@ -43,7 +44,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-file-list-header tests', () => {
+  suite('gr-file-list-header tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
index 04da0c7..fd10a22 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
@@ -23,6 +23,8 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
+<script src="/components/web-component-tester/data/a11ySuite.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="/bower_components/page/page.js"></script>
 <link rel="import" href="../../diff/gr-comment-api/gr-comment-api.html">
@@ -50,7 +52,9 @@
 </test-fixture>
 
 <script>
-  suite('gr-file-list tests', () => {
+  suite('gr-file-list tests', async () => {
+    await readyToTest();
+
     const kb = window.Gerrit.KeyboardShortcutBinder;
     kb.bindShortcut(kb.Shortcut.LEFT_PANE, 'shift+left');
     kb.bindShortcut(kb.Shortcut.RIGHT_PANE, 'shift+right');
@@ -75,1144 +79,1163 @@
     let saveStub;
     let loadCommentSpy;
 
-    setup(done => {
-      sandbox = sinon.sandbox.create();
-      stub('gr-rest-api-interface', {
-        getLoggedIn() { return Promise.resolve(true); },
-        getPreferences() { return Promise.resolve({}); },
-        getDiffPreferences() { return Promise.resolve({}); },
-        getDiffComments() { return Promise.resolve({}); },
-        getDiffRobotComments() { return Promise.resolve({}); },
-        getDiffDrafts() { return Promise.resolve({}); },
-        getAccountCapabilities() { return Promise.resolve({}); },
-      });
-      stub('gr-date-formatter', {
-        _loadTimeFormat() { return Promise.resolve(''); },
-      });
-      stub('gr-diff-host', {
-        reload() { return Promise.resolve(); },
+    suite('basic tests', () => {
+      setup(done => {
+        sandbox = sinon.sandbox.create();
+        stub('gr-rest-api-interface', {
+          getLoggedIn() { return Promise.resolve(true); },
+          getPreferences() { return Promise.resolve({}); },
+          getDiffPreferences() { return Promise.resolve({}); },
+          getDiffComments() { return Promise.resolve({}); },
+          getDiffRobotComments() { return Promise.resolve({}); },
+          getDiffDrafts() { return Promise.resolve({}); },
+          getAccountCapabilities() { return Promise.resolve({}); },
+        });
+        stub('gr-date-formatter', {
+          _loadTimeFormat() { return Promise.resolve(''); },
+        });
+        stub('gr-diff-host', {
+          reload() { return Promise.resolve(); },
+        });
+
+        // Element must be wrapped in an element with direct access to the
+        // comment API.
+        commentApiWrapper = fixture('basic');
+        element = commentApiWrapper.$.fileList;
+        loadCommentSpy = sandbox.spy(commentApiWrapper.$.commentAPI, 'loadAll');
+
+        // Stub methods on the changeComments object after changeComments has
+        // been initialized.
+        commentApiWrapper.loadComments().then(() => {
+          sandbox.stub(element.changeComments, 'getPaths').returns({});
+          sandbox.stub(element.changeComments, 'getCommentsBySideForPath')
+              .returns({meta: {}, left: [], right: []});
+          done();
+        });
+        element._loading = false;
+        element.diffPrefs = {};
+        element.numFilesShown = 200;
+        element.patchRange = {
+          basePatchNum: 'PARENT',
+          patchNum: '2',
+        };
+        saveStub = sandbox.stub(element, '_saveReviewedState',
+            () => Promise.resolve());
       });
 
-      // Element must be wrapped in an element with direct access to the
-      // comment API.
-      commentApiWrapper = fixture('basic');
-      element = commentApiWrapper.$.fileList;
-      loadCommentSpy = sandbox.spy(commentApiWrapper.$.commentAPI, 'loadAll');
-
-      // Stub methods on the changeComments object after changeComments has
-      // been initialized.
-      commentApiWrapper.loadComments().then(() => {
-        sandbox.stub(element.changeComments, 'getPaths').returns({});
-        sandbox.stub(element.changeComments, 'getCommentsBySideForPath')
-            .returns({meta: {}, left: [], right: []});
-        done();
+      teardown(() => {
+        sandbox.restore();
       });
-      element._loading = false;
-      element.diffPrefs = {};
-      element.numFilesShown = 200;
-      element.patchRange = {
-        basePatchNum: 'PARENT',
-        patchNum: '2',
-      };
-      saveStub = sandbox.stub(element, '_saveReviewedState',
-          () => Promise.resolve());
-    });
 
-    teardown(() => {
-      sandbox.restore();
-    });
+      test('correct number of files are shown', () => {
+        element.fileListIncrement = 300;
+        element._filesByPath = _.range(500)
+            .reduce((_filesByPath, i) => {
+              _filesByPath['/file' + i] = {lines_inserted: 9};
+              return _filesByPath;
+            }, {});
 
-    test('correct number of files are shown', () => {
-      element.fileListIncrement = 300;
-      element._filesByPath = _.range(500)
-          .reduce((_filesByPath, i) => {
-            _filesByPath['/file' + i] = {lines_inserted: 9};
-            return _filesByPath;
-          }, {});
+        flushAsynchronousOperations();
+        assert.equal(
+            Polymer.dom(element.root).querySelectorAll('.file-row').length,
+            element.numFilesShown);
+        const controlRow = element.$$('.controlRow');
+        assert.isFalse(controlRow.classList.contains('invisible'));
+        assert.equal(element.$.incrementButton.textContent.trim(),
+            'Show 300 more');
+        assert.equal(element.$.showAllButton.textContent.trim(),
+            'Show all 500 files');
 
-      flushAsynchronousOperations();
-      assert.equal(
-          Polymer.dom(element.root).querySelectorAll('.file-row').length,
-          element.numFilesShown);
-      const controlRow = element.$$('.controlRow');
-      assert.isFalse(controlRow.classList.contains('invisible'));
-      assert.equal(element.$.incrementButton.textContent.trim(),
-          'Show 300 more');
-      assert.equal(element.$.showAllButton.textContent.trim(),
-          'Show all 500 files');
+        MockInteractions.tap(element.$.showAllButton);
+        flushAsynchronousOperations();
 
-      MockInteractions.tap(element.$.showAllButton);
-      flushAsynchronousOperations();
-
-      assert.equal(element.numFilesShown, 500);
-      assert.equal(element._shownFiles.length, 500);
-      assert.isTrue(controlRow.classList.contains('invisible'));
-    });
-
-    test('rendering each row calls the _reportRenderedRow method', () => {
-      const renderedStub = sandbox.stub(element, '_reportRenderedRow');
-      element._filesByPath = _.range(10)
-          .reduce((_filesByPath, i) => {
-            _filesByPath['/file' + i] = {lines_inserted: 9};
-            return _filesByPath;
-          }, {});
-      flushAsynchronousOperations();
-      assert.equal(
-          Polymer.dom(element.root).querySelectorAll('.file-row').length, 10);
-      assert.equal(renderedStub.callCount, 10);
-    });
-
-    test('calculate totals for patch number', () => {
-      element._filesByPath = {
-        '/COMMIT_MSG': {
-          lines_inserted: 9,
-        },
-        '/MERGE_LIST': {
-          lines_inserted: 9,
-        },
-        'file_added_in_rev2.txt': {
-          lines_inserted: 1,
-          lines_deleted: 1,
-          size_delta: 10,
-          size: 100,
-        },
-        'myfile.txt': {
-          lines_inserted: 1,
-          lines_deleted: 1,
-          size_delta: 10,
-          size: 100,
-        },
-      };
-
-      assert.deepEqual(element._patchChange, {
-        inserted: 2,
-        deleted: 2,
-        size_delta_inserted: 0,
-        size_delta_deleted: 0,
-        total_size: 0,
+        assert.equal(element.numFilesShown, 500);
+        assert.equal(element._shownFiles.length, 500);
+        assert.isTrue(controlRow.classList.contains('invisible'));
       });
-      assert.isTrue(element._hideBinaryChangeTotals);
-      assert.isFalse(element._hideChangeTotals);
 
-      // Test with a commit message that isn't the first file.
-      element._filesByPath = {
-        'file_added_in_rev2.txt': {
-          lines_inserted: 1,
-          lines_deleted: 1,
-        },
-        '/COMMIT_MSG': {
-          lines_inserted: 9,
-        },
-        '/MERGE_LIST': {
-          lines_inserted: 9,
-        },
-        'myfile.txt': {
-          lines_inserted: 1,
-          lines_deleted: 1,
-        },
-      };
-
-      assert.deepEqual(element._patchChange, {
-        inserted: 2,
-        deleted: 2,
-        size_delta_inserted: 0,
-        size_delta_deleted: 0,
-        total_size: 0,
+      test('rendering each row calls the _reportRenderedRow method', () => {
+        const renderedStub = sandbox.stub(element, '_reportRenderedRow');
+        element._filesByPath = _.range(10)
+            .reduce((_filesByPath, i) => {
+              _filesByPath['/file' + i] = {lines_inserted: 9};
+              return _filesByPath;
+            }, {});
+        flushAsynchronousOperations();
+        assert.equal(
+            Polymer.dom(element.root).querySelectorAll('.file-row').length, 10);
+        assert.equal(renderedStub.callCount, 10);
       });
-      assert.isTrue(element._hideBinaryChangeTotals);
-      assert.isFalse(element._hideChangeTotals);
 
-      // Test with no commit message.
-      element._filesByPath = {
-        'file_added_in_rev2.txt': {
-          lines_inserted: 1,
-          lines_deleted: 1,
-        },
-        'myfile.txt': {
-          lines_inserted: 1,
-          lines_deleted: 1,
-        },
-      };
+      test('calculate totals for patch number', () => {
+        element._filesByPath = {
+          '/COMMIT_MSG': {
+            lines_inserted: 9,
+          },
+          '/MERGE_LIST': {
+            lines_inserted: 9,
+          },
+          'file_added_in_rev2.txt': {
+            lines_inserted: 1,
+            lines_deleted: 1,
+            size_delta: 10,
+            size: 100,
+          },
+          'myfile.txt': {
+            lines_inserted: 1,
+            lines_deleted: 1,
+            size_delta: 10,
+            size: 100,
+          },
+        };
 
-      assert.deepEqual(element._patchChange, {
-        inserted: 2,
-        deleted: 2,
-        size_delta_inserted: 0,
-        size_delta_deleted: 0,
-        total_size: 0,
+        assert.deepEqual(element._patchChange, {
+          inserted: 2,
+          deleted: 2,
+          size_delta_inserted: 0,
+          size_delta_deleted: 0,
+          total_size: 0,
+        });
+        assert.isTrue(element._hideBinaryChangeTotals);
+        assert.isFalse(element._hideChangeTotals);
+
+        // Test with a commit message that isn't the first file.
+        element._filesByPath = {
+          'file_added_in_rev2.txt': {
+            lines_inserted: 1,
+            lines_deleted: 1,
+          },
+          '/COMMIT_MSG': {
+            lines_inserted: 9,
+          },
+          '/MERGE_LIST': {
+            lines_inserted: 9,
+          },
+          'myfile.txt': {
+            lines_inserted: 1,
+            lines_deleted: 1,
+          },
+        };
+
+        assert.deepEqual(element._patchChange, {
+          inserted: 2,
+          deleted: 2,
+          size_delta_inserted: 0,
+          size_delta_deleted: 0,
+          total_size: 0,
+        });
+        assert.isTrue(element._hideBinaryChangeTotals);
+        assert.isFalse(element._hideChangeTotals);
+
+        // Test with no commit message.
+        element._filesByPath = {
+          'file_added_in_rev2.txt': {
+            lines_inserted: 1,
+            lines_deleted: 1,
+          },
+          'myfile.txt': {
+            lines_inserted: 1,
+            lines_deleted: 1,
+          },
+        };
+
+        assert.deepEqual(element._patchChange, {
+          inserted: 2,
+          deleted: 2,
+          size_delta_inserted: 0,
+          size_delta_deleted: 0,
+          total_size: 0,
+        });
+        assert.isTrue(element._hideBinaryChangeTotals);
+        assert.isFalse(element._hideChangeTotals);
+
+        // Test with files missing either lines_inserted or lines_deleted.
+        element._filesByPath = {
+          'file_added_in_rev2.txt': {lines_inserted: 1},
+          'myfile.txt': {lines_deleted: 1},
+        };
+        assert.deepEqual(element._patchChange, {
+          inserted: 1,
+          deleted: 1,
+          size_delta_inserted: 0,
+          size_delta_deleted: 0,
+          total_size: 0,
+        });
+        assert.isTrue(element._hideBinaryChangeTotals);
+        assert.isFalse(element._hideChangeTotals);
       });
-      assert.isTrue(element._hideBinaryChangeTotals);
-      assert.isFalse(element._hideChangeTotals);
 
-      // Test with files missing either lines_inserted or lines_deleted.
-      element._filesByPath = {
-        'file_added_in_rev2.txt': {lines_inserted: 1},
-        'myfile.txt': {lines_deleted: 1},
-      };
-      assert.deepEqual(element._patchChange, {
-        inserted: 1,
-        deleted: 1,
-        size_delta_inserted: 0,
-        size_delta_deleted: 0,
-        total_size: 0,
+      test('binary only files', () => {
+        element._filesByPath = {
+          '/COMMIT_MSG': {lines_inserted: 9},
+          'file_binary_1': {binary: true, size_delta: 10, size: 100},
+          'file_binary_2': {binary: true, size_delta: -5, size: 120},
+        };
+        assert.deepEqual(element._patchChange, {
+          inserted: 0,
+          deleted: 0,
+          size_delta_inserted: 10,
+          size_delta_deleted: -5,
+          total_size: 220,
+        });
+        assert.isFalse(element._hideBinaryChangeTotals);
+        assert.isTrue(element._hideChangeTotals);
       });
-      assert.isTrue(element._hideBinaryChangeTotals);
-      assert.isFalse(element._hideChangeTotals);
-    });
 
-    test('binary only files', () => {
-      element._filesByPath = {
-        '/COMMIT_MSG': {lines_inserted: 9},
-        'file_binary_1': {binary: true, size_delta: 10, size: 100},
-        'file_binary_2': {binary: true, size_delta: -5, size: 120},
-      };
-      assert.deepEqual(element._patchChange, {
-        inserted: 0,
-        deleted: 0,
-        size_delta_inserted: 10,
-        size_delta_deleted: -5,
-        total_size: 220,
+      test('binary and regular files', () => {
+        element._filesByPath = {
+          '/COMMIT_MSG': {lines_inserted: 9},
+          'file_binary_1': {binary: true, size_delta: 10, size: 100},
+          'file_binary_2': {binary: true, size_delta: -5, size: 120},
+          'myfile.txt': {lines_deleted: 5, size_delta: -10, size: 100},
+          'myfile2.txt': {lines_inserted: 10},
+        };
+        assert.deepEqual(element._patchChange, {
+          inserted: 10,
+          deleted: 5,
+          size_delta_inserted: 10,
+          size_delta_deleted: -5,
+          total_size: 220,
+        });
+        assert.isFalse(element._hideBinaryChangeTotals);
+        assert.isFalse(element._hideChangeTotals);
       });
-      assert.isFalse(element._hideBinaryChangeTotals);
-      assert.isTrue(element._hideChangeTotals);
-    });
 
-    test('binary and regular files', () => {
-      element._filesByPath = {
-        '/COMMIT_MSG': {lines_inserted: 9},
-        'file_binary_1': {binary: true, size_delta: 10, size: 100},
-        'file_binary_2': {binary: true, size_delta: -5, size: 120},
-        'myfile.txt': {lines_deleted: 5, size_delta: -10, size: 100},
-        'myfile2.txt': {lines_inserted: 10},
-      };
-      assert.deepEqual(element._patchChange, {
-        inserted: 10,
-        deleted: 5,
-        size_delta_inserted: 10,
-        size_delta_deleted: -5,
-        total_size: 220,
-      });
-      assert.isFalse(element._hideBinaryChangeTotals);
-      assert.isFalse(element._hideChangeTotals);
-    });
+      test('_formatBytes function', () => {
+        const table = {
+          '64': '+64 B',
+          '1023': '+1023 B',
+          '1024': '+1 KiB',
+          '4096': '+4 KiB',
+          '1073741824': '+1 GiB',
+          '-64': '-64 B',
+          '-1023': '-1023 B',
+          '-1024': '-1 KiB',
+          '-4096': '-4 KiB',
+          '-1073741824': '-1 GiB',
+          '0': '+/-0 B',
+        };
 
-    test('_formatBytes function', () => {
-      const table = {
-        '64': '+64 B',
-        '1023': '+1023 B',
-        '1024': '+1 KiB',
-        '4096': '+4 KiB',
-        '1073741824': '+1 GiB',
-        '-64': '-64 B',
-        '-1023': '-1023 B',
-        '-1024': '-1 KiB',
-        '-4096': '-4 KiB',
-        '-1073741824': '-1 GiB',
-        '0': '+/-0 B',
-      };
-
-      for (const bytes in table) {
-        if (table.hasOwnProperty(bytes)) {
-          assert.equal(element._formatBytes(bytes), table[bytes]);
+        for (const bytes in table) {
+          if (table.hasOwnProperty(bytes)) {
+            assert.equal(element._formatBytes(bytes), table[bytes]);
+          }
         }
-      }
-    });
+      });
 
-    test('_formatPercentage function', () => {
-      const table = [
-        {size: 100,
-          delta: 100,
-          display: '',
-        },
-        {size: 195060,
-          delta: 64,
-          display: '(+0%)',
-        },
-        {size: 195060,
-          delta: -64,
-          display: '(-0%)',
-        },
-        {size: 394892,
-          delta: -7128,
-          display: '(-2%)',
-        },
-        {size: 90,
-          delta: -10,
-          display: '(-10%)',
-        },
-        {size: 110,
-          delta: 10,
-          display: '(+10%)',
-        },
-      ];
-
-      for (const item of table) {
-        assert.equal(element._formatPercentage(
-            item.size, item.delta), item.display);
-      }
-    });
-
-    test('comment filtering', () => {
-      element.changeComments._comments = {
-        '/COMMIT_MSG': [
-          {patch_set: 1, message: 'Done', updated: '2017-02-08 16:40:49'},
-          {patch_set: 1, message: 'oh hay', updated: '2017-02-09 16:40:49'},
-          {patch_set: 2, message: 'hello', updated: '2017-02-10 16:40:49'},
-        ],
-        'myfile.txt': [
-          {patch_set: 1, message: 'good news!', updated: '2017-02-08 16:40:49'},
-          {patch_set: 2, message: 'wat!?', updated: '2017-02-09 16:40:49'},
-          {patch_set: 2, message: 'hi', updated: '2017-02-10 16:40:49'},
-        ],
-        'unresolved.file': [
-          {
-            patch_set: 2,
-            message: 'wat!?',
-            updated: '2017-02-09 16:40:49',
-            id: '1',
-            unresolved: true,
+      test('_formatPercentage function', () => {
+        const table = [
+          {size: 100,
+            delta: 100,
+            display: '',
           },
-          {
-            patch_set: 2,
-            message: 'hi',
-            updated: '2017-02-10 16:40:49',
-            id: '2',
-            in_reply_to: '1',
-            unresolved: false,
+          {size: 195060,
+            delta: 64,
+            display: '(+0%)',
           },
-          {
-            patch_set: 2,
-            message: 'good news!',
-            updated: '2017-02-08 16:40:49',
-            id: '3',
-            unresolved: true,
+          {size: 195060,
+            delta: -64,
+            display: '(-0%)',
           },
-        ],
-      };
-      element.changeComments._drafts = {
-        '/COMMIT_MSG': [
-          {
-            patch_set: 1,
-            message: 'hi',
-            updated: '2017-02-15 16:40:49',
-            id: '5',
-            unresolved: true,
+          {size: 394892,
+            delta: -7128,
+            display: '(-2%)',
           },
-          {
-            patch_set: 1,
-            message: 'fyi',
-            updated: '2017-02-15 16:40:49',
-            id: '6',
-            unresolved: false,
+          {size: 90,
+            delta: -10,
+            display: '(-10%)',
           },
-        ],
-        'unresolved.file': [
-          {
-            patch_set: 1,
-            message: 'hi',
-            updated: '2017-02-11 16:40:49',
-            id: '4',
-            unresolved: false,
+          {size: 110,
+            delta: 10,
+            display: '(+10%)',
           },
-        ],
-      };
+        ];
 
-      const parentTo1 = {
-        basePatchNum: 'PARENT',
-        patchNum: '1',
-      };
+        for (const item of table) {
+          assert.equal(element._formatPercentage(
+              item.size, item.delta), item.display);
+        }
+      });
 
-      const parentTo2 = {
-        basePatchNum: 'PARENT',
-        patchNum: '2',
-      };
+      test('comment filtering', () => {
+        element.changeComments._comments = {
+          '/COMMIT_MSG': [
+            {patch_set: 1, message: 'Done', updated: '2017-02-08 16:40:49'},
+            {patch_set: 1, message: 'oh hay', updated: '2017-02-09 16:40:49'},
+            {patch_set: 2, message: 'hello', updated: '2017-02-10 16:40:49'},
+          ],
+          'myfile.txt': [
+            {patch_set: 1, message: 'good news!', updated: '2017-02-08 16:40:49'},
+            {patch_set: 2, message: 'wat!?', updated: '2017-02-09 16:40:49'},
+            {patch_set: 2, message: 'hi', updated: '2017-02-10 16:40:49'},
+          ],
+          'unresolved.file': [
+            {
+              patch_set: 2,
+              message: 'wat!?',
+              updated: '2017-02-09 16:40:49',
+              id: '1',
+              unresolved: true,
+            },
+            {
+              patch_set: 2,
+              message: 'hi',
+              updated: '2017-02-10 16:40:49',
+              id: '2',
+              in_reply_to: '1',
+              unresolved: false,
+            },
+            {
+              patch_set: 2,
+              message: 'good news!',
+              updated: '2017-02-08 16:40:49',
+              id: '3',
+              unresolved: true,
+            },
+          ],
+        };
+        element.changeComments._drafts = {
+          '/COMMIT_MSG': [
+            {
+              patch_set: 1,
+              message: 'hi',
+              updated: '2017-02-15 16:40:49',
+              id: '5',
+              unresolved: true,
+            },
+            {
+              patch_set: 1,
+              message: 'fyi',
+              updated: '2017-02-15 16:40:49',
+              id: '6',
+              unresolved: false,
+            },
+          ],
+          'unresolved.file': [
+            {
+              patch_set: 1,
+              message: 'hi',
+              updated: '2017-02-11 16:40:49',
+              id: '4',
+              unresolved: false,
+            },
+          ],
+        };
 
-      const _1To2 = {
-        basePatchNum: '1',
-        patchNum: '2',
-      };
+        const parentTo1 = {
+          basePatchNum: 'PARENT',
+          patchNum: '1',
+        };
 
-      assert.equal(
-          element._computeCommentsString(element.changeComments, parentTo1,
-              '/COMMIT_MSG', 'comment'), '2 comments (1 unresolved)');
-      assert.equal(
-          element._computeCommentsString(element.changeComments, _1To2,
-              '/COMMIT_MSG', 'comment'), '3 comments (1 unresolved)');
-      assert.equal(
-          element._computeCommentsStringMobile(element.changeComments, parentTo1
-              , '/COMMIT_MSG'), '2c');
-      assert.equal(
-          element._computeCommentsStringMobile(element.changeComments, _1To2
-              , '/COMMIT_MSG'), '3c');
-      assert.equal(
-          element._computeDraftsString(element.changeComments, parentTo1,
-              'unresolved.file'), '1 draft');
-      assert.equal(
-          element._computeDraftsString(element.changeComments, _1To2,
-              'unresolved.file'), '1 draft');
-      assert.equal(
-          element._computeDraftsStringMobile(element.changeComments, parentTo1,
-              'unresolved.file'), '1d');
-      assert.equal(
-          element._computeDraftsStringMobile(element.changeComments, _1To2,
-              'unresolved.file'), '1d');
-      assert.equal(
-          element._computeCommentsString(element.changeComments, parentTo1,
-              'myfile.txt', 'comment'), '1 comment');
-      assert.equal(
-          element._computeCommentsString(element.changeComments, _1To2,
-              'myfile.txt', 'comment'), '3 comments');
-      assert.equal(
-          element._computeCommentsStringMobile(element.changeComments, parentTo1,
-              'myfile.txt'), '1c');
-      assert.equal(
-          element._computeCommentsStringMobile(element.changeComments, _1To2,
-              'myfile.txt'), '3c');
-      assert.equal(
-          element._computeDraftsString(element.changeComments, parentTo1,
-              'myfile.txt'), '');
-      assert.equal(
-          element._computeDraftsString(element.changeComments, _1To2,
-              'myfile.txt'), '');
-      assert.equal(
-          element._computeDraftsStringMobile(element.changeComments, parentTo1,
-              'myfile.txt'), '');
-      assert.equal(
-          element._computeDraftsStringMobile(element.changeComments, _1To2,
-              'myfile.txt'), '');
-      assert.equal(
-          element._computeCommentsString(element.changeComments, parentTo1,
-              'file_added_in_rev2.txt', 'comment'), '');
-      assert.equal(
-          element._computeCommentsString(element.changeComments, _1To2,
-              'file_added_in_rev2.txt', 'comment'), '');
-      assert.equal(
-          element._computeCommentsStringMobile(element.changeComments, parentTo1,
-              'file_added_in_rev2.txt'), '');
-      assert.equal(
-          element._computeCommentsStringMobile(element.changeComments, _1To2,
-              'file_added_in_rev2.txt'), '');
-      assert.equal(
-          element._computeDraftsString(element.changeComments, parentTo1,
-              'file_added_in_rev2.txt'), '');
-      assert.equal(
-          element._computeDraftsString(element.changeComments, _1To2,
-              'file_added_in_rev2.txt'), '');
-      assert.equal(
-          element._computeDraftsStringMobile(element.changeComments, parentTo1,
-              'file_added_in_rev2.txt'), '');
-      assert.equal(
-          element._computeDraftsStringMobile(element.changeComments, _1To2,
-              'file_added_in_rev2.txt'), '');
-      assert.equal(
-          element._computeCommentsString(element.changeComments, parentTo2,
-              '/COMMIT_MSG', 'comment'), '1 comment');
-      assert.equal(
-          element._computeCommentsString(element.changeComments, _1To2,
-              '/COMMIT_MSG', 'comment'), '3 comments (1 unresolved)');
-      assert.equal(
-          element._computeCommentsStringMobile(element.changeComments, parentTo2,
-              '/COMMIT_MSG'), '1c');
-      assert.equal(
-          element._computeCommentsStringMobile(element.changeComments, _1To2,
-              '/COMMIT_MSG'), '3c');
-      assert.equal(
-          element._computeDraftsString(element.changeComments, parentTo1,
-              '/COMMIT_MSG'), '2 drafts');
-      assert.equal(
-          element._computeDraftsString(element.changeComments, _1To2,
-              '/COMMIT_MSG'), '2 drafts');
-      assert.equal(
-          element._computeDraftsStringMobile(element.changeComments, parentTo1,
-              '/COMMIT_MSG'), '2d');
-      assert.equal(
-          element._computeDraftsStringMobile(element.changeComments, _1To2,
-              '/COMMIT_MSG'), '2d');
-      assert.equal(
-          element._computeCommentsString(element.changeComments, parentTo2,
-              'myfile.txt', 'comment'), '2 comments');
-      assert.equal(
-          element._computeCommentsString(element.changeComments, _1To2,
-              'myfile.txt', 'comment'), '3 comments');
-      assert.equal(
-          element._computeCommentsStringMobile(element.changeComments, parentTo2,
-              'myfile.txt'), '2c');
-      assert.equal(
-          element._computeCommentsStringMobile(element.changeComments, _1To2,
-              'myfile.txt'), '3c');
-      assert.equal(
-          element._computeDraftsStringMobile(element.changeComments, parentTo2,
-              'myfile.txt'), '');
-      assert.equal(
-          element._computeDraftsStringMobile(element.changeComments, _1To2,
-              'myfile.txt'), '');
-      assert.equal(
-          element._computeCommentsString(element.changeComments, parentTo2,
-              'file_added_in_rev2.txt', 'comment'), '');
-      assert.equal(
-          element._computeCommentsString(element.changeComments, _1To2,
-              'file_added_in_rev2.txt', 'comment'), '');
-      assert.equal(
-          element._computeCommentsString(element.changeComments, parentTo2,
-              'unresolved.file', 'comment'), '3 comments (1 unresolved)');
-      assert.equal(
-          element._computeCommentsString(element.changeComments, _1To2,
-              'unresolved.file', 'comment'), '3 comments (1 unresolved)');
-    });
+        const parentTo2 = {
+          basePatchNum: 'PARENT',
+          patchNum: '2',
+        };
 
-    test('_reviewedTitle', () => {
-      assert.equal(
-          element._reviewedTitle(true), 'Mark as not reviewed (shortcut: r)');
+        const _1To2 = {
+          basePatchNum: '1',
+          patchNum: '2',
+        };
 
-      assert.equal(
-          element._reviewedTitle(false), 'Mark as reviewed (shortcut: r)');
-    });
+        assert.equal(
+            element._computeCommentsString(element.changeComments, parentTo1,
+                '/COMMIT_MSG', 'comment'), '2 comments (1 unresolved)');
+        assert.equal(
+            element._computeCommentsString(element.changeComments, _1To2,
+                '/COMMIT_MSG', 'comment'), '3 comments (1 unresolved)');
+        assert.equal(
+            element._computeCommentsStringMobile(element.changeComments, parentTo1
+                , '/COMMIT_MSG'), '2c');
+        assert.equal(
+            element._computeCommentsStringMobile(element.changeComments, _1To2
+                , '/COMMIT_MSG'), '3c');
+        assert.equal(
+            element._computeDraftsString(element.changeComments, parentTo1,
+                'unresolved.file'), '1 draft');
+        assert.equal(
+            element._computeDraftsString(element.changeComments, _1To2,
+                'unresolved.file'), '1 draft');
+        assert.equal(
+            element._computeDraftsStringMobile(element.changeComments, parentTo1,
+                'unresolved.file'), '1d');
+        assert.equal(
+            element._computeDraftsStringMobile(element.changeComments, _1To2,
+                'unresolved.file'), '1d');
+        assert.equal(
+            element._computeCommentsString(element.changeComments, parentTo1,
+                'myfile.txt', 'comment'), '1 comment');
+        assert.equal(
+            element._computeCommentsString(element.changeComments, _1To2,
+                'myfile.txt', 'comment'), '3 comments');
+        assert.equal(
+            element._computeCommentsStringMobile(
+                element.changeComments,
+                parentTo1,
+                'myfile.txt'
+            ), '1c');
+        assert.equal(
+            element._computeCommentsStringMobile(element.changeComments, _1To2,
+                'myfile.txt'), '3c');
+        assert.equal(
+            element._computeDraftsString(element.changeComments, parentTo1,
+                'myfile.txt'), '');
+        assert.equal(
+            element._computeDraftsString(element.changeComments, _1To2,
+                'myfile.txt'), '');
+        assert.equal(
+            element._computeDraftsStringMobile(element.changeComments, parentTo1,
+                'myfile.txt'), '');
+        assert.equal(
+            element._computeDraftsStringMobile(element.changeComments, _1To2,
+                'myfile.txt'), '');
+        assert.equal(
+            element._computeCommentsString(element.changeComments, parentTo1,
+                'file_added_in_rev2.txt', 'comment'), '');
+        assert.equal(
+            element._computeCommentsString(element.changeComments, _1To2,
+                'file_added_in_rev2.txt', 'comment'), '');
+        assert.equal(
+            element._computeCommentsStringMobile(
+                element.changeComments,
+                parentTo1,
+                'file_added_in_rev2.txt'
+            ), '');
+        assert.equal(
+            element._computeCommentsStringMobile(element.changeComments, _1To2,
+                'file_added_in_rev2.txt'), '');
+        assert.equal(
+            element._computeDraftsString(element.changeComments, parentTo1,
+                'file_added_in_rev2.txt'), '');
+        assert.equal(
+            element._computeDraftsString(element.changeComments, _1To2,
+                'file_added_in_rev2.txt'), '');
+        assert.equal(
+            element._computeDraftsStringMobile(element.changeComments, parentTo1,
+                'file_added_in_rev2.txt'), '');
+        assert.equal(
+            element._computeDraftsStringMobile(element.changeComments, _1To2,
+                'file_added_in_rev2.txt'), '');
+        assert.equal(
+            element._computeCommentsString(element.changeComments, parentTo2,
+                '/COMMIT_MSG', 'comment'), '1 comment');
+        assert.equal(
+            element._computeCommentsString(element.changeComments, _1To2,
+                '/COMMIT_MSG', 'comment'), '3 comments (1 unresolved)');
+        assert.equal(
+            element._computeCommentsStringMobile(
+                element.changeComments,
+                parentTo2,
+                '/COMMIT_MSG'
+            ), '1c');
+        assert.equal(
+            element._computeCommentsStringMobile(element.changeComments, _1To2,
+                '/COMMIT_MSG'), '3c');
+        assert.equal(
+            element._computeDraftsString(element.changeComments, parentTo1,
+                '/COMMIT_MSG'), '2 drafts');
+        assert.equal(
+            element._computeDraftsString(element.changeComments, _1To2,
+                '/COMMIT_MSG'), '2 drafts');
+        assert.equal(
+            element._computeDraftsStringMobile(
+                element.changeComments,
+                parentTo1,
+                '/COMMIT_MSG'
+            ), '2d');
+        assert.equal(
+            element._computeDraftsStringMobile(element.changeComments, _1To2,
+                '/COMMIT_MSG'), '2d');
+        assert.equal(
+            element._computeCommentsString(element.changeComments, parentTo2,
+                'myfile.txt', 'comment'), '2 comments');
+        assert.equal(
+            element._computeCommentsString(element.changeComments, _1To2,
+                'myfile.txt', 'comment'), '3 comments');
+        assert.equal(
+            element._computeCommentsStringMobile(
+                element.changeComments,
+                parentTo2,
+                'myfile.txt'
+            ), '2c');
+        assert.equal(
+            element._computeCommentsStringMobile(element.changeComments, _1To2,
+                'myfile.txt'), '3c');
+        assert.equal(
+            element._computeDraftsStringMobile(element.changeComments, parentTo2,
+                'myfile.txt'), '');
+        assert.equal(
+            element._computeDraftsStringMobile(element.changeComments, _1To2,
+                'myfile.txt'), '');
+        assert.equal(
+            element._computeCommentsString(element.changeComments, parentTo2,
+                'file_added_in_rev2.txt', 'comment'), '');
+        assert.equal(
+            element._computeCommentsString(element.changeComments, _1To2,
+                'file_added_in_rev2.txt', 'comment'), '');
+        assert.equal(
+            element._computeCommentsString(element.changeComments, parentTo2,
+                'unresolved.file', 'comment'), '3 comments (1 unresolved)');
+        assert.equal(
+            element._computeCommentsString(element.changeComments, _1To2,
+                'unresolved.file', 'comment'), '3 comments (1 unresolved)');
+      });
 
-    suite('keyboard shortcuts', () => {
-      setup(() => {
+      test('_reviewedTitle', () => {
+        assert.equal(
+            element._reviewedTitle(true), 'Mark as not reviewed (shortcut: r)');
+
+        assert.equal(
+            element._reviewedTitle(false), 'Mark as reviewed (shortcut: r)');
+      });
+
+      suite('keyboard shortcuts', () => {
+        setup(() => {
+          element._filesByPath = {
+            '/COMMIT_MSG': {},
+            'file_added_in_rev2.txt': {},
+            'myfile.txt': {},
+          };
+          element.changeNum = '42';
+          element.patchRange = {
+            basePatchNum: 'PARENT',
+            patchNum: '2',
+          };
+          element.change = {_number: 42};
+          element.$.fileCursor.setCursorAtIndex(0);
+        });
+
+        test('toggle left diff via shortcut', () => {
+          const toggleLeftDiffStub = sandbox.stub();
+          // Property getter cannot be stubbed w/ sandbox due to a bug in Sinon.
+          // https://github.com/sinonjs/sinon/issues/781
+          const diffsStub = sinon.stub(element, 'diffs', {
+            get() {
+              return [{toggleLeftDiff: toggleLeftDiffStub}];
+            },
+          });
+          MockInteractions.pressAndReleaseKeyOn(element, 65, 'shift', 'a');
+          assert.isTrue(toggleLeftDiffStub.calledOnce);
+          diffsStub.restore();
+        });
+
+        test('keyboard shortcuts', () => {
+          flushAsynchronousOperations();
+
+          const items = Polymer.dom(element.root).querySelectorAll('.file-row');
+          element.$.fileCursor.stops = items;
+          element.$.fileCursor.setCursorAtIndex(0);
+          assert.equal(items.length, 3);
+          assert.isTrue(items[0].classList.contains('selected'));
+          assert.isFalse(items[1].classList.contains('selected'));
+          assert.isFalse(items[2].classList.contains('selected'));
+          // j with a modifier should not move the cursor.
+          MockInteractions.pressAndReleaseKeyOn(element, 74, 'shift', 'j');
+          assert.equal(element.$.fileCursor.index, 0);
+          // down should not move the cursor.
+          MockInteractions.pressAndReleaseKeyOn(element, 40, null, 'down');
+          assert.equal(element.$.fileCursor.index, 0);
+
+          MockInteractions.pressAndReleaseKeyOn(element, 74, null, 'j');
+          assert.equal(element.$.fileCursor.index, 1);
+          assert.equal(element.selectedIndex, 1);
+          MockInteractions.pressAndReleaseKeyOn(element, 74, null, 'j');
+
+          const navStub = sandbox.stub(Gerrit.Nav, 'navigateToDiff');
+          assert.equal(element.$.fileCursor.index, 2);
+          assert.equal(element.selectedIndex, 2);
+
+          // k with a modifier should not move the cursor.
+          MockInteractions.pressAndReleaseKeyOn(element, 75, 'shift', 'k');
+          assert.equal(element.$.fileCursor.index, 2);
+
+          // up should not move the cursor.
+          MockInteractions.pressAndReleaseKeyOn(element, 38, null, 'down');
+          assert.equal(element.$.fileCursor.index, 2);
+
+          MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
+          assert.equal(element.$.fileCursor.index, 1);
+          assert.equal(element.selectedIndex, 1);
+          MockInteractions.pressAndReleaseKeyOn(element, 79, null, 'o');
+
+          assert(navStub.lastCall.calledWith(element.change,
+              'file_added_in_rev2.txt', '2'),
+          'Should navigate to /c/42/2/file_added_in_rev2.txt');
+
+          MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
+          MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
+          MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
+          assert.equal(element.$.fileCursor.index, 0);
+          assert.equal(element.selectedIndex, 0);
+
+          const createCommentInPlaceStub = sandbox.stub(element.$.diffCursor,
+              'createCommentInPlace');
+          MockInteractions.pressAndReleaseKeyOn(element, 67, null, 'c');
+          assert.isTrue(createCommentInPlaceStub.called);
+        });
+
+        test('i key shows/hides selected inline diff', () => {
+          sandbox.stub(element, '_expandedPathsChanged');
+          flushAsynchronousOperations();
+          const files = Polymer.dom(element.root).querySelectorAll('.file-row');
+          element.$.fileCursor.stops = files;
+          element.$.fileCursor.setCursorAtIndex(0);
+          MockInteractions.keyUpOn(element, 73, null, 'i');
+          flushAsynchronousOperations();
+          assert.include(element._expandedFilePaths, element.diffs[0].path);
+          MockInteractions.keyUpOn(element, 73, null, 'i');
+          flushAsynchronousOperations();
+          assert.notInclude(element._expandedFilePaths, element.diffs[0].path);
+          element.$.fileCursor.setCursorAtIndex(1);
+          MockInteractions.keyUpOn(element, 73, null, 'i');
+          flushAsynchronousOperations();
+          assert.include(element._expandedFilePaths, element.diffs[1].path);
+
+          MockInteractions.keyUpOn(element, 73, 'shift', 'i');
+          flushAsynchronousOperations();
+          for (const index in element.diffs) {
+            if (!element.diffs.hasOwnProperty(index)) { continue; }
+            assert.include(element._expandedFilePaths, element.diffs[index].path);
+          }
+          MockInteractions.keyUpOn(element, 73, 'shift', 'i');
+          flushAsynchronousOperations();
+          for (const index in element.diffs) {
+            if (!element.diffs.hasOwnProperty(index)) { continue; }
+            assert.notInclude(element._expandedFilePaths,
+                element.diffs[index].path);
+          }
+        });
+
+        test('r key toggles reviewed flag', () => {
+          const reducer = (accum, file) => (file.isReviewed ? ++accum : accum);
+          const getNumReviewed = () => element._files.reduce(reducer, 0);
+          flushAsynchronousOperations();
+
+          // Default state should be unreviewed.
+          assert.equal(getNumReviewed(), 0);
+
+          // Press the review key to toggle it (set the flag).
+          MockInteractions.pressAndReleaseKeyOn(element, 82, null, 'r');
+          flushAsynchronousOperations();
+          assert.equal(getNumReviewed(), 1);
+
+          // Press the review key to toggle it (clear the flag).
+          MockInteractions.pressAndReleaseKeyOn(element, 82, null, 'r');
+          assert.equal(getNumReviewed(), 0);
+        });
+
+        suite('_handleOpenFile', () => {
+          let interact;
+
+          setup(() => {
+            sandbox.stub(element, 'shouldSuppressKeyboardShortcut')
+                .returns(false);
+            sandbox.stub(element, 'modifierPressed').returns(false);
+            const openCursorStub = sandbox.stub(element, '_openCursorFile');
+            const openSelectedStub = sandbox.stub(element, '_openSelectedFile');
+            const expandStub = sandbox.stub(element, '_togglePathExpanded');
+
+            interact = function(opt_payload) {
+              openCursorStub.reset();
+              openSelectedStub.reset();
+              expandStub.reset();
+
+              const e = new CustomEvent('fake-keyboard-event', opt_payload);
+              sinon.stub(e, 'preventDefault');
+              element._handleOpenFile(e);
+              assert.isTrue(e.preventDefault.called);
+              const result = {};
+              if (openCursorStub.called) {
+                result.opened_cursor = true;
+              }
+              if (openSelectedStub.called) {
+                result.opened_selected = true;
+              }
+              if (expandStub.called) {
+                result.expanded = true;
+              }
+              return result;
+            };
+          });
+
+          test('open from selected file', () => {
+            element._showInlineDiffs = false;
+            assert.deepEqual(interact(), {opened_selected: true});
+          });
+
+          test('open from diff cursor', () => {
+            element._showInlineDiffs = true;
+            assert.deepEqual(interact(), {opened_cursor: true});
+          });
+
+          test('expand when user prefers', () => {
+            element._showInlineDiffs = false;
+            assert.deepEqual(interact(), {opened_selected: true});
+            element._userPrefs = {};
+            assert.deepEqual(interact(), {opened_selected: true});
+          });
+        });
+
+        test('shift+left/shift+right', () => {
+          const moveLeftStub = sandbox.stub(element.$.diffCursor, 'moveLeft');
+          const moveRightStub = sandbox.stub(element.$.diffCursor, 'moveRight');
+
+          let noDiffsExpanded = true;
+          sandbox.stub(element, '_noDiffsExpanded', () => noDiffsExpanded);
+
+          MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'left');
+          assert.isFalse(moveLeftStub.called);
+          MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'right');
+          assert.isFalse(moveRightStub.called);
+
+          noDiffsExpanded = false;
+
+          MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'left');
+          assert.isTrue(moveLeftStub.called);
+          MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'right');
+          assert.isTrue(moveRightStub.called);
+        });
+      });
+
+      test('computed properties', () => {
+        assert.equal(element._computeFileStatus('A'), 'A');
+        assert.equal(element._computeFileStatus(undefined), 'M');
+        assert.equal(element._computeFileStatus(null), 'M');
+
+        assert.equal(element._computeClass('clazz', '/foo/bar/baz'), 'clazz');
+        assert.equal(element._computeClass('clazz', '/COMMIT_MSG'),
+            'clazz invisible');
+      });
+
+      test('file review status', () => {
+        element._reviewed = ['/COMMIT_MSG', 'myfile.txt'];
         element._filesByPath = {
           '/COMMIT_MSG': {},
           'file_added_in_rev2.txt': {},
           'myfile.txt': {},
         };
+        element._loggedIn = true;
+        element.changeNum = '42';
+        element.patchRange = {
+          basePatchNum: 'PARENT',
+          patchNum: '2',
+        };
+        element.$.fileCursor.setCursorAtIndex(0);
+
+        flushAsynchronousOperations();
+        const fileRows =
+            Polymer.dom(element.root).querySelectorAll('.row:not(.header-row)');
+        const checkSelector = 'input.reviewed[type="checkbox"]';
+        const commitMsg = fileRows[0].querySelector(checkSelector);
+        const fileAdded = fileRows[1].querySelector(checkSelector);
+        const myFile = fileRows[2].querySelector(checkSelector);
+
+        assert.isTrue(commitMsg.checked);
+        assert.isFalse(fileAdded.checked);
+        assert.isTrue(myFile.checked);
+
+        const commitReviewLabel = fileRows[0].querySelector('.reviewedLabel');
+        const markReviewLabel = commitMsg.nextElementSibling;
+        assert.isTrue(commitReviewLabel.classList.contains('isReviewed'));
+        assert.equal(markReviewLabel.textContent, 'MARK UNREVIEWED');
+
+        const clickSpy = sandbox.spy(element, '_handleFileListClick');
+        MockInteractions.tap(markReviewLabel);
+        assert.isTrue(saveStub.lastCall.calledWithExactly('/COMMIT_MSG', false));
+        assert.isFalse(commitReviewLabel.classList.contains('isReviewed'));
+        assert.equal(markReviewLabel.textContent, 'MARK REVIEWED');
+        assert.isTrue(clickSpy.lastCall.args[0].defaultPrevented);
+
+        MockInteractions.tap(markReviewLabel);
+        assert.isTrue(saveStub.lastCall.calledWithExactly('/COMMIT_MSG', true));
+        assert.isTrue(commitReviewLabel.classList.contains('isReviewed'));
+        assert.equal(markReviewLabel.textContent, 'MARK UNREVIEWED');
+        assert.isTrue(clickSpy.lastCall.args[0].defaultPrevented);
+      });
+
+      test('_computeFileStatusLabel', () => {
+        assert.equal(element._computeFileStatusLabel('A'), 'Added');
+        assert.equal(element._computeFileStatusLabel('M'), 'Modified');
+      });
+
+      test('_handleFileListClick', () => {
+        element._filesByPath = {
+          '/COMMIT_MSG': {},
+          'f1.txt': {},
+          'f2.txt': {},
+        };
+        element.changeNum = '42';
+        element.patchRange = {
+          basePatchNum: 'PARENT',
+          patchNum: '2',
+        };
+
+        const clickSpy = sandbox.spy(element, '_handleFileListClick');
+        const reviewStub = sandbox.stub(element, '_reviewFile');
+        const toggleExpandSpy = sandbox.spy(element, '_togglePathExpanded');
+
+        const row = Polymer.dom(element.root)
+            .querySelector('.row[data-path="f1.txt"]');
+
+        // Click on the expand button, resulting in _togglePathExpanded being
+        // called and not resulting in a call to _reviewFile.
+        row.querySelector('div.show-hide').click();
+        assert.isTrue(clickSpy.calledOnce);
+        assert.isTrue(toggleExpandSpy.calledOnce);
+        assert.isFalse(reviewStub.called);
+
+        // Click inside the diff. This should result in no additional calls to
+        // _togglePathExpanded or _reviewFile.
+        Polymer.dom(element.root).querySelector('gr-diff-host')
+            .click();
+        assert.isTrue(clickSpy.calledTwice);
+        assert.isTrue(toggleExpandSpy.calledOnce);
+        assert.isFalse(reviewStub.called);
+
+        // Click the reviewed checkbox, resulting in a call to _reviewFile, but
+        // no additional call to _togglePathExpanded.
+        row.querySelector('.markReviewed').click();
+        assert.isTrue(clickSpy.calledThrice);
+        assert.isTrue(toggleExpandSpy.calledOnce);
+        assert.isTrue(reviewStub.calledOnce);
+      });
+
+      test('_handleFileListClick editMode', () => {
+        element._filesByPath = {
+          '/COMMIT_MSG': {},
+          'f1.txt': {},
+          'f2.txt': {},
+        };
+        element.changeNum = '42';
+        element.patchRange = {
+          basePatchNum: 'PARENT',
+          patchNum: '2',
+        };
+        element.editMode = true;
+        flushAsynchronousOperations();
+        const clickSpy = sandbox.spy(element, '_handleFileListClick');
+        const toggleExpandSpy = sandbox.spy(element, '_togglePathExpanded');
+
+        // Tap the edit controls. Should be ignored by _handleFileListClick.
+        MockInteractions.tap(element.$$('.editFileControls'));
+        assert.isTrue(clickSpy.calledOnce);
+        assert.isFalse(toggleExpandSpy.called);
+      });
+
+      test('patch set from revisions', () => {
+        const expected = [
+          {num: 4, desc: 'test', sha: 'rev4'},
+          {num: 3, desc: 'test', sha: 'rev3'},
+          {num: 2, desc: 'test', sha: 'rev2'},
+          {num: 1, desc: 'test', sha: 'rev1'},
+        ];
+        const patchNums = element.computeAllPatchSets({
+          revisions: {
+            rev3: {_number: 3, description: 'test', date: 3},
+            rev1: {_number: 1, description: 'test', date: 1},
+            rev4: {_number: 4, description: 'test', date: 4},
+            rev2: {_number: 2, description: 'test', date: 2},
+          },
+        });
+        assert.equal(patchNums.length, expected.length);
+        for (let i = 0; i < expected.length; i++) {
+          assert.deepEqual(patchNums[i], expected[i]);
+        }
+      });
+
+      test('checkbox shows/hides diff inline', () => {
+        element._filesByPath = {
+          'myfile.txt': {},
+        };
         element.changeNum = '42';
         element.patchRange = {
           basePatchNum: 'PARENT',
           patchNum: '2',
         };
-        element.change = {_number: 42};
         element.$.fileCursor.setCursorAtIndex(0);
-      });
-
-      test('toggle left diff via shortcut', () => {
-        const toggleLeftDiffStub = sandbox.stub();
-        // Property getter cannot be stubbed w/ sandbox due to a bug in Sinon.
-        // https://github.com/sinonjs/sinon/issues/781
-        const diffsStub = sinon.stub(element, 'diffs', {
-          get() {
-            return [{toggleLeftDiff: toggleLeftDiffStub}];
-          },
-        });
-        MockInteractions.pressAndReleaseKeyOn(element, 65, 'shift', 'a');
-        assert.isTrue(toggleLeftDiffStub.calledOnce);
-        diffsStub.restore();
-      });
-
-      test('keyboard shortcuts', () => {
-        flushAsynchronousOperations();
-
-        const items = Polymer.dom(element.root).querySelectorAll('.file-row');
-        element.$.fileCursor.stops = items;
-        element.$.fileCursor.setCursorAtIndex(0);
-        assert.equal(items.length, 3);
-        assert.isTrue(items[0].classList.contains('selected'));
-        assert.isFalse(items[1].classList.contains('selected'));
-        assert.isFalse(items[2].classList.contains('selected'));
-        // j with a modifier should not move the cursor.
-        MockInteractions.pressAndReleaseKeyOn(element, 74, 'shift', 'j');
-        assert.equal(element.$.fileCursor.index, 0);
-        // down should not move the cursor.
-        MockInteractions.pressAndReleaseKeyOn(element, 40, null, 'down');
-        assert.equal(element.$.fileCursor.index, 0);
-
-        MockInteractions.pressAndReleaseKeyOn(element, 74, null, 'j');
-        assert.equal(element.$.fileCursor.index, 1);
-        assert.equal(element.selectedIndex, 1);
-        MockInteractions.pressAndReleaseKeyOn(element, 74, null, 'j');
-
-        const navStub = sandbox.stub(Gerrit.Nav, 'navigateToDiff');
-        assert.equal(element.$.fileCursor.index, 2);
-        assert.equal(element.selectedIndex, 2);
-
-        // k with a modifier should not move the cursor.
-        MockInteractions.pressAndReleaseKeyOn(element, 75, 'shift', 'k');
-        assert.equal(element.$.fileCursor.index, 2);
-
-        // up should not move the cursor.
-        MockInteractions.pressAndReleaseKeyOn(element, 38, null, 'down');
-        assert.equal(element.$.fileCursor.index, 2);
-
-        MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
-        assert.equal(element.$.fileCursor.index, 1);
-        assert.equal(element.selectedIndex, 1);
-        MockInteractions.pressAndReleaseKeyOn(element, 79, null, 'o');
-
-        assert(navStub.lastCall.calledWith(element.change,
-            'file_added_in_rev2.txt', '2'),
-        'Should navigate to /c/42/2/file_added_in_rev2.txt');
-
-        MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
-        MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
-        MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
-        assert.equal(element.$.fileCursor.index, 0);
-        assert.equal(element.selectedIndex, 0);
-
-        const createCommentInPlaceStub = sandbox.stub(element.$.diffCursor,
-            'createCommentInPlace');
-        MockInteractions.pressAndReleaseKeyOn(element, 67, null, 'c');
-        assert.isTrue(createCommentInPlaceStub.called);
-      });
-
-      test('i key shows/hides selected inline diff', () => {
         sandbox.stub(element, '_expandedPathsChanged');
         flushAsynchronousOperations();
-        const files = Polymer.dom(element.root).querySelectorAll('.file-row');
-        element.$.fileCursor.stops = files;
+        const fileRows =
+            Polymer.dom(element.root).querySelectorAll('.row:not(.header-row)');
+        // Because the label surrounds the input, the tap event is triggered
+        // there first.
+        const showHideLabel = fileRows[0].querySelector('label.show-hide');
+        const showHideCheck = fileRows[0].querySelector(
+            'input.show-hide[type="checkbox"]');
+        assert.isNotOk(showHideCheck.checked);
+        MockInteractions.tap(showHideLabel);
+        assert.isOk(showHideCheck.checked);
+        assert.notEqual(element._expandedFilePaths.indexOf('myfile.txt'), -1);
+      });
+
+      test('diff mode correctly toggles the diffs', () => {
+        element._filesByPath = {
+          'myfile.txt': {},
+        };
+        element.changeNum = '42';
+        element.patchRange = {
+          basePatchNum: 'PARENT',
+          patchNum: '2',
+        };
+        sandbox.spy(element, '_updateDiffPreferences');
         element.$.fileCursor.setCursorAtIndex(0);
-        MockInteractions.keyUpOn(element, 73, null, 'i');
         flushAsynchronousOperations();
-        assert.include(element._expandedFilePaths, element.diffs[0].path);
-        MockInteractions.keyUpOn(element, 73, null, 'i');
-        flushAsynchronousOperations();
-        assert.notInclude(element._expandedFilePaths, element.diffs[0].path);
-        element.$.fileCursor.setCursorAtIndex(1);
-        MockInteractions.keyUpOn(element, 73, null, 'i');
-        flushAsynchronousOperations();
-        assert.include(element._expandedFilePaths, element.diffs[1].path);
 
-        MockInteractions.keyUpOn(element, 73, 'shift', 'i');
+        // Tap on a file to generate the diff.
+        const row = Polymer.dom(element.root)
+            .querySelectorAll('.row:not(.header-row) label.show-hide')[0];
+
+        MockInteractions.tap(row);
         flushAsynchronousOperations();
-        for (const index in element.diffs) {
-          if (!element.diffs.hasOwnProperty(index)) { continue; }
-          assert.include(element._expandedFilePaths, element.diffs[index].path);
-        }
-        MockInteractions.keyUpOn(element, 73, 'shift', 'i');
-        flushAsynchronousOperations();
-        for (const index in element.diffs) {
-          if (!element.diffs.hasOwnProperty(index)) { continue; }
-          assert.notInclude(element._expandedFilePaths,
-              element.diffs[index].path);
-        }
+        const diffDisplay = element.diffs[0];
+        element._userPrefs = {default_diff_view: 'SIDE_BY_SIDE'};
+        element.set('diffViewMode', 'UNIFIED_DIFF');
+        assert.equal(diffDisplay.viewMode, 'UNIFIED_DIFF');
+        assert.isTrue(element._updateDiffPreferences.called);
       });
 
-      test('r key toggles reviewed flag', () => {
-        const reducer = (accum, file) => (file.isReviewed ? ++accum : accum);
-        const getNumReviewed = () => element._files.reduce(reducer, 0);
+      test('expanded attribute not set on path when not expanded', () => {
+        element._filesByPath = {
+          '/COMMIT_MSG': {},
+        };
+        assert.isNotOk(element.$$('.expanded'));
+      });
+
+      test('tapping row ignores links', () => {
+        element._filesByPath = {
+          '/COMMIT_MSG': {},
+        };
+        element.changeNum = '42';
+        element.patchRange = {
+          basePatchNum: 'PARENT',
+          patchNum: '2',
+        };
+        sandbox.stub(element, '_expandedPathsChanged');
+        flushAsynchronousOperations();
+        const commitMsgFile = Polymer.dom(element.root)
+            .querySelectorAll('.row:not(.header-row) a.pathLink')[0];
+
+        // Remove href attribute so the app doesn't route to a diff view
+        commitMsgFile.removeAttribute('href');
+        const togglePathSpy = sandbox.spy(element, '_togglePathExpanded');
+
+        MockInteractions.tap(commitMsgFile);
+        flushAsynchronousOperations();
+        assert(togglePathSpy.notCalled, 'file is opened as diff view');
+        assert.isNotOk(element.$$('.expanded'));
+        assert.notEqual(getComputedStyle(element.$$('.show-hide')).display,
+            'none');
+      });
+
+      test('_togglePathExpanded', () => {
+        const path = 'path/to/my/file.txt';
+        element._filesByPath = {[path]: {}};
+        const renderSpy = sandbox.spy(element, '_renderInOrder');
+        const collapseStub = sandbox.stub(element, '_clearCollapsedDiffs');
+
+        assert.equal(element.$$('iron-icon').icon, 'gr-icons:expand-more');
+        assert.equal(element._expandedFilePaths.length, 0);
+        element._togglePathExpanded(path);
+        flushAsynchronousOperations();
+        assert.equal(collapseStub.lastCall.args[0].length, 0);
+        assert.equal(element.$$('iron-icon').icon, 'gr-icons:expand-less');
+
+        assert.equal(renderSpy.callCount, 1);
+        assert.include(element._expandedFilePaths, path);
+        element._togglePathExpanded(path);
         flushAsynchronousOperations();
 
-        // Default state should be unreviewed.
-        assert.equal(getNumReviewed(), 0);
+        assert.equal(element.$$('iron-icon').icon, 'gr-icons:expand-more');
+        assert.equal(renderSpy.callCount, 1);
+        assert.notInclude(element._expandedFilePaths, path);
+        assert.equal(collapseStub.lastCall.args[0].length, 1);
+      });
 
-        // Press the review key to toggle it (set the flag).
-        MockInteractions.pressAndReleaseKeyOn(element, 82, null, 'r');
+      test('expandAllDiffs and collapseAllDiffs', () => {
+        const collapseStub = sandbox.stub(element, '_clearCollapsedDiffs');
+        const cursorUpdateStub = sandbox.stub(element.$.diffCursor,
+            'handleDiffUpdate');
+
+        const path = 'path/to/my/file.txt';
+        element._filesByPath = {[path]: {}};
+        element.expandAllDiffs();
         flushAsynchronousOperations();
-        assert.equal(getNumReviewed(), 1);
+        assert.isTrue(element._showInlineDiffs);
+        assert.isTrue(cursorUpdateStub.calledOnce);
+        assert.equal(collapseStub.lastCall.args[0].length, 0);
 
-        // Press the review key to toggle it (clear the flag).
-        MockInteractions.pressAndReleaseKeyOn(element, 82, null, 'r');
-        assert.equal(getNumReviewed(), 0);
+        element.collapseAllDiffs();
+        flushAsynchronousOperations();
+        assert.equal(element._expandedFilePaths.length, 0);
+        assert.isFalse(element._showInlineDiffs);
+        assert.isTrue(cursorUpdateStub.calledTwice);
+        assert.equal(collapseStub.lastCall.args[0].length, 1);
       });
 
-      suite('_handleOpenFile', () => {
-        let interact;
-
-        setup(() => {
-          sandbox.stub(element, 'shouldSuppressKeyboardShortcut')
-              .returns(false);
-          sandbox.stub(element, 'modifierPressed').returns(false);
-          const openCursorStub = sandbox.stub(element, '_openCursorFile');
-          const openSelectedStub = sandbox.stub(element, '_openSelectedFile');
-          const expandStub = sandbox.stub(element, '_togglePathExpanded');
-
-          interact = function(opt_payload) {
-            openCursorStub.reset();
-            openSelectedStub.reset();
-            expandStub.reset();
-
-            const e = new CustomEvent('fake-keyboard-event', opt_payload);
-            sinon.stub(e, 'preventDefault');
-            element._handleOpenFile(e);
-            assert.isTrue(e.preventDefault.called);
-            const result = {};
-            if (openCursorStub.called) {
-              result.opened_cursor = true;
-            }
-            if (openSelectedStub.called) {
-              result.opened_selected = true;
-            }
-            if (expandStub.called) {
-              result.expanded = true;
-            }
-            return result;
-          };
-        });
-
-        test('open from selected file', () => {
-          element._showInlineDiffs = false;
-          assert.deepEqual(interact(), {opened_selected: true});
-        });
-
-        test('open from diff cursor', () => {
-          element._showInlineDiffs = true;
-          assert.deepEqual(interact(), {opened_cursor: true});
-        });
-
-        test('expand when user prefers', () => {
-          element._showInlineDiffs = false;
-          assert.deepEqual(interact(), {opened_selected: true});
-          element._userPrefs = {};
-          assert.deepEqual(interact(), {opened_selected: true});
-        });
-      });
-
-      test('shift+left/shift+right', () => {
-        const moveLeftStub = sandbox.stub(element.$.diffCursor, 'moveLeft');
-        const moveRightStub = sandbox.stub(element.$.diffCursor, 'moveRight');
-
-        let noDiffsExpanded = true;
-        sandbox.stub(element, '_noDiffsExpanded', () => noDiffsExpanded);
-
-        MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'left');
-        assert.isFalse(moveLeftStub.called);
-        MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'right');
-        assert.isFalse(moveRightStub.called);
-
-        noDiffsExpanded = false;
-
-        MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'left');
-        assert.isTrue(moveLeftStub.called);
-        MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'right');
-        assert.isTrue(moveRightStub.called);
-      });
-    });
-
-    test('computed properties', () => {
-      assert.equal(element._computeFileStatus('A'), 'A');
-      assert.equal(element._computeFileStatus(undefined), 'M');
-      assert.equal(element._computeFileStatus(null), 'M');
-
-      assert.equal(element._computeClass('clazz', '/foo/bar/baz'), 'clazz');
-      assert.equal(element._computeClass('clazz', '/COMMIT_MSG'),
-          'clazz invisible');
-    });
-
-    test('file review status', () => {
-      element._reviewed = ['/COMMIT_MSG', 'myfile.txt'];
-      element._filesByPath = {
-        '/COMMIT_MSG': {},
-        'file_added_in_rev2.txt': {},
-        'myfile.txt': {},
-      };
-      element._loggedIn = true;
-      element.changeNum = '42';
-      element.patchRange = {
-        basePatchNum: 'PARENT',
-        patchNum: '2',
-      };
-      element.$.fileCursor.setCursorAtIndex(0);
-
-      flushAsynchronousOperations();
-      const fileRows =
-          Polymer.dom(element.root).querySelectorAll('.row:not(.header-row)');
-      const checkSelector = 'input.reviewed[type="checkbox"]';
-      const commitMsg = fileRows[0].querySelector(checkSelector);
-      const fileAdded = fileRows[1].querySelector(checkSelector);
-      const myFile = fileRows[2].querySelector(checkSelector);
-
-      assert.isTrue(commitMsg.checked);
-      assert.isFalse(fileAdded.checked);
-      assert.isTrue(myFile.checked);
-
-      const commitReviewLabel = fileRows[0].querySelector('.reviewedLabel');
-      const markReviewLabel = commitMsg.nextElementSibling;
-      assert.isTrue(commitReviewLabel.classList.contains('isReviewed'));
-      assert.equal(markReviewLabel.textContent, 'MARK UNREVIEWED');
-
-      const clickSpy = sandbox.spy(element, '_handleFileListClick');
-      MockInteractions.tap(markReviewLabel);
-      assert.isTrue(saveStub.lastCall.calledWithExactly('/COMMIT_MSG', false));
-      assert.isFalse(commitReviewLabel.classList.contains('isReviewed'));
-      assert.equal(markReviewLabel.textContent, 'MARK REVIEWED');
-      assert.isTrue(clickSpy.lastCall.args[0].defaultPrevented);
-
-      MockInteractions.tap(markReviewLabel);
-      assert.isTrue(saveStub.lastCall.calledWithExactly('/COMMIT_MSG', true));
-      assert.isTrue(commitReviewLabel.classList.contains('isReviewed'));
-      assert.equal(markReviewLabel.textContent, 'MARK UNREVIEWED');
-      assert.isTrue(clickSpy.lastCall.args[0].defaultPrevented);
-    });
-
-    test('_computeFileStatusLabel', () => {
-      assert.equal(element._computeFileStatusLabel('A'), 'Added');
-      assert.equal(element._computeFileStatusLabel('M'), 'Modified');
-    });
-
-    test('_handleFileListClick', () => {
-      element._filesByPath = {
-        '/COMMIT_MSG': {},
-        'f1.txt': {},
-        'f2.txt': {},
-      };
-      element.changeNum = '42';
-      element.patchRange = {
-        basePatchNum: 'PARENT',
-        patchNum: '2',
-      };
-
-      const clickSpy = sandbox.spy(element, '_handleFileListClick');
-      const reviewStub = sandbox.stub(element, '_reviewFile');
-      const toggleExpandSpy = sandbox.spy(element, '_togglePathExpanded');
-
-      const row = Polymer.dom(element.root)
-          .querySelector('.row[data-path="f1.txt"]');
-
-      // Click on the expand button, resulting in _togglePathExpanded being
-      // called and not resulting in a call to _reviewFile.
-      row.querySelector('div.show-hide').click();
-      assert.isTrue(clickSpy.calledOnce);
-      assert.isTrue(toggleExpandSpy.calledOnce);
-      assert.isFalse(reviewStub.called);
-
-      // Click inside the diff. This should result in no additional calls to
-      // _togglePathExpanded or _reviewFile.
-      Polymer.dom(element.root).querySelector('gr-diff-host')
-          .click();
-      assert.isTrue(clickSpy.calledTwice);
-      assert.isTrue(toggleExpandSpy.calledOnce);
-      assert.isFalse(reviewStub.called);
-
-      // Click the reviewed checkbox, resulting in a call to _reviewFile, but
-      // no additional call to _togglePathExpanded.
-      row.querySelector('.markReviewed').click();
-      assert.isTrue(clickSpy.calledThrice);
-      assert.isTrue(toggleExpandSpy.calledOnce);
-      assert.isTrue(reviewStub.calledOnce);
-    });
-
-    test('_handleFileListClick editMode', () => {
-      element._filesByPath = {
-        '/COMMIT_MSG': {},
-        'f1.txt': {},
-        'f2.txt': {},
-      };
-      element.changeNum = '42';
-      element.patchRange = {
-        basePatchNum: 'PARENT',
-        patchNum: '2',
-      };
-      element.editMode = true;
-      flushAsynchronousOperations();
-      const clickSpy = sandbox.spy(element, '_handleFileListClick');
-      const toggleExpandSpy = sandbox.spy(element, '_togglePathExpanded');
-
-      // Tap the edit controls. Should be ignored by _handleFileListClick.
-      MockInteractions.tap(element.$$('.editFileControls'));
-      assert.isTrue(clickSpy.calledOnce);
-      assert.isFalse(toggleExpandSpy.called);
-    });
-
-    test('patch set from revisions', () => {
-      const expected = [
-        {num: 4, desc: 'test', sha: 'rev4'},
-        {num: 3, desc: 'test', sha: 'rev3'},
-        {num: 2, desc: 'test', sha: 'rev2'},
-        {num: 1, desc: 'test', sha: 'rev1'},
-      ];
-      const patchNums = element.computeAllPatchSets({
-        revisions: {
-          rev3: {_number: 3, description: 'test', date: 3},
-          rev1: {_number: 1, description: 'test', date: 1},
-          rev4: {_number: 4, description: 'test', date: 4},
-          rev2: {_number: 2, description: 'test', date: 2},
-        },
-      });
-      assert.equal(patchNums.length, expected.length);
-      for (let i = 0; i < expected.length; i++) {
-        assert.deepEqual(patchNums[i], expected[i]);
-      }
-    });
-
-    test('checkbox shows/hides diff inline', () => {
-      element._filesByPath = {
-        'myfile.txt': {},
-      };
-      element.changeNum = '42';
-      element.patchRange = {
-        basePatchNum: 'PARENT',
-        patchNum: '2',
-      };
-      element.$.fileCursor.setCursorAtIndex(0);
-      sandbox.stub(element, '_expandedPathsChanged');
-      flushAsynchronousOperations();
-      const fileRows =
-          Polymer.dom(element.root).querySelectorAll('.row:not(.header-row)');
-      // Because the label surrounds the input, the tap event is triggered
-      // there first.
-      const showHideLabel = fileRows[0].querySelector('label.show-hide');
-      const showHideCheck = fileRows[0].querySelector(
-          'input.show-hide[type="checkbox"]');
-      assert.isNotOk(showHideCheck.checked);
-      MockInteractions.tap(showHideLabel);
-      assert.isOk(showHideCheck.checked);
-      assert.notEqual(element._expandedFilePaths.indexOf('myfile.txt'), -1);
-    });
-
-    test('diff mode correctly toggles the diffs', () => {
-      element._filesByPath = {
-        'myfile.txt': {},
-      };
-      element.changeNum = '42';
-      element.patchRange = {
-        basePatchNum: 'PARENT',
-        patchNum: '2',
-      };
-      sandbox.spy(element, '_updateDiffPreferences');
-      element.$.fileCursor.setCursorAtIndex(0);
-      flushAsynchronousOperations();
-
-      // Tap on a file to generate the diff.
-      const row = Polymer.dom(element.root)
-          .querySelectorAll('.row:not(.header-row) label.show-hide')[0];
-
-      MockInteractions.tap(row);
-      flushAsynchronousOperations();
-      const diffDisplay = element.diffs[0];
-      element._userPrefs = {default_diff_view: 'SIDE_BY_SIDE'};
-      element.set('diffViewMode', 'UNIFIED_DIFF');
-      assert.equal(diffDisplay.viewMode, 'UNIFIED_DIFF');
-      assert.isTrue(element._updateDiffPreferences.called);
-    });
-
-    test('expanded attribute not set on path when not expanded', () => {
-      element._filesByPath = {
-        '/COMMIT_MSG': {},
-      };
-      assert.isNotOk(element.$$('.expanded'));
-    });
-
-    test('tapping row ignores links', () => {
-      element._filesByPath = {
-        '/COMMIT_MSG': {},
-      };
-      element.changeNum = '42';
-      element.patchRange = {
-        basePatchNum: 'PARENT',
-        patchNum: '2',
-      };
-      sandbox.stub(element, '_expandedPathsChanged');
-      flushAsynchronousOperations();
-      const commitMsgFile = Polymer.dom(element.root)
-          .querySelectorAll('.row:not(.header-row) a.pathLink')[0];
-
-      // Remove href attribute so the app doesn't route to a diff view
-      commitMsgFile.removeAttribute('href');
-      const togglePathSpy = sandbox.spy(element, '_togglePathExpanded');
-
-      MockInteractions.tap(commitMsgFile);
-      flushAsynchronousOperations();
-      assert(togglePathSpy.notCalled, 'file is opened as diff view');
-      assert.isNotOk(element.$$('.expanded'));
-      assert.notEqual(getComputedStyle(element.$$('.show-hide')).display,
-          'none');
-    });
-
-    test('_togglePathExpanded', () => {
-      const path = 'path/to/my/file.txt';
-      element._filesByPath = {[path]: {}};
-      const renderSpy = sandbox.spy(element, '_renderInOrder');
-      const collapseStub = sandbox.stub(element, '_clearCollapsedDiffs');
-
-      assert.equal(element.$$('iron-icon').icon, 'gr-icons:expand-more');
-      assert.equal(element._expandedFilePaths.length, 0);
-      element._togglePathExpanded(path);
-      flushAsynchronousOperations();
-      assert.equal(collapseStub.lastCall.args[0].length, 0);
-      assert.equal(element.$$('iron-icon').icon, 'gr-icons:expand-less');
-
-      assert.equal(renderSpy.callCount, 1);
-      assert.include(element._expandedFilePaths, path);
-      element._togglePathExpanded(path);
-      flushAsynchronousOperations();
-
-      assert.equal(element.$$('iron-icon').icon, 'gr-icons:expand-more');
-      assert.equal(renderSpy.callCount, 1);
-      assert.notInclude(element._expandedFilePaths, path);
-      assert.equal(collapseStub.lastCall.args[0].length, 1);
-    });
-
-    test('expandAllDiffs and collapseAllDiffs', () => {
-      const collapseStub = sandbox.stub(element, '_clearCollapsedDiffs');
-      const cursorUpdateStub = sandbox.stub(element.$.diffCursor,
-          'handleDiffUpdate');
-
-      const path = 'path/to/my/file.txt';
-      element._filesByPath = {[path]: {}};
-      element.expandAllDiffs();
-      flushAsynchronousOperations();
-      assert.isTrue(element._showInlineDiffs);
-      assert.isTrue(cursorUpdateStub.calledOnce);
-      assert.equal(collapseStub.lastCall.args[0].length, 0);
-
-      element.collapseAllDiffs();
-      flushAsynchronousOperations();
-      assert.equal(element._expandedFilePaths.length, 0);
-      assert.isFalse(element._showInlineDiffs);
-      assert.isTrue(cursorUpdateStub.calledTwice);
-      assert.equal(collapseStub.lastCall.args[0].length, 1);
-    });
-
-    test('_expandedPathsChanged', done => {
-      sandbox.stub(element, '_reviewFile');
-      const path = 'path/to/my/file.txt';
-      const diffs = [{
-        path,
-        reload() {
-          done();
-        },
-        cancel() {},
-        getCursorStops() { return []; },
-        addEventListener(eventName, callback) { callback(new Event(eventName)); },
-      }];
-      sinon.stub(element, 'diffs', {
-        get() { return diffs; },
-      });
-      element.push('_expandedFilePaths', path);
-    });
-
-    test('_clearCollapsedDiffs', () => {
-      const diff = {
-        cancel: sinon.stub(),
-        clearDiffContent: sinon.stub(),
-      };
-      element._clearCollapsedDiffs([diff]);
-      assert.isTrue(diff.cancel.calledOnce);
-      assert.isTrue(diff.clearDiffContent.calledOnce);
-    });
-
-    test('filesExpanded value updates to correct enum', () => {
-      element._filesByPath = {
-        'foo.bar': {},
-        'baz.bar': {},
-      };
-      flushAsynchronousOperations();
-      assert.equal(element.filesExpanded,
-          GrFileListConstants.FilesExpandedState.NONE);
-      element.push('_expandedFilePaths', 'baz.bar');
-      flushAsynchronousOperations();
-      assert.equal(element.filesExpanded,
-          GrFileListConstants.FilesExpandedState.SOME);
-      element.push('_expandedFilePaths', 'foo.bar');
-      flushAsynchronousOperations();
-      assert.equal(element.filesExpanded,
-          GrFileListConstants.FilesExpandedState.ALL);
-      element.collapseAllDiffs();
-      flushAsynchronousOperations();
-      assert.equal(element.filesExpanded,
-          GrFileListConstants.FilesExpandedState.NONE);
-      element.expandAllDiffs();
-      flushAsynchronousOperations();
-      assert.equal(element.filesExpanded,
-          GrFileListConstants.FilesExpandedState.ALL);
-    });
-
-    test('_renderInOrder', done => {
-      const reviewStub = sandbox.stub(element, '_reviewFile');
-      let callCount = 0;
-      const diffs = [{
-        path: 'p0',
-        reload() {
-          assert.equal(callCount++, 2);
-          return Promise.resolve();
-        },
-      }, {
-        path: 'p1',
-        reload() {
-          assert.equal(callCount++, 1);
-          return Promise.resolve();
-        },
-      }, {
-        path: 'p2',
-        reload() {
-          assert.equal(callCount++, 0);
-          return Promise.resolve();
-        },
-      }];
-      element._renderInOrder(['p2', 'p1', 'p0'], diffs, 3)
-          .then(() => {
-            assert.isFalse(reviewStub.called);
-            assert.isTrue(loadCommentSpy.called);
+      test('_expandedPathsChanged', done => {
+        sandbox.stub(element, '_reviewFile');
+        const path = 'path/to/my/file.txt';
+        const diffs = [{
+          path,
+          reload() {
             done();
-          });
-    });
+          },
+          cancel() {},
+          getCursorStops() { return []; },
+          addEventListener(eventName, callback) {
+            callback(new Event(eventName));
+          },
+        }];
+        sinon.stub(element, 'diffs', {
+          get() { return diffs; },
+        });
+        element.push('_expandedFilePaths', path);
+      });
 
-    test('_renderInOrder logged in', done => {
-      element._loggedIn = true;
-      const reviewStub = sandbox.stub(element, '_reviewFile');
-      let callCount = 0;
-      const diffs = [{
-        path: 'p0',
-        reload() {
-          assert.equal(reviewStub.callCount, 2);
-          assert.equal(callCount++, 2);
-          return Promise.resolve();
-        },
-      }, {
-        path: 'p1',
-        reload() {
-          assert.equal(reviewStub.callCount, 1);
-          assert.equal(callCount++, 1);
-          return Promise.resolve();
-        },
-      }, {
-        path: 'p2',
-        reload() {
-          assert.equal(reviewStub.callCount, 0);
-          assert.equal(callCount++, 0);
-          return Promise.resolve();
-        },
-      }];
-      element._renderInOrder(['p2', 'p1', 'p0'], diffs, 3)
-          .then(() => {
-            assert.equal(reviewStub.callCount, 3);
-            done();
-          });
-    });
+      test('_clearCollapsedDiffs', () => {
+        const diff = {
+          cancel: sinon.stub(),
+          clearDiffContent: sinon.stub(),
+        };
+        element._clearCollapsedDiffs([diff]);
+        assert.isTrue(diff.cancel.calledOnce);
+        assert.isTrue(diff.clearDiffContent.calledOnce);
+      });
 
-    test('_renderInOrder respects diffPrefs.manual_review', () => {
-      element._loggedIn = true;
-      element.diffPrefs = {manual_review: true};
-      const reviewStub = sandbox.stub(element, '_reviewFile');
-      const diffs = [{
-        path: 'p',
-        reload() { return Promise.resolve(); },
-      }];
+      test('filesExpanded value updates to correct enum', () => {
+        element._filesByPath = {
+          'foo.bar': {},
+          'baz.bar': {},
+        };
+        flushAsynchronousOperations();
+        assert.equal(element.filesExpanded,
+            GrFileListConstants.FilesExpandedState.NONE);
+        element.push('_expandedFilePaths', 'baz.bar');
+        flushAsynchronousOperations();
+        assert.equal(element.filesExpanded,
+            GrFileListConstants.FilesExpandedState.SOME);
+        element.push('_expandedFilePaths', 'foo.bar');
+        flushAsynchronousOperations();
+        assert.equal(element.filesExpanded,
+            GrFileListConstants.FilesExpandedState.ALL);
+        element.collapseAllDiffs();
+        flushAsynchronousOperations();
+        assert.equal(element.filesExpanded,
+            GrFileListConstants.FilesExpandedState.NONE);
+        element.expandAllDiffs();
+        flushAsynchronousOperations();
+        assert.equal(element.filesExpanded,
+            GrFileListConstants.FilesExpandedState.ALL);
+      });
 
-      return element._renderInOrder(['p'], diffs, 1).then(() => {
-        assert.isFalse(reviewStub.called);
-        delete element.diffPrefs.manual_review;
+      test('_renderInOrder', done => {
+        const reviewStub = sandbox.stub(element, '_reviewFile');
+        let callCount = 0;
+        const diffs = [{
+          path: 'p0',
+          reload() {
+            assert.equal(callCount++, 2);
+            return Promise.resolve();
+          },
+        }, {
+          path: 'p1',
+          reload() {
+            assert.equal(callCount++, 1);
+            return Promise.resolve();
+          },
+        }, {
+          path: 'p2',
+          reload() {
+            assert.equal(callCount++, 0);
+            return Promise.resolve();
+          },
+        }];
+        element._renderInOrder(['p2', 'p1', 'p0'], diffs, 3)
+            .then(() => {
+              assert.isFalse(reviewStub.called);
+              assert.isTrue(loadCommentSpy.called);
+              done();
+            });
+      });
+
+      test('_renderInOrder logged in', done => {
+        element._loggedIn = true;
+        const reviewStub = sandbox.stub(element, '_reviewFile');
+        let callCount = 0;
+        const diffs = [{
+          path: 'p0',
+          reload() {
+            assert.equal(reviewStub.callCount, 2);
+            assert.equal(callCount++, 2);
+            return Promise.resolve();
+          },
+        }, {
+          path: 'p1',
+          reload() {
+            assert.equal(reviewStub.callCount, 1);
+            assert.equal(callCount++, 1);
+            return Promise.resolve();
+          },
+        }, {
+          path: 'p2',
+          reload() {
+            assert.equal(reviewStub.callCount, 0);
+            assert.equal(callCount++, 0);
+            return Promise.resolve();
+          },
+        }];
+        element._renderInOrder(['p2', 'p1', 'p0'], diffs, 3)
+            .then(() => {
+              assert.equal(reviewStub.callCount, 3);
+              done();
+            });
+      });
+
+      test('_renderInOrder respects diffPrefs.manual_review', () => {
+        element._loggedIn = true;
+        element.diffPrefs = {manual_review: true};
+        const reviewStub = sandbox.stub(element, '_reviewFile');
+        const diffs = [{
+          path: 'p',
+          reload() { return Promise.resolve(); },
+        }];
+
         return element._renderInOrder(['p'], diffs, 1).then(() => {
-          assert.isTrue(reviewStub.called);
-          assert.isTrue(reviewStub.calledWithExactly('p', true));
+          assert.isFalse(reviewStub.called);
+          delete element.diffPrefs.manual_review;
+          return element._renderInOrder(['p'], diffs, 1).then(() => {
+            assert.isTrue(reviewStub.called);
+            assert.isTrue(reviewStub.calledWithExactly('p', true));
+          });
         });
       });
-    });
 
-    test('_loadingChanged fired from reload in debouncer', done => {
-      sandbox.stub(element, '_getReviewedFiles').returns(Promise.resolve([]));
-      element.changeNum = 123;
-      element.patchRange = {patchNum: 12};
-      element._filesByPath = {'foo.bar': {}};
+      test('_loadingChanged fired from reload in debouncer', done => {
+        sandbox.stub(element, '_getReviewedFiles').returns(Promise.resolve([]));
+        element.changeNum = 123;
+        element.patchRange = {patchNum: 12};
+        element._filesByPath = {'foo.bar': {}};
 
-      element.reload().then(() => {
-        assert.isFalse(element._loading);
+        element.reload().then(() => {
+          assert.isFalse(element._loading);
+          element.flushDebouncer('loading-change');
+          assert.isFalse(element.classList.contains('loading'));
+          done();
+        });
+        assert.isTrue(element._loading);
+        assert.isFalse(element.classList.contains('loading'));
+        element.flushDebouncer('loading-change');
+        assert.isTrue(element.classList.contains('loading'));
+      });
+
+      test('_loadingChanged does not set class when there are no files', () => {
+        sandbox.stub(element, '_getReviewedFiles').returns(Promise.resolve([]));
+        element.changeNum = 123;
+        element.patchRange = {patchNum: 12};
+        element.reload();
+        assert.isTrue(element._loading);
         element.flushDebouncer('loading-change');
         assert.isFalse(element.classList.contains('loading'));
-        done();
       });
-      assert.isTrue(element._loading);
-      assert.isFalse(element.classList.contains('loading'));
-      element.flushDebouncer('loading-change');
-      assert.isTrue(element.classList.contains('loading'));
-    });
-
-    test('_loadingChanged does not set class when there are no files', () => {
-      sandbox.stub(element, '_getReviewedFiles').returns(Promise.resolve([]));
-      element.changeNum = 123;
-      element.patchRange = {patchNum: 12};
-      element.reload();
-      assert.isTrue(element._loading);
-      element.flushDebouncer('loading-change');
-      assert.isFalse(element.classList.contains('loading'));
     });
 
     suite('size bars', () => {
@@ -1340,408 +1363,12 @@
             'sizeBars desktop ');
       });
     });
-  });
 
-  suite('gr-file-list inline diff tests', () => {
-    let element;
-    let sandbox;
+    suite('gr-file-list inline diff tests', () => {
+      let element;
+      let sandbox;
 
-    const commitMsgComments = [
-      {
-        patch_set: 2,
-        id: 'ecf0b9fa_fe1a5f62',
-        line: 20,
-        updated: '2018-02-08 18:49:18.000000000',
-        message: 'another comment',
-        unresolved: true,
-      },
-      {
-        patch_set: 2,
-        id: '503008e2_0ab203ee',
-        line: 10,
-        updated: '2018-02-14 22:07:43.000000000',
-        message: 'a comment',
-        unresolved: true,
-      },
-      {
-        patch_set: 2,
-        id: 'cc788d2c_cb1d728c',
-        line: 20,
-        in_reply_to: 'ecf0b9fa_fe1a5f62',
-        updated: '2018-02-13 22:07:43.000000000',
-        message: 'response',
-        unresolved: true,
-      },
-    ];
-
-    const setupDiff = function(diff) {
-      const mock = document.createElement('mock-diff-response');
-      diff.comments = {
-        left: diff.path === '/COMMIT_MSG' ? commitMsgComments : [],
-        right: [],
-        meta: {
-          changeNum: 1,
-          patchRange: {
-            basePatchNum: 'PARENT',
-            patchNum: 2,
-          },
-        },
-      };
-      diff.prefs = {
-        context: 10,
-        tab_size: 8,
-        font_size: 12,
-        line_length: 100,
-        cursor_blink_rate: 0,
-        line_wrapping: false,
-        intraline_difference: true,
-        show_line_endings: true,
-        show_tabs: true,
-        show_whitespace_errors: true,
-        syntax_highlighting: true,
-        auto_hide_diff_table_header: true,
-        theme: 'DEFAULT',
-        ignore_whitespace: 'IGNORE_NONE',
-      };
-      diff.diff = mock.diffResponse;
-      diff.$.diff.flushDebouncer('renderDiffTable');
-    };
-
-    const renderAndGetNewDiffs = function(index) {
-      const diffs =
-          Polymer.dom(element.root).querySelectorAll('gr-diff-host');
-
-      for (let i = index; i < diffs.length; i++) {
-        setupDiff(diffs[i]);
-      }
-
-      element._updateDiffCursor();
-      element.$.diffCursor.handleDiffUpdate();
-      return diffs;
-    };
-
-    setup(done => {
-      sandbox = sinon.sandbox.create();
-      stub('gr-rest-api-interface', {
-        getLoggedIn() { return Promise.resolve(true); },
-        getPreferences() { return Promise.resolve({}); },
-        getDiffComments() { return Promise.resolve({}); },
-        getDiffRobotComments() { return Promise.resolve({}); },
-        getDiffDrafts() { return Promise.resolve({}); },
-      });
-      stub('gr-date-formatter', {
-        _loadTimeFormat() { return Promise.resolve(''); },
-      });
-      stub('gr-diff-host', {
-        reload() { return Promise.resolve(); },
-      });
-
-      // Element must be wrapped in an element with direct access to the
-      // comment API.
-      commentApiWrapper = fixture('basic');
-      element = commentApiWrapper.$.fileList;
-      loadCommentSpy = sandbox.spy(commentApiWrapper.$.commentAPI, 'loadAll');
-      element.diffPrefs = {};
-      sandbox.stub(element, '_reviewFile');
-
-      // Stub methods on the changeComments object after changeComments has
-      // been initialized.
-      commentApiWrapper.loadComments().then(() => {
-        sandbox.stub(element.changeComments, 'getPaths').returns({});
-        sandbox.stub(element.changeComments, 'getCommentsBySideForPath')
-            .returns({meta: {}, left: [], right: []});
-        done();
-      });
-      element._loading = false;
-      element.numFilesShown = 75;
-      element.selectedIndex = 0;
-      element._filesByPath = {
-        '/COMMIT_MSG': {lines_inserted: 9},
-        'file_added_in_rev2.txt': {
-          lines_inserted: 1,
-          lines_deleted: 1,
-          size_delta: 10,
-          size: 100,
-        },
-        'myfile.txt': {
-          lines_inserted: 1,
-          lines_deleted: 1,
-          size_delta: 10,
-          size: 100,
-        },
-      };
-      element._reviewed = ['/COMMIT_MSG', 'myfile.txt'];
-      element._loggedIn = true;
-      element.changeNum = '42';
-      element.patchRange = {
-        basePatchNum: 'PARENT',
-        patchNum: '2',
-      };
-      sandbox.stub(window, 'fetch', () => Promise.resolve());
-      flushAsynchronousOperations();
-    });
-
-    teardown(() => {
-      sandbox.restore();
-    });
-
-    test('cursor with individually opened files', () => {
-      MockInteractions.keyUpOn(element, 73, null, 'i');
-      flushAsynchronousOperations();
-      let diffs = renderAndGetNewDiffs(0);
-      const diffStops = diffs[0].getCursorStops();
-
-      // 1 diff should be rendered.
-      assert.equal(diffs.length, 1);
-
-      // No line number is selected.
-      assert.isFalse(diffStops[10].classList.contains('target-row'));
-
-      // Tapping content on a line selects the line number.
-      MockInteractions.tap(Polymer.dom(
-          diffStops[10]).querySelectorAll('.contentText')[0]);
-      flushAsynchronousOperations();
-      assert.isTrue(diffStops[10].classList.contains('target-row'));
-
-      // Keyboard shortcuts are still moving the file cursor, not the diff
-      // cursor.
-      MockInteractions.pressAndReleaseKeyOn(element, 74, null, 'j');
-      flushAsynchronousOperations();
-      assert.isTrue(diffStops[10].classList.contains('target-row'));
-      assert.isFalse(diffStops[11].classList.contains('target-row'));
-
-      // The file cusor is now at 1.
-      assert.equal(element.$.fileCursor.index, 1);
-      MockInteractions.keyUpOn(element, 73, null, 'i');
-      flushAsynchronousOperations();
-
-      diffs = renderAndGetNewDiffs(1);
-      // Two diffs should be rendered.
-      assert.equal(diffs.length, 2);
-      const diffStopsFirst = diffs[0].getCursorStops();
-      const diffStopsSecond = diffs[1].getCursorStops();
-
-      // The line on the first diff is stil selected
-      assert.isTrue(diffStopsFirst[10].classList.contains('target-row'));
-      assert.isFalse(diffStopsSecond[10].classList.contains('target-row'));
-    });
-
-    test('cursor with toggle all files', () => {
-      MockInteractions.keyUpOn(element, 73, 'shift', 'i');
-      flushAsynchronousOperations();
-
-      const diffs = renderAndGetNewDiffs(0);
-      const diffStops = diffs[0].getCursorStops();
-
-      // 1 diff should be rendered.
-      assert.equal(diffs.length, 3);
-
-      // No line number is selected.
-      assert.isFalse(diffStops[10].classList.contains('target-row'));
-
-      // Tapping content on a line selects the line number.
-      MockInteractions.tap(Polymer.dom(
-          diffStops[10]).querySelectorAll('.contentText')[0]);
-      flushAsynchronousOperations();
-      assert.isTrue(diffStops[10].classList.contains('target-row'));
-
-      // Keyboard shortcuts are still moving the file cursor, not the diff
-      // cursor.
-      MockInteractions.pressAndReleaseKeyOn(element, 74, null, 'j');
-      flushAsynchronousOperations();
-      assert.isFalse(diffStops[10].classList.contains('target-row'));
-      assert.isTrue(diffStops[11].classList.contains('target-row'));
-
-      // The file cusor is still at 0.
-      assert.equal(element.$.fileCursor.index, 0);
-    });
-
-    suite('n key presses', () => {
-      let nKeySpy;
-      let nextCommentStub;
-      let nextChunkStub;
-      let fileRows;
-
-      setup(() => {
-        sandbox.stub(element, '_renderInOrder').returns(Promise.resolve());
-        nKeySpy = sandbox.spy(element, '_handleNextChunk');
-        nextCommentStub = sandbox.stub(element.$.diffCursor,
-            'moveToNextCommentThread');
-        nextChunkStub = sandbox.stub(element.$.diffCursor,
-            'moveToNextChunk');
-        fileRows =
-            Polymer.dom(element.root).querySelectorAll('.row:not(.header-row)');
-      });
-
-      test('n key with some files expanded and no shift key', () => {
-        MockInteractions.keyUpOn(fileRows[0], 73, null, 'i');
-        flushAsynchronousOperations();
-        assert.equal(nextChunkStub.callCount, 1);
-
-        // Handle N key should return before calling diff cursor functions.
-        MockInteractions.pressAndReleaseKeyOn(element, 78, null, 'n');
-        assert.isTrue(nKeySpy.called);
-        assert.isFalse(nextCommentStub.called);
-
-        // This is also called in diffCursor.moveToFirstChunk.
-        assert.equal(nextChunkStub.callCount, 2);
-        assert.equal(element.filesExpanded, 'some');
-      });
-
-      test('n key with some files expanded and shift key', () => {
-        MockInteractions.keyUpOn(fileRows[0], 73, null, 'i');
-        flushAsynchronousOperations();
-        assert.equal(nextChunkStub.callCount, 1);
-
-        MockInteractions.pressAndReleaseKeyOn(element, 78, 'shift', 'n');
-        assert.isTrue(nKeySpy.called);
-        assert.isTrue(nextCommentStub.called);
-
-        // This is also called in diffCursor.moveToFirstChunk.
-        assert.equal(nextChunkStub.callCount, 1);
-        assert.equal(element.filesExpanded, 'some');
-      });
-
-      test('n key without all files expanded and shift key', () => {
-        MockInteractions.keyUpOn(fileRows[0], 73, 'shift', 'i');
-        flushAsynchronousOperations();
-
-        MockInteractions.pressAndReleaseKeyOn(element, 78, null, 'n');
-        assert.isTrue(nKeySpy.called);
-        assert.isFalse(nextCommentStub.called);
-
-        // This is also called in diffCursor.moveToFirstChunk.
-        assert.equal(nextChunkStub.callCount, 2);
-        assert.isTrue(element._showInlineDiffs);
-      });
-
-      test('n key without all files expanded and no shift key', () => {
-        MockInteractions.keyUpOn(fileRows[0], 73, 'shift', 'i');
-        flushAsynchronousOperations();
-
-        MockInteractions.pressAndReleaseKeyOn(element, 78, 'shift', 'n');
-        assert.isTrue(nKeySpy.called);
-        assert.isTrue(nextCommentStub.called);
-
-        // This is also called in diffCursor.moveToFirstChunk.
-        assert.equal(nextChunkStub.callCount, 1);
-        assert.isTrue(element._showInlineDiffs);
-      });
-    });
-
-    test('_openSelectedFile behavior', () => {
-      const _filesByPath = element._filesByPath;
-      element.set('_filesByPath', {});
-      const navStub = sandbox.stub(Gerrit.Nav, 'navigateToDiff');
-      // Noop when there are no files.
-      element._openSelectedFile();
-      assert.isFalse(navStub.called);
-
-      element.set('_filesByPath', _filesByPath);
-      flushAsynchronousOperations();
-      // Navigates when a file is selected.
-      element._openSelectedFile();
-      assert.isTrue(navStub.called);
-    });
-
-    test('_displayLine', () => {
-      sandbox.stub(element, 'shouldSuppressKeyboardShortcut', () => false);
-      sandbox.stub(element, 'modifierPressed', () => false);
-      element._showInlineDiffs = true;
-      const mockEvent = {preventDefault() {}};
-
-      element._displayLine = false;
-      element._handleCursorNext(mockEvent);
-      assert.isTrue(element._displayLine);
-
-      element._displayLine = false;
-      element._handleCursorPrev(mockEvent);
-      assert.isTrue(element._displayLine);
-
-      element._displayLine = true;
-      element._handleEscKey(mockEvent);
-      assert.isFalse(element._displayLine);
-    });
-
-    suite('editMode behavior', () => {
-      test('reviewed checkbox', () => {
-        element._reviewFile.restore();
-        const saveReviewStub = sandbox.stub(element, '_saveReviewedState');
-
-        element.editMode = false;
-        MockInteractions.pressAndReleaseKeyOn(element, 82, null, 'r');
-        assert.isTrue(saveReviewStub.calledOnce);
-
-        element.editMode = true;
-        flushAsynchronousOperations();
-
-        MockInteractions.pressAndReleaseKeyOn(element, 82, null, 'r');
-        assert.isTrue(saveReviewStub.calledOnce);
-      });
-
-      test('_getReviewedFiles does not call API', () => {
-        const apiSpy = sandbox.spy(element.$.restAPI, 'getReviewedFiles');
-        element.editMode = true;
-        return element._getReviewedFiles().then(files => {
-          assert.equal(files.length, 0);
-          assert.isFalse(apiSpy.called);
-        });
-      });
-    });
-
-    test('editing actions', () => {
-      // Edit controls are guarded behind a dom-if initially and not rendered.
-      assert.isNotOk(Polymer.dom(element.root)
-          .querySelector('gr-edit-file-controls'));
-
-      element.editMode = true;
-      flushAsynchronousOperations();
-
-      // Commit message should not have edit controls.
-      const editControls =
-          Array.from(
-              Polymer.dom(element.root)
-                  .querySelectorAll('.row:not(.header-row)'))
-              .map(row => row.querySelector('gr-edit-file-controls'));
-      assert.isTrue(editControls[0].classList.contains('invisible'));
-    });
-
-    test('reloadCommentsForThreadWithRootId', () => {
-      // Expand the commit message diff
-      MockInteractions.keyUpOn(element, 73, 'shift', 'i');
-      const diffs = renderAndGetNewDiffs(0);
-      flushAsynchronousOperations();
-
-      // Two comment threads should be generated by renderAndGetNewDiffs
-      const threadEls = diffs[0].getThreadEls();
-      assert.equal(threadEls.length, 2);
-      const threadElsByRootId = new Map(
-          threadEls.map(threadEl => [threadEl.rootId, threadEl]));
-
-      const thread1 = threadElsByRootId.get('503008e2_0ab203ee');
-      assert.equal(thread1.comments.length, 1);
-      assert.equal(thread1.comments[0].message, 'a comment');
-      assert.equal(thread1.comments[0].line, 10);
-
-      const thread2 = threadElsByRootId.get('ecf0b9fa_fe1a5f62');
-      assert.equal(thread2.comments.length, 2);
-      assert.isTrue(thread2.comments[0].unresolved);
-      assert.equal(thread2.comments[0].message, 'another comment');
-      assert.equal(thread2.comments[0].line, 20);
-
-      const commentStub =
-          sandbox.stub(element.changeComments, 'getCommentsForThread');
-      const commentStubRes1 = [
-        {
-          patch_set: 2,
-          id: '503008e2_0ab203ee',
-          line: 20,
-          updated: '2018-02-08 18:49:18.000000000',
-          message: 'edited text',
-          unresolved: false,
-        },
-      ];
-      const commentStubRes2 = [
+      const commitMsgComments = [
         {
           patch_set: 2,
           id: 'ecf0b9fa_fe1a5f62',
@@ -1754,57 +1381,453 @@
           patch_set: 2,
           id: '503008e2_0ab203ee',
           line: 10,
-          in_reply_to: 'ecf0b9fa_fe1a5f62',
           updated: '2018-02-14 22:07:43.000000000',
-          message: 'response',
+          message: 'a comment',
           unresolved: true,
         },
         {
           patch_set: 2,
-          id: '503008e2_0ab203ef',
+          id: 'cc788d2c_cb1d728c',
           line: 20,
-          in_reply_to: '503008e2_0ab203ee',
-          updated: '2018-02-15 22:07:43.000000000',
-          message: 'a third comment in the thread',
+          in_reply_to: 'ecf0b9fa_fe1a5f62',
+          updated: '2018-02-13 22:07:43.000000000',
+          message: 'response',
           unresolved: true,
         },
       ];
-      commentStub.withArgs('503008e2_0ab203ee').returns(
-          commentStubRes1);
-      commentStub.withArgs('ecf0b9fa_fe1a5f62').returns(
-          commentStubRes2);
 
-      // Reload comments from the first comment thread, which should have a
-      // an updated message and a toggled resolve state.
-      element.reloadCommentsForThreadWithRootId('503008e2_0ab203ee',
-          '/COMMIT_MSG');
-      assert.equal(thread1.comments.length, 1);
-      assert.isFalse(thread1.comments[0].unresolved);
-      assert.equal(thread1.comments[0].message, 'edited text');
+      const setupDiff = function(diff) {
+        const mock = document.createElement('mock-diff-response');
+        diff.comments = {
+          left: diff.path === '/COMMIT_MSG' ? commitMsgComments : [],
+          right: [],
+          meta: {
+            changeNum: 1,
+            patchRange: {
+              basePatchNum: 'PARENT',
+              patchNum: 2,
+            },
+          },
+        };
+        diff.prefs = {
+          context: 10,
+          tab_size: 8,
+          font_size: 12,
+          line_length: 100,
+          cursor_blink_rate: 0,
+          line_wrapping: false,
+          intraline_difference: true,
+          show_line_endings: true,
+          show_tabs: true,
+          show_whitespace_errors: true,
+          syntax_highlighting: true,
+          auto_hide_diff_table_header: true,
+          theme: 'DEFAULT',
+          ignore_whitespace: 'IGNORE_NONE',
+        };
+        diff.diff = mock.diffResponse;
+        diff.$.diff.flushDebouncer('renderDiffTable');
+      };
 
-      // Reload comments from the second comment thread, which should have a new
-      // reply.
-      element.reloadCommentsForThreadWithRootId('ecf0b9fa_fe1a5f62',
-          '/COMMIT_MSG');
-      assert.equal(thread2.comments.length, 3);
+      const renderAndGetNewDiffs = function(index) {
+        const diffs =
+            Polymer.dom(element.root).querySelectorAll('gr-diff-host');
 
-      const commentStubCount = commentStub.callCount;
-      const getThreadsSpy = sandbox.spy(diffs[0], 'getThreadEls');
+        for (let i = index; i < diffs.length; i++) {
+          setupDiff(diffs[i]);
+        }
 
-      // Should not be getting threads when the file is not expanded.
-      element.reloadCommentsForThreadWithRootId('ecf0b9fa_fe1a5f62',
-          'other/file');
-      assert.isFalse(getThreadsSpy.called);
-      assert.equal(commentStubCount, commentStub.callCount);
+        element._updateDiffCursor();
+        element.$.diffCursor.handleDiffUpdate();
+        return diffs;
+      };
 
-      // Should be query selecting diffs when the file is expanded.
-      // Should not be fetching change comments when the rootId is not found
-      // to match.
-      element.reloadCommentsForThreadWithRootId('acf0b9fa_fe1a5f62',
-          '/COMMIT_MSG');
-      assert.isTrue(getThreadsSpy.called);
-      assert.equal(commentStubCount, commentStub.callCount);
+      setup(done => {
+        sandbox = sinon.sandbox.create();
+        stub('gr-rest-api-interface', {
+          getLoggedIn() { return Promise.resolve(true); },
+          getPreferences() { return Promise.resolve({}); },
+          getDiffComments() { return Promise.resolve({}); },
+          getDiffRobotComments() { return Promise.resolve({}); },
+          getDiffDrafts() { return Promise.resolve({}); },
+        });
+        stub('gr-date-formatter', {
+          _loadTimeFormat() { return Promise.resolve(''); },
+        });
+        stub('gr-diff-host', {
+          reload() { return Promise.resolve(); },
+        });
+
+        // Element must be wrapped in an element with direct access to the
+        // comment API.
+        commentApiWrapper = fixture('basic');
+        element = commentApiWrapper.$.fileList;
+        loadCommentSpy = sandbox.spy(commentApiWrapper.$.commentAPI, 'loadAll');
+        element.diffPrefs = {};
+        sandbox.stub(element, '_reviewFile');
+
+        // Stub methods on the changeComments object after changeComments has
+        // been initialized.
+        commentApiWrapper.loadComments().then(() => {
+          sandbox.stub(element.changeComments, 'getPaths').returns({});
+          sandbox.stub(element.changeComments, 'getCommentsBySideForPath')
+              .returns({meta: {}, left: [], right: []});
+          done();
+        });
+        element._loading = false;
+        element.numFilesShown = 75;
+        element.selectedIndex = 0;
+        element._filesByPath = {
+          '/COMMIT_MSG': {lines_inserted: 9},
+          'file_added_in_rev2.txt': {
+            lines_inserted: 1,
+            lines_deleted: 1,
+            size_delta: 10,
+            size: 100,
+          },
+          'myfile.txt': {
+            lines_inserted: 1,
+            lines_deleted: 1,
+            size_delta: 10,
+            size: 100,
+          },
+        };
+        element._reviewed = ['/COMMIT_MSG', 'myfile.txt'];
+        element._loggedIn = true;
+        element.changeNum = '42';
+        element.patchRange = {
+          basePatchNum: 'PARENT',
+          patchNum: '2',
+        };
+        sandbox.stub(window, 'fetch', () => Promise.resolve());
+        flushAsynchronousOperations();
+      });
+
+      teardown(() => {
+        sandbox.restore();
+      });
+
+      test('cursor with individually opened files', () => {
+        MockInteractions.keyUpOn(element, 73, null, 'i');
+        flushAsynchronousOperations();
+        let diffs = renderAndGetNewDiffs(0);
+        const diffStops = diffs[0].getCursorStops();
+
+        // 1 diff should be rendered.
+        assert.equal(diffs.length, 1);
+
+        // No line number is selected.
+        assert.isFalse(diffStops[10].classList.contains('target-row'));
+
+        // Tapping content on a line selects the line number.
+        MockInteractions.tap(Polymer.dom(
+            diffStops[10]).querySelectorAll('.contentText')[0]);
+        flushAsynchronousOperations();
+        assert.isTrue(diffStops[10].classList.contains('target-row'));
+
+        // Keyboard shortcuts are still moving the file cursor, not the diff
+        // cursor.
+        MockInteractions.pressAndReleaseKeyOn(element, 74, null, 'j');
+        flushAsynchronousOperations();
+        assert.isTrue(diffStops[10].classList.contains('target-row'));
+        assert.isFalse(diffStops[11].classList.contains('target-row'));
+
+        // The file cusor is now at 1.
+        assert.equal(element.$.fileCursor.index, 1);
+        MockInteractions.keyUpOn(element, 73, null, 'i');
+        flushAsynchronousOperations();
+
+        diffs = renderAndGetNewDiffs(1);
+        // Two diffs should be rendered.
+        assert.equal(diffs.length, 2);
+        const diffStopsFirst = diffs[0].getCursorStops();
+        const diffStopsSecond = diffs[1].getCursorStops();
+
+        // The line on the first diff is stil selected
+        assert.isTrue(diffStopsFirst[10].classList.contains('target-row'));
+        assert.isFalse(diffStopsSecond[10].classList.contains('target-row'));
+      });
+
+      test('cursor with toggle all files', () => {
+        MockInteractions.keyUpOn(element, 73, 'shift', 'i');
+        flushAsynchronousOperations();
+
+        const diffs = renderAndGetNewDiffs(0);
+        const diffStops = diffs[0].getCursorStops();
+
+        // 1 diff should be rendered.
+        assert.equal(diffs.length, 3);
+
+        // No line number is selected.
+        assert.isFalse(diffStops[10].classList.contains('target-row'));
+
+        // Tapping content on a line selects the line number.
+        MockInteractions.tap(Polymer.dom(
+            diffStops[10]).querySelectorAll('.contentText')[0]);
+        flushAsynchronousOperations();
+        assert.isTrue(diffStops[10].classList.contains('target-row'));
+
+        // Keyboard shortcuts are still moving the file cursor, not the diff
+        // cursor.
+        MockInteractions.pressAndReleaseKeyOn(element, 74, null, 'j');
+        flushAsynchronousOperations();
+        assert.isFalse(diffStops[10].classList.contains('target-row'));
+        assert.isTrue(diffStops[11].classList.contains('target-row'));
+
+        // The file cusor is still at 0.
+        assert.equal(element.$.fileCursor.index, 0);
+      });
+
+      suite('n key presses', () => {
+        let nKeySpy;
+        let nextCommentStub;
+        let nextChunkStub;
+        let fileRows;
+
+        setup(() => {
+          sandbox.stub(element, '_renderInOrder').returns(Promise.resolve());
+          nKeySpy = sandbox.spy(element, '_handleNextChunk');
+          nextCommentStub = sandbox.stub(element.$.diffCursor,
+              'moveToNextCommentThread');
+          nextChunkStub = sandbox.stub(element.$.diffCursor,
+              'moveToNextChunk');
+          fileRows =
+              Polymer.dom(element.root).querySelectorAll('.row:not(.header-row)');
+        });
+
+        test('n key with some files expanded and no shift key', () => {
+          MockInteractions.keyUpOn(fileRows[0], 73, null, 'i');
+          flushAsynchronousOperations();
+          assert.equal(nextChunkStub.callCount, 1);
+
+          // Handle N key should return before calling diff cursor functions.
+          MockInteractions.pressAndReleaseKeyOn(element, 78, null, 'n');
+          assert.isTrue(nKeySpy.called);
+          assert.isFalse(nextCommentStub.called);
+
+          // This is also called in diffCursor.moveToFirstChunk.
+          assert.equal(nextChunkStub.callCount, 2);
+          assert.equal(element.filesExpanded, 'some');
+        });
+
+        test('n key with some files expanded and shift key', () => {
+          MockInteractions.keyUpOn(fileRows[0], 73, null, 'i');
+          flushAsynchronousOperations();
+          assert.equal(nextChunkStub.callCount, 1);
+
+          MockInteractions.pressAndReleaseKeyOn(element, 78, 'shift', 'n');
+          assert.isTrue(nKeySpy.called);
+          assert.isTrue(nextCommentStub.called);
+
+          // This is also called in diffCursor.moveToFirstChunk.
+          assert.equal(nextChunkStub.callCount, 1);
+          assert.equal(element.filesExpanded, 'some');
+        });
+
+        test('n key without all files expanded and shift key', () => {
+          MockInteractions.keyUpOn(fileRows[0], 73, 'shift', 'i');
+          flushAsynchronousOperations();
+
+          MockInteractions.pressAndReleaseKeyOn(element, 78, null, 'n');
+          assert.isTrue(nKeySpy.called);
+          assert.isFalse(nextCommentStub.called);
+
+          // This is also called in diffCursor.moveToFirstChunk.
+          assert.equal(nextChunkStub.callCount, 2);
+          assert.isTrue(element._showInlineDiffs);
+        });
+
+        test('n key without all files expanded and no shift key', () => {
+          MockInteractions.keyUpOn(fileRows[0], 73, 'shift', 'i');
+          flushAsynchronousOperations();
+
+          MockInteractions.pressAndReleaseKeyOn(element, 78, 'shift', 'n');
+          assert.isTrue(nKeySpy.called);
+          assert.isTrue(nextCommentStub.called);
+
+          // This is also called in diffCursor.moveToFirstChunk.
+          assert.equal(nextChunkStub.callCount, 1);
+          assert.isTrue(element._showInlineDiffs);
+        });
+      });
+
+      test('_openSelectedFile behavior', () => {
+        const _filesByPath = element._filesByPath;
+        element.set('_filesByPath', {});
+        const navStub = sandbox.stub(Gerrit.Nav, 'navigateToDiff');
+        // Noop when there are no files.
+        element._openSelectedFile();
+        assert.isFalse(navStub.called);
+
+        element.set('_filesByPath', _filesByPath);
+        flushAsynchronousOperations();
+        // Navigates when a file is selected.
+        element._openSelectedFile();
+        assert.isTrue(navStub.called);
+      });
+
+      test('_displayLine', () => {
+        sandbox.stub(element, 'shouldSuppressKeyboardShortcut', () => false);
+        sandbox.stub(element, 'modifierPressed', () => false);
+        element._showInlineDiffs = true;
+        const mockEvent = {preventDefault() {}};
+
+        element._displayLine = false;
+        element._handleCursorNext(mockEvent);
+        assert.isTrue(element._displayLine);
+
+        element._displayLine = false;
+        element._handleCursorPrev(mockEvent);
+        assert.isTrue(element._displayLine);
+
+        element._displayLine = true;
+        element._handleEscKey(mockEvent);
+        assert.isFalse(element._displayLine);
+      });
+
+      suite('editMode behavior', () => {
+        test('reviewed checkbox', () => {
+          element._reviewFile.restore();
+          const saveReviewStub = sandbox.stub(element, '_saveReviewedState');
+
+          element.editMode = false;
+          MockInteractions.pressAndReleaseKeyOn(element, 82, null, 'r');
+          assert.isTrue(saveReviewStub.calledOnce);
+
+          element.editMode = true;
+          flushAsynchronousOperations();
+
+          MockInteractions.pressAndReleaseKeyOn(element, 82, null, 'r');
+          assert.isTrue(saveReviewStub.calledOnce);
+        });
+
+        test('_getReviewedFiles does not call API', () => {
+          const apiSpy = sandbox.spy(element.$.restAPI, 'getReviewedFiles');
+          element.editMode = true;
+          return element._getReviewedFiles().then(files => {
+            assert.equal(files.length, 0);
+            assert.isFalse(apiSpy.called);
+          });
+        });
+      });
+
+      test('editing actions', () => {
+        // Edit controls are guarded behind a dom-if initially and not rendered.
+        assert.isNotOk(Polymer.dom(element.root)
+            .querySelector('gr-edit-file-controls'));
+
+        element.editMode = true;
+        flushAsynchronousOperations();
+
+        // Commit message should not have edit controls.
+        const editControls =
+            Array.from(
+                Polymer.dom(element.root)
+                    .querySelectorAll('.row:not(.header-row)'))
+                .map(row => row.querySelector('gr-edit-file-controls'));
+        assert.isTrue(editControls[0].classList.contains('invisible'));
+      });
+
+      test('reloadCommentsForThreadWithRootId', () => {
+        // Expand the commit message diff
+        MockInteractions.keyUpOn(element, 73, 'shift', 'i');
+        const diffs = renderAndGetNewDiffs(0);
+        flushAsynchronousOperations();
+
+        // Two comment threads should be generated by renderAndGetNewDiffs
+        const threadEls = diffs[0].getThreadEls();
+        assert.equal(threadEls.length, 2);
+        const threadElsByRootId = new Map(
+            threadEls.map(threadEl => [threadEl.rootId, threadEl]));
+
+        const thread1 = threadElsByRootId.get('503008e2_0ab203ee');
+        assert.equal(thread1.comments.length, 1);
+        assert.equal(thread1.comments[0].message, 'a comment');
+        assert.equal(thread1.comments[0].line, 10);
+
+        const thread2 = threadElsByRootId.get('ecf0b9fa_fe1a5f62');
+        assert.equal(thread2.comments.length, 2);
+        assert.isTrue(thread2.comments[0].unresolved);
+        assert.equal(thread2.comments[0].message, 'another comment');
+        assert.equal(thread2.comments[0].line, 20);
+
+        const commentStub =
+            sandbox.stub(element.changeComments, 'getCommentsForThread');
+        const commentStubRes1 = [
+          {
+            patch_set: 2,
+            id: '503008e2_0ab203ee',
+            line: 20,
+            updated: '2018-02-08 18:49:18.000000000',
+            message: 'edited text',
+            unresolved: false,
+          },
+        ];
+        const commentStubRes2 = [
+          {
+            patch_set: 2,
+            id: 'ecf0b9fa_fe1a5f62',
+            line: 20,
+            updated: '2018-02-08 18:49:18.000000000',
+            message: 'another comment',
+            unresolved: true,
+          },
+          {
+            patch_set: 2,
+            id: '503008e2_0ab203ee',
+            line: 10,
+            in_reply_to: 'ecf0b9fa_fe1a5f62',
+            updated: '2018-02-14 22:07:43.000000000',
+            message: 'response',
+            unresolved: true,
+          },
+          {
+            patch_set: 2,
+            id: '503008e2_0ab203ef',
+            line: 20,
+            in_reply_to: '503008e2_0ab203ee',
+            updated: '2018-02-15 22:07:43.000000000',
+            message: 'a third comment in the thread',
+            unresolved: true,
+          },
+        ];
+        commentStub.withArgs('503008e2_0ab203ee').returns(
+            commentStubRes1);
+        commentStub.withArgs('ecf0b9fa_fe1a5f62').returns(
+            commentStubRes2);
+
+        // Reload comments from the first comment thread, which should have a
+        // an updated message and a toggled resolve state.
+        element.reloadCommentsForThreadWithRootId('503008e2_0ab203ee',
+            '/COMMIT_MSG');
+        assert.equal(thread1.comments.length, 1);
+        assert.isFalse(thread1.comments[0].unresolved);
+        assert.equal(thread1.comments[0].message, 'edited text');
+
+        // Reload comments from the second comment thread, which should have a new
+        // reply.
+        element.reloadCommentsForThreadWithRootId('ecf0b9fa_fe1a5f62',
+            '/COMMIT_MSG');
+        assert.equal(thread2.comments.length, 3);
+
+        const commentStubCount = commentStub.callCount;
+        const getThreadsSpy = sandbox.spy(diffs[0], 'getThreadEls');
+
+        // Should not be getting threads when the file is not expanded.
+        element.reloadCommentsForThreadWithRootId('ecf0b9fa_fe1a5f62',
+            'other/file');
+        assert.isFalse(getThreadsSpy.called);
+        assert.equal(commentStubCount, commentStub.callCount);
+
+        // Should be query selecting diffs when the file is expanded.
+        // Should not be fetching change comments when the rootId is not found
+        // to match.
+        element.reloadCommentsForThreadWithRootId('acf0b9fa_fe1a5f62',
+            '/COMMIT_MSG');
+        assert.isTrue(getThreadsSpy.called);
+        assert.equal(commentStubCount, commentStub.callCount);
+      });
     });
+    a11ySuite('basic');
   });
-  a11ySuite('basic');
 </script>
diff --git a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_test.html b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_test.html
index b97e0b4..bec6c7b 100644
--- a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-included-in-dialog.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-included-in-dialog', () => {
+  suite('gr-included-in-dialog', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.html b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.html
index 134dd5c..50c01aa 100644
--- a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.html
+++ b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.html
@@ -61,19 +61,19 @@
           @apply --vote-chip-styles;
         }
       }
-      gr-button.iron-selected.max {
+      gr-button.iron-selected[vote="max"] {
         --button-background-color: var(--vote-color-approved);
       }
-      gr-button.iron-selected.positive {
+      gr-button.iron-selected[vote="positive"] {
         --button-background-color: var(--vote-color-recommended);
       }
-      gr-button.iron-selected.min {
+      gr-button.iron-selected[vote="min"] {
         --button-background-color: var(--vote-color-rejected);
       }
-      gr-button.iron-selected.negative {
+      gr-button.iron-selected[vote="negative"] {
         --button-background-color: var(--vote-color-disliked);
       }
-      gr-button.iron-selected.neutral {
+      gr-button.iron-selected[vote="neutral"] {
         --button-background-color: var(--vote-color-neutral);
       }
       .placeholder {
@@ -114,7 +114,7 @@
             items="[[_items]]"
             as="value">
           <gr-button
-              class$="[[_computeButtonClass(value, index, _items.length)]]"
+              vote$="[[_computeVoteAttribute(value, index, _items.length)]]"
               has-tooltip
               data-name$="[[label.name]]"
               data-value$="[[value]]"
diff --git a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.js b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.js
index 1f9845e..0316428 100644
--- a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.js
+++ b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.js
@@ -99,25 +99,24 @@
       }
     }
 
-    _computeButtonClass(value, index, totalItems) {
-      const classes = [];
-      if (value === this.selectedValue) {
-        classes.push('iron-selected');
-      }
-
+    /**
+     * Maps the label value to exactly one of: min, max, positive, negative,
+     * neutral. Used for the 'vote' attribute, because we don't want to
+     * interfere with <iron-selector> using the 'class' attribute for setting
+     * 'iron-selected'.
+     */
+    _computeVoteAttribute(value, index, totalItems) {
       if (value < 0 && index === 0) {
-        classes.push('min');
+        return 'min';
       } else if (value < 0) {
-        classes.push('negative');
+        return 'negative';
       } else if (value > 0 && index === totalItems - 1) {
-        classes.push('max');
+        return 'max';
       } else if (value > 0) {
-        classes.push('positive');
+        return 'positive';
       } else {
-        classes.push('neutral');
+        return 'neutral';
       }
-
-      return classes.join(' ');
     }
 
     _computeLabelValue(labels, permittedLabels, label) {
diff --git a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_test.html b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_test.html
index e9c21bc..c363982 100644
--- a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_test.html
+++ b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_test.html
@@ -24,6 +24,7 @@
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
 
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-label-score-row.html">
 
@@ -36,7 +37,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-label-row-score tests', () => {
+  suite('gr-label-row-score tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
@@ -122,36 +124,36 @@
       assert.equal(detail.value, '-1');
     });
 
-    test('_computeButtonClass', () => {
+    test('_computeVoteAttribute', () => {
       let value = 1;
       let index = 0;
       const totalItems = 5;
       // positive and first position
-      assert.equal(element._computeButtonClass(value, index,
+      assert.equal(element._computeVoteAttribute(value, index,
           totalItems), 'positive');
       // negative and first position
       value = -1;
-      assert.equal(element._computeButtonClass(value, index,
+      assert.equal(element._computeVoteAttribute(value, index,
           totalItems), 'min');
       // negative but not first position
       index = 1;
-      assert.equal(element._computeButtonClass(value, index,
+      assert.equal(element._computeVoteAttribute(value, index,
           totalItems), 'negative');
       // neutral
       value = 0;
-      assert.equal(element._computeButtonClass(value, index,
+      assert.equal(element._computeVoteAttribute(value, index,
           totalItems), 'neutral');
       // positive but not last position
       value = 1;
-      assert.equal(element._computeButtonClass(value, index,
+      assert.equal(element._computeVoteAttribute(value, index,
           totalItems), 'positive');
       // positive and last position
       index = 4;
-      assert.equal(element._computeButtonClass(value, index,
+      assert.equal(element._computeVoteAttribute(value, index,
           totalItems), 'max');
       // negative and last position
       value = -1;
-      assert.equal(element._computeButtonClass(value, index,
+      assert.equal(element._computeVoteAttribute(value, index,
           totalItems), 'negative');
     });
 
diff --git a/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores_test.html b/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores_test.html
index 4c489b7..22849f8 100644
--- a/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores_test.html
+++ b/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-label-scores.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-label-scores tests', () => {
+  suite('gr-label-scores tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message.html b/polygerrit-ui/app/elements/change/gr-message/gr-message.html
index 2ea1134..b807b37 100644
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message.html
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message.html
@@ -81,11 +81,15 @@
         margin: 0 -4px;
       }
       .collapsed gr-comment-list,
-      .collapsed .replyContainer,
+      .collapsed .replyBtn,
+      .collapsed .deleteBtn,
       .collapsed .hideOnCollapsed,
       .hideOnOpen {
         display: none;
       }
+      .replyBtn {
+        margin-right: var(--spacing-m);
+      }
       .collapsed .hideOnOpen {
         display: block;
       }
@@ -219,8 +223,18 @@
                 content="[[_messageContentExpanded]]"
                 config="[[_projectConfig.commentlinks]]"></gr-formatted-text>
             <template is="dom-if" if="[[!_isMessageContentEmpty()]]">
-              <div class="replyContainer" hidden$="[[!showReplyButton]]" hidden>
-                <gr-button link small on-click="_handleReplyTap">Reply</gr-button>
+              <div class="replyActionContainer" hidden$="[[!showReplyButton]]" hidden>
+                  <gr-button
+                     class="replyBtn"
+                     link small on-click="_handleReplyTap">
+                    Reply
+                  </gr-button>
+                  <gr-button
+                    disabled$=[[_isDeletingChangeMsg]]
+                    class="deleteBtn" hidden$="[[!_isAdmin]]" hidden
+                    link small on-click="_handleDeleteMessage">
+                    Delete
+                  </gr-button>
               </div>
             </template>
             <gr-comment-list
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message.js b/polygerrit-ui/app/elements/change/gr-message/gr-message.js
index d5505a4..13a4213 100644
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message.js
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message.js
@@ -42,6 +42,12 @@
      * @event message-anchor-tap
      */
 
+    /**
+     * Fired when a change message is deleted.
+     *
+     * @event change-message-deleted
+     */
+
     static get properties() {
       return {
         changeNum: Number,
@@ -115,6 +121,14 @@
           type: Boolean,
           value: false,
         },
+        _isAdmin: {
+          type: Boolean,
+          value: false,
+        },
+        _isDeletingChangeMsg: {
+          type: Boolean,
+          value: false,
+        },
       };
     }
 
@@ -140,6 +154,9 @@
       this.$.restAPI.getLoggedIn().then(loggedIn => {
         this._loggedIn = loggedIn;
       });
+      this.$.restAPI.getIsAdmin().then(isAdmin => {
+        this._isAdmin = isAdmin;
+      });
     }
 
     _updateExpandedClass(expanded) {
@@ -344,6 +361,17 @@
       this.fire('reply', {message: this.message});
     }
 
+    _handleDeleteMessage(e) {
+      e.preventDefault();
+      if (!this.message || !this.message.id) return;
+      this._isDeletingChangeMsg = true;
+      this.$.restAPI.deleteChangeCommitMessage(this.changeNum, this.message.id)
+          .then(() => {
+            this._isDeletingChangeMsg = false;
+            this.fire('change-message-deleted', {message: this.message});
+          });
+    }
+
     _projectNameChanged(name) {
       this.$.restAPI.getProjectConfig(name).then(config => {
         this._projectConfig = config;
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message_test.html b/polygerrit-ui/app/elements/change/gr-message/gr-message_test.html
index 20d87d2..b23c797 100644
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message_test.html
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-message.html">
 
@@ -35,264 +36,384 @@
 </test-fixture>
 
 <script>
-  suite('gr-message tests', () => {
+  suite('gr-message tests', async () => {
+    await readyToTest();
     let element;
 
-    setup(done => {
-      stub('gr-rest-api-interface', {
-        getLoggedIn() { return Promise.resolve(false); },
-        getConfig() { return Promise.resolve({}); },
+    suite('when admin and logged in', () => {
+      setup(done => {
+        stub('gr-rest-api-interface', {
+          getLoggedIn() { return Promise.resolve(true); },
+          getPreferences() { return Promise.resolve({}); },
+          getConfig() { return Promise.resolve({}); },
+          getIsAdmin() { return Promise.resolve(true); },
+          deleteChangeCommitMessage() { return Promise.resolve({}); },
+        });
+        element = fixture('basic');
+        flush(done);
       });
-      element = fixture('basic');
-      flush(done);
-    });
 
-    test('reply event', done => {
-      element.message = {
-        id: '47c43261_55aa2c41',
-        author: {
-          _account_id: 1115495,
-          name: 'Andrew Bonventre',
-          email: 'andybons@chromium.org',
-        },
-        date: '2016-01-12 20:24:49.448000000',
-        message: 'Uploaded patch set 1.',
-        _revision_number: 1,
-      };
+      test('reply event', done => {
+        element.message = {
+          id: '47c43261_55aa2c41',
+          author: {
+            _account_id: 1115495,
+            name: 'Andrew Bonventre',
+            email: 'andybons@chromium.org',
+          },
+          date: '2016-01-12 20:24:49.448000000',
+          message: 'Uploaded patch set 1.',
+          _revision_number: 1,
+        };
 
-      element.addEventListener('reply', e => {
-        assert.deepEqual(e.detail.message, element.message);
-        done();
+        element.addEventListener('reply', e => {
+          assert.deepEqual(e.detail.message, element.message);
+          done();
+        });
+        flushAsynchronousOperations();
+        assert.isFalse(
+            element.shadowRoot.querySelector('.replyActionContainer').hidden
+        );
+        MockInteractions.tap(element.shadowRoot.querySelector('.replyBtn'));
       });
-      flushAsynchronousOperations();
-      MockInteractions.tap(element.$$('.replyContainer gr-button'));
-    });
 
-    test('autogenerated prefix hiding', () => {
-      element.message = {
-        tag: 'autogenerated:gerrit:test',
-        updated: '2016-01-12 20:24:49.448000000',
-      };
+      test('can see delete button', () => {
+        element.message = {
+          id: '47c43261_55aa2c41',
+          author: {
+            _account_id: 1115495,
+            name: 'Andrew Bonventre',
+            email: 'andybons@chromium.org',
+          },
+          date: '2016-01-12 20:24:49.448000000',
+          message: 'Uploaded patch set 1.',
+          _revision_number: 1,
+        };
 
-      assert.isTrue(element.isAutomated);
-      assert.isFalse(element.hidden);
+        flushAsynchronousOperations();
+        assert.isFalse(element.shadowRoot.querySelector('.deleteBtn').hidden);
+      });
 
-      element.hideAutomated = true;
+      test('delete change message', done => {
+        element.message = {
+          id: '47c43261_55aa2c41',
+          author: {
+            _account_id: 1115495,
+            name: 'Andrew Bonventre',
+            email: 'andybons@chromium.org',
+          },
+          date: '2016-01-12 20:24:49.448000000',
+          message: 'Uploaded patch set 1.',
+          _revision_number: 1,
+        };
 
-      assert.isTrue(element.hidden);
-    });
+        element.addEventListener('change-message-deleted', e => {
+          assert.deepEqual(e.detail.message, element.message);
+          assert.isFalse(element.shadowRoot.querySelector('.deleteBtn').disabled);
+          done();
+        });
+        flushAsynchronousOperations();
+        MockInteractions.tap(element.shadowRoot.querySelector('.deleteBtn'));
+        assert.isTrue(element.shadowRoot.querySelector('.deleteBtn').disabled);
+      });
 
-    test('reviewer message treated as autogenerated', () => {
-      element.message = {
-        tag: 'autogenerated:gerrit:test',
-        updated: '2016-01-12 20:24:49.448000000',
-        reviewer: {},
-      };
+      test('autogenerated prefix hiding', () => {
+        element.message = {
+          tag: 'autogenerated:gerrit:test',
+          updated: '2016-01-12 20:24:49.448000000',
+        };
 
-      assert.isTrue(element.isAutomated);
-      assert.isFalse(element.hidden);
+        assert.isTrue(element.isAutomated);
+        assert.isFalse(element.hidden);
 
-      element.hideAutomated = true;
+        element.hideAutomated = true;
 
-      assert.isTrue(element.hidden);
-    });
+        assert.isTrue(element.hidden);
+      });
 
-    test('batch reviewer message treated as autogenerated', () => {
-      element.message = {
-        type: 'REVIEWER_UPDATE',
-        updated: '2016-01-12 20:24:49.448000000',
-        reviewer: {},
-      };
+      test('reviewer message treated as autogenerated', () => {
+        element.message = {
+          tag: 'autogenerated:gerrit:test',
+          updated: '2016-01-12 20:24:49.448000000',
+          reviewer: {},
+        };
 
-      assert.isTrue(element.isAutomated);
-      assert.isFalse(element.hidden);
+        assert.isTrue(element.isAutomated);
+        assert.isFalse(element.hidden);
 
-      element.hideAutomated = true;
+        element.hideAutomated = true;
 
-      assert.isTrue(element.hidden);
-    });
+        assert.isTrue(element.hidden);
+      });
 
-    test('tag that is not autogenerated prefix does not hide', () => {
-      element.message = {
-        tag: 'something',
-        updated: '2016-01-12 20:24:49.448000000',
-      };
+      test('batch reviewer message treated as autogenerated', () => {
+        element.message = {
+          type: 'REVIEWER_UPDATE',
+          updated: '2016-01-12 20:24:49.448000000',
+          reviewer: {},
+        };
 
-      assert.isFalse(element.isAutomated);
-      assert.isFalse(element.hidden);
+        assert.isTrue(element.isAutomated);
+        assert.isFalse(element.hidden);
 
-      element.hideAutomated = true;
+        element.hideAutomated = true;
 
-      assert.isFalse(element.hidden);
-    });
+        assert.isTrue(element.hidden);
+      });
 
-    test('reply button hidden unless logged in', () => {
-      const message = {
-        message: 'Uploaded patch set 1.',
-      };
-      assert.isFalse(element._computeShowReplyButton(message, false));
-      assert.isTrue(element._computeShowReplyButton(message, true));
-    });
+      test('tag that is not autogenerated prefix does not hide', () => {
+        element.message = {
+          tag: 'something',
+          updated: '2016-01-12 20:24:49.448000000',
+        };
 
-    test('_computeShowOnBehalfOf', () => {
-      const message = {
-        message: '...',
-      };
-      assert.isNotOk(element._computeShowOnBehalfOf(message));
-      message.author = {_account_id: 1115495};
-      assert.isNotOk(element._computeShowOnBehalfOf(message));
-      message.real_author = {_account_id: 1115495};
-      assert.isNotOk(element._computeShowOnBehalfOf(message));
-      message.real_author._account_id = 123456;
-      assert.isOk(element._computeShowOnBehalfOf(message));
-      message.updated_by = message.author;
-      delete message.author;
-      assert.isOk(element._computeShowOnBehalfOf(message));
-      delete message.updated_by;
-      assert.isNotOk(element._computeShowOnBehalfOf(message));
-    });
+        assert.isFalse(element.isAutomated);
+        assert.isFalse(element.hidden);
 
-    ['Trybot-Ready', 'Tryjob-Request', 'Commit-Queue'].forEach(label => {
-      test(`${label} ignored for color voting`, () => {
+        element.hideAutomated = true;
+
+        assert.isFalse(element.hidden);
+      });
+
+      test('reply button hidden unless logged in', () => {
+        const message = {
+          message: 'Uploaded patch set 1.',
+        };
+        assert.isFalse(element._computeShowReplyButton(message, false));
+        assert.isTrue(element._computeShowReplyButton(message, true));
+      });
+
+      test('_computeShowOnBehalfOf', () => {
+        const message = {
+          message: '...',
+        };
+        assert.isNotOk(element._computeShowOnBehalfOf(message));
+        message.author = {_account_id: 1115495};
+        assert.isNotOk(element._computeShowOnBehalfOf(message));
+        message.real_author = {_account_id: 1115495};
+        assert.isNotOk(element._computeShowOnBehalfOf(message));
+        message.real_author._account_id = 123456;
+        assert.isOk(element._computeShowOnBehalfOf(message));
+        message.updated_by = message.author;
+        delete message.author;
+        assert.isOk(element._computeShowOnBehalfOf(message));
+        delete message.updated_by;
+        assert.isNotOk(element._computeShowOnBehalfOf(message));
+      });
+
+      ['Trybot-Ready', 'Tryjob-Request', 'Commit-Queue'].forEach(label => {
+        test(`${label} ignored for color voting`, () => {
+          element.message = {
+            author: {},
+            expanded: false,
+            message: `Patch Set 1: ${label}+1`,
+          };
+          assert.isNotOk(
+              Polymer.dom(element.root).querySelector('.negativeVote'));
+          assert.isNotOk(
+              Polymer.dom(element.root).querySelector('.positiveVote'));
+        });
+      });
+
+      test('clicking on date link fires event', () => {
+        element.message = {
+          type: 'REVIEWER_UPDATE',
+          updated: '2016-01-12 20:24:49.448000000',
+          reviewer: {},
+          id: '47c43261_55aa2c41',
+        };
+        flushAsynchronousOperations();
+        const stub = sinon.stub();
+        element.addEventListener('message-anchor-tap', stub);
+        const dateEl = element.$$('.date');
+        assert.ok(dateEl);
+        MockInteractions.tap(dateEl);
+
+        assert.isTrue(stub.called);
+        assert.deepEqual(stub.lastCall.args[0].detail, {id: element.message.id});
+      });
+
+      suite('compute messages', () => {
+        test('empty', () => {
+          assert.equal(element._computeMessageContent('', '', true), '');
+          assert.equal(element._computeMessageContent('', '', false), '');
+        });
+
+        test('new patchset', () => {
+          const original = 'Uploaded patch set 1.';
+          const tag = 'autogenerated:gerrit:newPatchSet';
+          let actual = element._computeMessageContent(original, tag, true);
+          assert.equal(actual, original);
+          actual = element._computeMessageContent(original, tag, false);
+          assert.equal(actual, original);
+        });
+
+        test('new patchset rebased', () => {
+          const original = 'Patch Set 27: Patch Set 26 was rebased';
+          const tag = 'autogenerated:gerrit:newPatchSet';
+          const expected = 'Patch Set 26 was rebased';
+          let actual = element._computeMessageContent(original, tag, true);
+          assert.equal(actual, expected);
+          actual = element._computeMessageContent(original, tag, false);
+          assert.equal(actual, expected);
+        });
+
+        test('ready for review', () => {
+          const original = 'Patch Set 1:\n\nThis change is ready for review.';
+          const tag = undefined;
+          const expected = 'This change is ready for review.';
+          let actual = element._computeMessageContent(original, tag, true);
+          assert.equal(actual, expected);
+          actual = element._computeMessageContent(original, tag, false);
+          assert.equal(actual, expected);
+        });
+
+        test('vote', () => {
+          const original = 'Patch Set 1: Code-Style+1';
+          const tag = undefined;
+          const expected = '';
+          let actual = element._computeMessageContent(original, tag, true);
+          assert.equal(actual, expected);
+          actual = element._computeMessageContent(original, tag, false);
+          assert.equal(actual, expected);
+        });
+
+        test('comments', () => {
+          const original = 'Patch Set 1:\n\n(3 comments)';
+          const tag = undefined;
+          const expected = '';
+          let actual = element._computeMessageContent(original, tag, true);
+          assert.equal(actual, expected);
+          actual = element._computeMessageContent(original, tag, false);
+          assert.equal(actual, expected);
+        });
+      });
+
+      test('votes', () => {
         element.message = {
           author: {},
           expanded: false,
-          message: `Patch Set 1: ${label}+1`,
+          message: 'Patch Set 1: Verified+1 Code-Review-2 Trybot-Label3+1 Blub+1',
         };
-        assert.isNotOk(
-            Polymer.dom(element.root).querySelector('.negativeVote'));
-        assert.isNotOk(
-            Polymer.dom(element.root).querySelector('.positiveVote'));
+        element.labelExtremes = {
+          'Verified': {max: 1, min: -1},
+          'Code-Review': {max: 2, min: -2},
+          'Trybot-Label3': {max: 3, min: 0},
+        };
+        flushAsynchronousOperations();
+        const scoreChips = Polymer.dom(element.root).querySelectorAll('.score');
+        assert.equal(scoreChips.length, 3);
+
+        assert.isTrue(scoreChips[0].classList.contains('positive'));
+        assert.isTrue(scoreChips[0].classList.contains('max'));
+
+        assert.isTrue(scoreChips[1].classList.contains('negative'));
+        assert.isTrue(scoreChips[1].classList.contains('min'));
+
+        assert.isTrue(scoreChips[2].classList.contains('positive'));
+        assert.isFalse(scoreChips[2].classList.contains('min'));
+      });
+
+      test('removed votes', () => {
+        element.message = {
+          author: {},
+          expanded: false,
+          message: 'Patch Set 1: Verified+1 -Code-Review -Commit-Queue',
+        };
+        element.labelExtremes = {
+          'Verified': {max: 1, min: -1},
+          'Code-Review': {max: 2, min: -2},
+          'Commit-Queue': {max: 3, min: 0},
+        };
+        flushAsynchronousOperations();
+        const scoreChips = Polymer.dom(element.root).querySelectorAll('.score');
+        assert.equal(scoreChips.length, 3);
+
+        assert.isTrue(scoreChips[1].classList.contains('removed'));
+        assert.isTrue(scoreChips[2].classList.contains('removed'));
+      });
+
+      test('false negative vote', () => {
+        element.message = {
+          author: {},
+          expanded: false,
+          message: 'Patch Set 1: Cherry Picked from branch stable-2.14.',
+        };
+        element.labelExtremes = {};
+        const scoreChips = Polymer.dom(element.root).querySelectorAll('.score');
+        assert.equal(scoreChips.length, 0);
       });
     });
 
-    test('clicking on date link fires event', () => {
-      element.message = {
-        type: 'REVIEWER_UPDATE',
-        updated: '2016-01-12 20:24:49.448000000',
-        reviewer: {},
-        id: '47c43261_55aa2c41',
-      };
-      flushAsynchronousOperations();
-      const stub = sinon.stub();
-      element.addEventListener('message-anchor-tap', stub);
-      const dateEl = element.$$('.date');
-      assert.ok(dateEl);
-      MockInteractions.tap(dateEl);
-
-      assert.isTrue(stub.called);
-      assert.deepEqual(stub.lastCall.args[0].detail, {id: element.message.id});
-    });
-
-    suite('compute messages', () => {
-      test('empty', () => {
-        assert.equal(element._computeMessageContent('', '', true), '');
-        assert.equal(element._computeMessageContent('', '', false), '');
+    suite('when not logged in', () => {
+      setup(done => {
+        stub('gr-rest-api-interface', {
+          getLoggedIn() { return Promise.resolve(false); },
+          getPreferences() { return Promise.resolve({}); },
+          getConfig() { return Promise.resolve({}); },
+          getIsAdmin() { return Promise.resolve(false); },
+          deleteChangeCommitMessage() { return Promise.resolve({}); },
+        });
+        element = fixture('basic');
+        flush(done);
       });
 
-      test('new patchset', () => {
-        const original = 'Uploaded patch set 1.';
-        const tag = 'autogenerated:gerrit:newPatchSet';
-        let actual = element._computeMessageContent(original, tag, true);
-        assert.equal(actual, original);
-        actual = element._computeMessageContent(original, tag, false);
-        assert.equal(actual, original);
-      });
+      test('reply and delete button should be hidden', () => {
+        element.message = {
+          id: '47c43261_55aa2c41',
+          author: {
+            _account_id: 1115495,
+            name: 'Andrew Bonventre',
+            email: 'andybons@chromium.org',
+          },
+          date: '2016-01-12 20:24:49.448000000',
+          message: 'Uploaded patch set 1.',
+          _revision_number: 1,
+        };
 
-      test('new patchset rebased', () => {
-        const original = 'Patch Set 27: Patch Set 26 was rebased';
-        const tag = 'autogenerated:gerrit:newPatchSet';
-        const expected = 'Patch Set 26 was rebased';
-        let actual = element._computeMessageContent(original, tag, true);
-        assert.equal(actual, expected);
-        actual = element._computeMessageContent(original, tag, false);
-        assert.equal(actual, expected);
-      });
-
-      test('ready for review', () => {
-        const original = 'Patch Set 1:\n\nThis change is ready for review.';
-        const tag = undefined;
-        const expected = 'This change is ready for review.';
-        let actual = element._computeMessageContent(original, tag, true);
-        assert.equal(actual, expected);
-        actual = element._computeMessageContent(original, tag, false);
-        assert.equal(actual, expected);
-      });
-
-      test('vote', () => {
-        const original = 'Patch Set 1: Code-Style+1';
-        const tag = undefined;
-        const expected = '';
-        let actual = element._computeMessageContent(original, tag, true);
-        assert.equal(actual, expected);
-        actual = element._computeMessageContent(original, tag, false);
-        assert.equal(actual, expected);
-      });
-
-      test('comments', () => {
-        const original = 'Patch Set 1:\n\n(3 comments)';
-        const tag = undefined;
-        const expected = '';
-        let actual = element._computeMessageContent(original, tag, true);
-        assert.equal(actual, expected);
-        actual = element._computeMessageContent(original, tag, false);
-        assert.equal(actual, expected);
+        flushAsynchronousOperations();
+        assert.isTrue(
+            element.shadowRoot.querySelector('.replyActionContainer').hidden
+        );
+        assert.isTrue(
+            element.shadowRoot.querySelector('.deleteBtn').hidden
+        );
       });
     });
 
-    test('votes', () => {
-      element.message = {
-        author: {},
-        expanded: false,
-        message: 'Patch Set 1: Verified+1 Code-Review-2 Trybot-Label3+1 Blub+1',
-      };
-      element.labelExtremes = {
-        'Verified': {max: 1, min: -1},
-        'Code-Review': {max: 2, min: -2},
-        'Trybot-Label3': {max: 3, min: 0},
-      };
-      flushAsynchronousOperations();
-      const scoreChips = Polymer.dom(element.root).querySelectorAll('.score');
-      assert.equal(scoreChips.length, 3);
+    suite('when logged in but not admin', () => {
+      setup(done => {
+        stub('gr-rest-api-interface', {
+          getLoggedIn() { return Promise.resolve(true); },
+          getConfig() { return Promise.resolve({}); },
+          getIsAdmin() { return Promise.resolve(false); },
+          deleteChangeCommitMessage() { return Promise.resolve({}); },
+        });
+        element = fixture('basic');
+        flush(done);
+      });
 
-      assert.isTrue(scoreChips[0].classList.contains('positive'));
-      assert.isTrue(scoreChips[0].classList.contains('max'));
+      test('can see reply but not delete button', () => {
+        element.message = {
+          id: '47c43261_55aa2c41',
+          author: {
+            _account_id: 1115495,
+            name: 'Andrew Bonventre',
+            email: 'andybons@chromium.org',
+          },
+          date: '2016-01-12 20:24:49.448000000',
+          message: 'Uploaded patch set 1.',
+          _revision_number: 1,
+        };
 
-      assert.isTrue(scoreChips[1].classList.contains('negative'));
-      assert.isTrue(scoreChips[1].classList.contains('min'));
-
-      assert.isTrue(scoreChips[2].classList.contains('positive'));
-      assert.isFalse(scoreChips[2].classList.contains('min'));
-    });
-
-    test('removed votes', () => {
-      element.message = {
-        author: {},
-        expanded: false,
-        message: 'Patch Set 1: Verified+1 -Code-Review -Commit-Queue',
-      };
-      element.labelExtremes = {
-        'Verified': {max: 1, min: -1},
-        'Code-Review': {max: 2, min: -2},
-        'Commit-Queue': {max: 3, min: 0},
-      };
-      flushAsynchronousOperations();
-      const scoreChips = Polymer.dom(element.root).querySelectorAll('.score');
-      assert.equal(scoreChips.length, 3);
-
-      assert.isTrue(scoreChips[1].classList.contains('removed'));
-      assert.isTrue(scoreChips[2].classList.contains('removed'));
-    });
-
-    test('false negative vote', () => {
-      element.message = {
-        author: {},
-        expanded: false,
-        message: 'Patch Set 1: Cherry Picked from branch stable-2.14.',
-      };
-      element.labelExtremes = {};
-      const scoreChips = Polymer.dom(element.root).querySelectorAll('.score');
-      assert.equal(scoreChips.length, 0);
+        flushAsynchronousOperations();
+        assert.isFalse(
+            element.shadowRoot.querySelector('.replyActionContainer').hidden
+        );
+        assert.isTrue(
+            element.shadowRoot.querySelector('.deleteBtn').hidden
+        );
+      });
     });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_test.html b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_test.html
index 9c3f53b..0662f54 100644
--- a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="../../diff/gr-comment-api/gr-comment-api.html">
 
@@ -70,7 +71,8 @@
         randomMessage(opt_params));
   };
 
-  suite('gr-messages-list tests', () => {
+  suite('gr-messages-list tests', async () => {
+    await readyToTest();
     let element;
     let messages;
     let sandbox;
@@ -132,483 +134,485 @@
       ],
     };
 
-    setup(() => {
-      stub('gr-rest-api-interface', {
-        getConfig() { return Promise.resolve({}); },
-        getLoggedIn() { return Promise.resolve(false); },
-        getDiffComments() { return Promise.resolve(comments); },
-        getDiffRobotComments() { return Promise.resolve({}); },
-        getDiffDrafts() { return Promise.resolve({}); },
+    suite('basic tests', () => {
+      setup(() => {
+        stub('gr-rest-api-interface', {
+          getConfig() { return Promise.resolve({}); },
+          getLoggedIn() { return Promise.resolve(false); },
+          getDiffComments() { return Promise.resolve(comments); },
+          getDiffRobotComments() { return Promise.resolve({}); },
+          getDiffDrafts() { return Promise.resolve({}); },
+        });
+        sandbox = sinon.sandbox.create();
+        messages = _.times(3, randomMessage);
+        // Element must be wrapped in an element with direct access to the
+        // comment API.
+        commentApiWrapper = fixture('basic');
+        element = commentApiWrapper.$.messagesList;
+        loadCommentSpy = sandbox.spy(commentApiWrapper.$.commentAPI, 'loadAll');
+        element.messages = messages;
+
+        // Stub methods on the changeComments object after changeComments has
+        // been initialized.
+        return commentApiWrapper.loadComments();
       });
-      sandbox = sinon.sandbox.create();
-      messages = _.times(3, randomMessage);
-      // Element must be wrapped in an element with direct access to the
-      // comment API.
-      commentApiWrapper = fixture('basic');
-      element = commentApiWrapper.$.messagesList;
-      loadCommentSpy = sandbox.spy(commentApiWrapper.$.commentAPI, 'loadAll');
-      element.messages = messages;
 
-      // Stub methods on the changeComments object after changeComments has
-      // been initialized.
-      return commentApiWrapper.loadComments();
+      teardown(() => {
+        sandbox.restore();
+      });
+
+      test('show some old messages', () => {
+        assert.isTrue(element.$.messageControlsContainer.hasAttribute('hidden'));
+        element.messages = _.times(26, randomMessage);
+        flushAsynchronousOperations();
+
+        assert.isFalse(element.$.messageControlsContainer.hasAttribute('hidden'));
+        assert.equal(getMessages().length, 20);
+        assert.equal(element.$.incrementMessagesBtn.innerText.toUpperCase()
+            .trim(), 'SHOW 5 MORE');
+        MockInteractions.tap(element.$.incrementMessagesBtn);
+        flushAsynchronousOperations();
+
+        assert.equal(getMessages().length, 25);
+        assert.equal(element.$.incrementMessagesBtn.innerText.toUpperCase()
+            .trim(), 'SHOW 1 MORE');
+        MockInteractions.tap(element.$.incrementMessagesBtn);
+        flushAsynchronousOperations();
+
+        assert.isTrue(element.$.messageControlsContainer.hasAttribute('hidden'));
+        assert.equal(getMessages().length, 26);
+      });
+
+      test('show all old messages', () => {
+        assert.isTrue(element.$.messageControlsContainer.hasAttribute('hidden'));
+        element.messages = _.times(26, randomMessage);
+        flushAsynchronousOperations();
+
+        assert.isFalse(element.$.messageControlsContainer.hasAttribute('hidden'));
+        assert.equal(getMessages().length, 20);
+        assert.equal(element.$.oldMessagesBtn.innerText.toUpperCase(),
+            'SHOW ALL 6 MESSAGES');
+        MockInteractions.tap(element.$.oldMessagesBtn);
+        flushAsynchronousOperations();
+
+        assert.equal(getMessages().length, 26);
+        assert.isTrue(element.$.messageControlsContainer.hasAttribute('hidden'));
+      });
+
+      test('message count respects automated', () => {
+        element.messages = _.times(10, randomAutomated)
+            .concat(_.times(11, randomMessage));
+        flushAsynchronousOperations();
+
+        assert.equal(element.$.oldMessagesBtn.innerText.toUpperCase(),
+            'SHOW 1 MESSAGE');
+        assert.isFalse(element.$.messageControlsContainer.hasAttribute('hidden'));
+        MockInteractions.tap(element.$.automatedMessageToggle);
+        flushAsynchronousOperations();
+
+        assert.isTrue(element.$.messageControlsContainer.hasAttribute('hidden'));
+      });
+
+      test('message count still respects non-automated on toggle', () => {
+        element.messages = _.times(10, randomMessage)
+            .concat(_.times(11, randomAutomated));
+        flushAsynchronousOperations();
+
+        assert.equal(element.$.oldMessagesBtn.innerText.toUpperCase(),
+            'SHOW 1 MESSAGE');
+        assert.isFalse(element.$.messageControlsContainer.hasAttribute('hidden'));
+        MockInteractions.tap(element.$.automatedMessageToggle);
+        flushAsynchronousOperations();
+
+        assert.equal(element.$.oldMessagesBtn.innerText.toUpperCase(),
+            'SHOW 1 MESSAGE');
+        assert.isFalse(element.$.messageControlsContainer.hasAttribute('hidden'));
+      });
+
+      test('show all messages respects expand', () => {
+        element.messages = _.times(10, randomAutomated)
+            .concat(_.times(11, randomMessage));
+        flushAsynchronousOperations();
+
+        MockInteractions.tap(element.shadowRoot
+            .querySelector('#collapse-messages')); // Expand all.
+        flushAsynchronousOperations();
+
+        let messages = getMessages();
+        assert.equal(messages.length, 20);
+        for (const message of messages) {
+          assert.isTrue(message._expanded);
+        }
+
+        MockInteractions.tap(element.$.oldMessagesBtn);
+        flushAsynchronousOperations();
+
+        messages = getMessages();
+        assert.equal(messages.length, 21);
+        for (const message of messages) {
+          assert.isTrue(message._expanded);
+        }
+      });
+
+      test('show all messages respects collapse', () => {
+        element.messages = _.times(10, randomAutomated)
+            .concat(_.times(11, randomMessage));
+        flushAsynchronousOperations();
+
+        MockInteractions.tap(element.shadowRoot
+            .querySelector('#collapse-messages')); // Expand all.
+        MockInteractions.tap(element.shadowRoot
+            .querySelector('#collapse-messages')); // Collapse all.
+        flushAsynchronousOperations();
+
+        let messages = getMessages();
+        assert.equal(messages.length, 20);
+        for (const message of messages) {
+          assert.isFalse(message._expanded);
+        }
+
+        MockInteractions.tap(element.$.oldMessagesBtn);
+        flushAsynchronousOperations();
+
+        messages = getMessages();
+        assert.equal(messages.length, 21);
+        for (const message of messages) {
+          assert.isFalse(message._expanded);
+        }
+      });
+
+      test('expand/collapse all', () => {
+        let allMessageEls = getMessages();
+        for (const message of allMessageEls) {
+          message._expanded = false;
+        }
+        MockInteractions.tap(allMessageEls[1]);
+        assert.isTrue(allMessageEls[1]._expanded);
+
+        MockInteractions.tap(element.shadowRoot
+            .querySelector('#collapse-messages'));
+        allMessageEls = getMessages();
+        for (const message of allMessageEls) {
+          assert.isTrue(message._expanded);
+        }
+
+        MockInteractions.tap(element.shadowRoot
+            .querySelector('#collapse-messages'));
+        allMessageEls = getMessages();
+        for (const message of allMessageEls) {
+          assert.isFalse(message._expanded);
+        }
+      });
+
+      test('expand/collapse from external keypress', () => {
+        MockInteractions.tap(element.shadowRoot
+            .querySelector('#collapse-messages'));
+        let allMessageEls = getMessages();
+        for (const message of allMessageEls) {
+          assert.isTrue(message._expanded);
+        }
+
+        // Expand/collapse all text also changes.
+        assert.equal(element.shadowRoot
+            .querySelector('#collapse-messages').textContent.trim(),
+        'Collapse all');
+
+        MockInteractions.tap(element.shadowRoot
+            .querySelector('#collapse-messages'));
+        allMessageEls = getMessages();
+        for (const message of allMessageEls) {
+          assert.isFalse(message._expanded);
+        }
+        // Expand/collapse all text also changes.
+        assert.equal(element.shadowRoot
+            .querySelector('#collapse-messages').textContent.trim(),
+        'Expand all');
+      });
+
+      test('hide messages does not appear when no automated messages', () => {
+        assert.isOk(element.shadowRoot
+            .querySelector('#automatedMessageToggleContainer[hidden]'));
+      });
+
+      test('scroll to message', () => {
+        const allMessageEls = getMessages();
+        for (const message of allMessageEls) {
+          message.set('message.expanded', false);
+        }
+
+        const scrollToStub = sandbox.stub(window, 'scrollTo');
+        const highlightStub = sandbox.stub(element, '_highlightEl');
+
+        element.scrollToMessage('invalid');
+
+        for (const message of allMessageEls) {
+          assert.isFalse(message._expanded,
+              'expected gr-message to not be expanded');
+        }
+
+        const messageID = messages[1].id;
+        element.scrollToMessage(messageID);
+        assert.isTrue(
+            element.$$('[data-message-id="' + messageID + '"]')._expanded);
+
+        assert.isTrue(scrollToStub.calledOnce);
+        assert.isTrue(highlightStub.calledOnce);
+      });
+
+      test('scroll to message offscreen', () => {
+        const scrollToStub = sandbox.stub(window, 'scrollTo');
+        const highlightStub = sandbox.stub(element, '_highlightEl');
+        element.messages = _.times(25, randomMessage);
+        flushAsynchronousOperations();
+        assert.isFalse(scrollToStub.called);
+        assert.isFalse(highlightStub.called);
+
+        const messageID = element.messages[1].id;
+        element.scrollToMessage(messageID);
+        assert.isTrue(scrollToStub.calledOnce);
+        assert.isTrue(highlightStub.calledOnce);
+        assert.equal(element._visibleMessages.length, 24);
+        assert.isTrue(
+            element.$$('[data-message-id="' + messageID + '"]')._expanded);
+      });
+
+      test('messages', () => {
+        const messages = [].concat(
+            randomMessage(),
+            {
+              _index: 5,
+              _revision_number: 4,
+              message: 'Uploaded patch set 4.',
+              date: '2016-09-28 13:36:33.000000000',
+              author,
+              id: '8c19ccc949c6d482b061be6a28e10782abf0e7af',
+            },
+            {
+              _index: 6,
+              _revision_number: 4,
+              message: 'Patch Set 4:\n\n(6 comments)',
+              date: '2016-09-28 13:36:33.000000000',
+              author,
+              id: 'e7bfdbc842f6b6d8064bc68e0f52b673f40c0ca5',
+            }
+        );
+        element.messages = messages;
+        const isAuthor = function(author, message) {
+          return message.author._account_id === author._account_id;
+        };
+        const isMarvin = isAuthor.bind(null, author);
+        flushAsynchronousOperations();
+        const messageElements = getMessages();
+        assert.equal(messageElements.length, messages.length);
+        assert.deepEqual(messageElements[1].message, messages[1]);
+        assert.deepEqual(messageElements[2].message, messages[2]);
+        assert.deepEqual(messageElements[1].comments.file1,
+            comments.file1.filter(isMarvin));
+        assert.deepEqual(messageElements[1].comments.file2,
+            comments.file2.filter(isMarvin));
+        assert.deepEqual(messageElements[2].comments, {});
+      });
+
+      test('messages without author do not throw', () => {
+        const messages = [{
+          _index: 5,
+          _revision_number: 4,
+          message: 'Uploaded patch set 4.',
+          date: '2016-09-28 13:36:33.000000000',
+          id: '8c19ccc949c6d482b061be6a28e10782abf0e7af',
+        }];
+        element.messages = messages;
+        flushAsynchronousOperations();
+        const messageEls = getMessages();
+        assert.equal(messageEls.length, 1);
+        assert.equal(messageEls[0].message.message, messages[0].message);
+      });
+
+      test('hide increment text if increment >= total remaining', () => {
+        // Test with stubbed return values, as _numRemaining and _getDelta have
+        // their own tests.
+        sandbox.stub(element, '_getDelta').returns(5);
+        const remainingStub = sandbox.stub(element, '_numRemaining').returns(6);
+        assert.isFalse(element._computeIncrementHidden(null, null, null));
+        remainingStub.restore();
+
+        sandbox.stub(element, '_numRemaining').returns(4);
+        assert.isTrue(element._computeIncrementHidden(null, null, null));
+      });
     });
 
-    teardown(() => {
-      sandbox.restore();
-    });
+    suite('gr-messages-list automate tests', () => {
+      let element;
+      let messages;
+      let sandbox;
+      let commentApiWrapper;
 
-    test('show some old messages', () => {
-      assert.isTrue(element.$.messageControlsContainer.hasAttribute('hidden'));
-      element.messages = _.times(26, randomMessage);
-      flushAsynchronousOperations();
-
-      assert.isFalse(element.$.messageControlsContainer.hasAttribute('hidden'));
-      assert.equal(getMessages().length, 20);
-      assert.equal(element.$.incrementMessagesBtn.innerText.toUpperCase()
-          .trim(), 'SHOW 5 MORE');
-      MockInteractions.tap(element.$.incrementMessagesBtn);
-      flushAsynchronousOperations();
-
-      assert.equal(getMessages().length, 25);
-      assert.equal(element.$.incrementMessagesBtn.innerText.toUpperCase()
-          .trim(), 'SHOW 1 MORE');
-      MockInteractions.tap(element.$.incrementMessagesBtn);
-      flushAsynchronousOperations();
-
-      assert.isTrue(element.$.messageControlsContainer.hasAttribute('hidden'));
-      assert.equal(getMessages().length, 26);
-    });
-
-    test('show all old messages', () => {
-      assert.isTrue(element.$.messageControlsContainer.hasAttribute('hidden'));
-      element.messages = _.times(26, randomMessage);
-      flushAsynchronousOperations();
-
-      assert.isFalse(element.$.messageControlsContainer.hasAttribute('hidden'));
-      assert.equal(getMessages().length, 20);
-      assert.equal(element.$.oldMessagesBtn.innerText.toUpperCase(),
-          'SHOW ALL 6 MESSAGES');
-      MockInteractions.tap(element.$.oldMessagesBtn);
-      flushAsynchronousOperations();
-
-      assert.equal(getMessages().length, 26);
-      assert.isTrue(element.$.messageControlsContainer.hasAttribute('hidden'));
-    });
-
-    test('message count respects automated', () => {
-      element.messages = _.times(10, randomAutomated)
-          .concat(_.times(11, randomMessage));
-      flushAsynchronousOperations();
-
-      assert.equal(element.$.oldMessagesBtn.innerText.toUpperCase(),
-          'SHOW 1 MESSAGE');
-      assert.isFalse(element.$.messageControlsContainer.hasAttribute('hidden'));
-      MockInteractions.tap(element.$.automatedMessageToggle);
-      flushAsynchronousOperations();
-
-      assert.isTrue(element.$.messageControlsContainer.hasAttribute('hidden'));
-    });
-
-    test('message count still respects non-automated on toggle', () => {
-      element.messages = _.times(10, randomMessage)
-          .concat(_.times(11, randomAutomated));
-      flushAsynchronousOperations();
-
-      assert.equal(element.$.oldMessagesBtn.innerText.toUpperCase(),
-          'SHOW 1 MESSAGE');
-      assert.isFalse(element.$.messageControlsContainer.hasAttribute('hidden'));
-      MockInteractions.tap(element.$.automatedMessageToggle);
-      flushAsynchronousOperations();
-
-      assert.equal(element.$.oldMessagesBtn.innerText.toUpperCase(),
-          'SHOW 1 MESSAGE');
-      assert.isFalse(element.$.messageControlsContainer.hasAttribute('hidden'));
-    });
-
-    test('show all messages respects expand', () => {
-      element.messages = _.times(10, randomAutomated)
-          .concat(_.times(11, randomMessage));
-      flushAsynchronousOperations();
-
-      MockInteractions.tap(element.shadowRoot
-          .querySelector('#collapse-messages')); // Expand all.
-      flushAsynchronousOperations();
-
-      let messages = getMessages();
-      assert.equal(messages.length, 20);
-      for (const message of messages) {
-        assert.isTrue(message._expanded);
-      }
-
-      MockInteractions.tap(element.$.oldMessagesBtn);
-      flushAsynchronousOperations();
-
-      messages = getMessages();
-      assert.equal(messages.length, 21);
-      for (const message of messages) {
-        assert.isTrue(message._expanded);
-      }
-    });
-
-    test('show all messages respects collapse', () => {
-      element.messages = _.times(10, randomAutomated)
-          .concat(_.times(11, randomMessage));
-      flushAsynchronousOperations();
-
-      MockInteractions.tap(element.shadowRoot
-          .querySelector('#collapse-messages')); // Expand all.
-      MockInteractions.tap(element.shadowRoot
-          .querySelector('#collapse-messages')); // Collapse all.
-      flushAsynchronousOperations();
-
-      let messages = getMessages();
-      assert.equal(messages.length, 20);
-      for (const message of messages) {
-        assert.isFalse(message._expanded);
-      }
-
-      MockInteractions.tap(element.$.oldMessagesBtn);
-      flushAsynchronousOperations();
-
-      messages = getMessages();
-      assert.equal(messages.length, 21);
-      for (const message of messages) {
-        assert.isFalse(message._expanded);
-      }
-    });
-
-    test('expand/collapse all', () => {
-      let allMessageEls = getMessages();
-      for (const message of allMessageEls) {
-        message._expanded = false;
-      }
-      MockInteractions.tap(allMessageEls[1]);
-      assert.isTrue(allMessageEls[1]._expanded);
-
-      MockInteractions.tap(element.shadowRoot
-          .querySelector('#collapse-messages'));
-      allMessageEls = getMessages();
-      for (const message of allMessageEls) {
-        assert.isTrue(message._expanded);
-      }
-
-      MockInteractions.tap(element.shadowRoot
-          .querySelector('#collapse-messages'));
-      allMessageEls = getMessages();
-      for (const message of allMessageEls) {
-        assert.isFalse(message._expanded);
-      }
-    });
-
-    test('expand/collapse from external keypress', () => {
-      MockInteractions.tap(element.shadowRoot
-          .querySelector('#collapse-messages'));
-      let allMessageEls = getMessages();
-      for (const message of allMessageEls) {
-        assert.isTrue(message._expanded);
-      }
-
-      // Expand/collapse all text also changes.
-      assert.equal(element.shadowRoot
-          .querySelector('#collapse-messages').textContent.trim(),
-      'Collapse all');
-
-      MockInteractions.tap(element.shadowRoot
-          .querySelector('#collapse-messages'));
-      allMessageEls = getMessages();
-      for (const message of allMessageEls) {
-        assert.isFalse(message._expanded);
-      }
-      // Expand/collapse all text also changes.
-      assert.equal(element.shadowRoot
-          .querySelector('#collapse-messages').textContent.trim(),
-      'Expand all');
-    });
-
-    test('hide messages does not appear when no automated messages', () => {
-      assert.isOk(element.shadowRoot
-          .querySelector('#automatedMessageToggleContainer[hidden]'));
-    });
-
-    test('scroll to message', () => {
-      const allMessageEls = getMessages();
-      for (const message of allMessageEls) {
-        message.set('message.expanded', false);
-      }
-
-      const scrollToStub = sandbox.stub(window, 'scrollTo');
-      const highlightStub = sandbox.stub(element, '_highlightEl');
-
-      element.scrollToMessage('invalid');
-
-      for (const message of allMessageEls) {
-        assert.isFalse(message._expanded,
-            'expected gr-message to not be expanded');
-      }
-
-      const messageID = messages[1].id;
-      element.scrollToMessage(messageID);
-      assert.isTrue(
-          element.$$('[data-message-id="' + messageID + '"]')._expanded);
-
-      assert.isTrue(scrollToStub.calledOnce);
-      assert.isTrue(highlightStub.calledOnce);
-    });
-
-    test('scroll to message offscreen', () => {
-      const scrollToStub = sandbox.stub(window, 'scrollTo');
-      const highlightStub = sandbox.stub(element, '_highlightEl');
-      element.messages = _.times(25, randomMessage);
-      flushAsynchronousOperations();
-      assert.isFalse(scrollToStub.called);
-      assert.isFalse(highlightStub.called);
-
-      const messageID = element.messages[1].id;
-      element.scrollToMessage(messageID);
-      assert.isTrue(scrollToStub.calledOnce);
-      assert.isTrue(highlightStub.calledOnce);
-      assert.equal(element._visibleMessages.length, 24);
-      assert.isTrue(
-          element.$$('[data-message-id="' + messageID + '"]')._expanded);
-    });
-
-    test('messages', () => {
-      const messages = [].concat(
-          randomMessage(),
-          {
-            _index: 5,
-            _revision_number: 4,
-            message: 'Uploaded patch set 4.',
-            date: '2016-09-28 13:36:33.000000000',
-            author,
-            id: '8c19ccc949c6d482b061be6a28e10782abf0e7af',
-          },
-          {
-            _index: 6,
-            _revision_number: 4,
-            message: 'Patch Set 4:\n\n(6 comments)',
-            date: '2016-09-28 13:36:33.000000000',
-            author,
-            id: 'e7bfdbc842f6b6d8064bc68e0f52b673f40c0ca5',
-          }
-      );
-      element.messages = messages;
-      const isAuthor = function(author, message) {
-        return message.author._account_id === author._account_id;
+      const getMessages = function() {
+        return Polymer.dom(element.root).querySelectorAll('gr-message');
       };
-      const isMarvin = isAuthor.bind(null, author);
-      flushAsynchronousOperations();
-      const messageElements = getMessages();
-      assert.equal(messageElements.length, messages.length);
-      assert.deepEqual(messageElements[1].message, messages[1]);
-      assert.deepEqual(messageElements[2].message, messages[2]);
-      assert.deepEqual(messageElements[1].comments.file1,
-          comments.file1.filter(isMarvin));
-      assert.deepEqual(messageElements[1].comments.file2,
-          comments.file2.filter(isMarvin));
-      assert.deepEqual(messageElements[2].comments, {});
-    });
+      const getHiddenMessages = function() {
+        return Polymer.dom(element.root).querySelectorAll('gr-message[hidden]');
+      };
 
-    test('messages without author do not throw', () => {
-      const messages = [{
-        _index: 5,
-        _revision_number: 4,
-        message: 'Uploaded patch set 4.',
-        date: '2016-09-28 13:36:33.000000000',
-        id: '8c19ccc949c6d482b061be6a28e10782abf0e7af',
-      }];
-      element.messages = messages;
-      flushAsynchronousOperations();
-      const messageEls = getMessages();
-      assert.equal(messageEls.length, 1);
-      assert.equal(messageEls[0].message.message, messages[0].message);
-    });
+      const randomMessageReviewer = {
+        reviewer: {},
+        date: '2016-01-13 20:30:33.038000',
+      };
 
-    test('hide increment text if increment >= total remaining', () => {
-      // Test with stubbed return values, as _numRemaining and _getDelta have
-      // their own tests.
-      sandbox.stub(element, '_getDelta').returns(5);
-      const remainingStub = sandbox.stub(element, '_numRemaining').returns(6);
-      assert.isFalse(element._computeIncrementHidden(null, null, null));
-      remainingStub.restore();
-
-      sandbox.stub(element, '_numRemaining').returns(4);
-      assert.isTrue(element._computeIncrementHidden(null, null, null));
-    });
-  });
-
-  suite('gr-messages-list automate tests', () => {
-    let element;
-    let messages;
-    let sandbox;
-    let commentApiWrapper;
-
-    const getMessages = function() {
-      return Polymer.dom(element.root).querySelectorAll('gr-message');
-    };
-    const getHiddenMessages = function() {
-      return Polymer.dom(element.root).querySelectorAll('gr-message[hidden]');
-    };
-
-    const randomMessageReviewer = {
-      reviewer: {},
-      date: '2016-01-13 20:30:33.038000',
-    };
-
-    setup(() => {
-      stub('gr-rest-api-interface', {
-        getConfig() { return Promise.resolve({}); },
-        getLoggedIn() { return Promise.resolve(false); },
-        getDiffComments() { return Promise.resolve({}); },
-        getDiffRobotComments() { return Promise.resolve({}); },
-        getDiffDrafts() { return Promise.resolve({}); },
-      });
-
-      sandbox = sinon.sandbox.create();
-      messages = _.times(2, randomAutomated);
-      messages.push(randomMessageReviewer);
-
-      // Element must be wrapped in an element with direct access to the
-      // comment API.
-      commentApiWrapper = fixture('basic');
-      element = commentApiWrapper.$.messagesList;
-      loadCommentSpy = sandbox.spy(commentApiWrapper.$.commentAPI, 'loadAll');
-      element.messages = messages;
-
-      // Stub methods on the changeComments object after changeComments has
-      // been initialized.
-      return commentApiWrapper.loadComments();
-    });
-
-    teardown(() => {
-      sandbox.restore();
-    });
-
-    test('hide autogenerated button is not hidden', () => {
-      assert.isNotOk(element.shadowRoot
-          .querySelector('#automatedMessageToggle[hidden]'));
-    });
-
-    test('autogenerated messages are not hidden initially', () => {
-      const allHiddenMessageEls = getHiddenMessages();
-
-      // There are no hidden messages.
-      assert.isFalse(!!allHiddenMessageEls.length);
-    });
-
-    test('autogenerated messages hidden after comments only toggle', () => {
-      let allHiddenMessageEls = getHiddenMessages();
-
-      element._hideAutomated = false;
-      MockInteractions.tap(element.$.automatedMessageToggle);
-      flushAsynchronousOperations();
-      allMessageEls = getMessages();
-      allHiddenMessageEls = getHiddenMessages();
-
-      // Autogenerated messages are now hidden.
-      assert.equal(allHiddenMessageEls.length, allMessageEls.length);
-    });
-
-    test('autogenerated messages not hidden after comments only toggle',
-        () => {
-          let allHiddenMessageEls = getHiddenMessages();
-
-          element._hideAutomated = true;
-          MockInteractions.tap(element.$.automatedMessageToggle);
-          allHiddenMessageEls = getHiddenMessages();
-
-          // Autogenerated messages are now hidden.
-          assert.isFalse(!!allHiddenMessageEls.length);
+      setup(() => {
+        stub('gr-rest-api-interface', {
+          getConfig() { return Promise.resolve({}); },
+          getLoggedIn() { return Promise.resolve(false); },
+          getDiffComments() { return Promise.resolve({}); },
+          getDiffRobotComments() { return Promise.resolve({}); },
+          getDiffDrafts() { return Promise.resolve({}); },
         });
 
-    test('_getDelta', () => {
-      let messages = [randomMessage()];
-      assert.equal(element._getDelta([], messages, false), 1);
-      assert.equal(element._getDelta([], messages, true), 1);
+        sandbox = sinon.sandbox.create();
+        messages = _.times(2, randomAutomated);
+        messages.push(randomMessageReviewer);
 
-      messages = _.times(7, randomMessage);
-      assert.equal(element._getDelta([], messages, false), 5);
-      assert.equal(element._getDelta([], messages, true), 5);
+        // Element must be wrapped in an element with direct access to the
+        // comment API.
+        commentApiWrapper = fixture('basic');
+        element = commentApiWrapper.$.messagesList;
+        loadCommentSpy = sandbox.spy(commentApiWrapper.$.commentAPI, 'loadAll');
+        element.messages = messages;
 
-      messages = _.times(4, randomMessage)
-          .concat(_.times(2, randomAutomated))
-          .concat(_.times(3, randomMessage));
+        // Stub methods on the changeComments object after changeComments has
+        // been initialized.
+        return commentApiWrapper.loadComments();
+      });
 
-      const dummyArr = _.times(2, randomMessage);
-      assert.equal(element._getDelta(dummyArr, messages, false), 5);
-      assert.equal(element._getDelta(dummyArr, messages, true), 7);
-    });
+      teardown(() => {
+        sandbox.restore();
+      });
 
-    test('_getHumanMessages', () => {
-      assert.equal(
-          element._getHumanMessages(_.times(5, randomAutomated)).length, 0);
-      assert.equal(
-          element._getHumanMessages(_.times(5, randomMessage)).length, 5);
+      test('hide autogenerated button is not hidden', () => {
+        assert.isNotOk(element.shadowRoot
+            .querySelector('#automatedMessageToggle[hidden]'));
+      });
 
-      let messages = _.shuffle(_.times(5, randomMessage)
-          .concat(_.times(5, randomAutomated)));
-      messages = element._getHumanMessages(messages);
-      assert.equal(messages.length, 5);
-      assert.isFalse(element._hasAutomatedMessages(messages));
-    });
+      test('autogenerated messages are not hidden initially', () => {
+        const allHiddenMessageEls = getHiddenMessages();
 
-    test('initially show only 20 messages', () => {
-      sandbox.stub(element.$.reporting, 'reportInteraction',
-          (eventName, details) => {
-            assert.equal(typeof(eventName), 'string');
-            if (details) {
-              assert.equal(typeof(details), 'object');
-            }
+        // There are no hidden messages.
+        assert.isFalse(!!allHiddenMessageEls.length);
+      });
+
+      test('autogenerated messages hidden after comments only toggle', () => {
+        let allHiddenMessageEls = getHiddenMessages();
+
+        element._hideAutomated = false;
+        MockInteractions.tap(element.$.automatedMessageToggle);
+        flushAsynchronousOperations();
+        allMessageEls = getMessages();
+        allHiddenMessageEls = getHiddenMessages();
+
+        // Autogenerated messages are now hidden.
+        assert.equal(allHiddenMessageEls.length, allMessageEls.length);
+      });
+
+      test('autogenerated messages not hidden after comments only toggle',
+          () => {
+            let allHiddenMessageEls = getHiddenMessages();
+
+            element._hideAutomated = true;
+            MockInteractions.tap(element.$.automatedMessageToggle);
+            allHiddenMessageEls = getHiddenMessages();
+
+            // Autogenerated messages are now hidden.
+            assert.isFalse(!!allHiddenMessageEls.length);
           });
-      const messages = Array.from(Array(23).keys())
-          .map(() => {
-            return {};
-          });
-      element._processedMessagesChanged(messages);
 
-      assert.equal(element._visibleMessages.length, 20);
-    });
+      test('_getDelta', () => {
+        let messages = [randomMessage()];
+        assert.equal(element._getDelta([], messages, false), 1);
+        assert.equal(element._getDelta([], messages, true), 1);
 
-    test('_computeLabelExtremes', () => {
-      const computeSpy = sandbox.spy(element, '_computeLabelExtremes');
+        messages = _.times(7, randomMessage);
+        assert.equal(element._getDelta([], messages, false), 5);
+        assert.equal(element._getDelta([], messages, true), 5);
 
-      element.labels = null;
-      assert.isTrue(computeSpy.calledOnce);
-      assert.deepEqual(computeSpy.lastCall.returnValue, {});
+        messages = _.times(4, randomMessage)
+            .concat(_.times(2, randomAutomated))
+            .concat(_.times(3, randomMessage));
 
-      element.labels = {};
-      assert.isTrue(computeSpy.calledTwice);
-      assert.deepEqual(computeSpy.lastCall.returnValue, {});
+        const dummyArr = _.times(2, randomMessage);
+        assert.equal(element._getDelta(dummyArr, messages, false), 5);
+        assert.equal(element._getDelta(dummyArr, messages, true), 7);
+      });
 
-      element.labels = {'my-label': {}};
-      assert.isTrue(computeSpy.calledThrice);
-      assert.deepEqual(computeSpy.lastCall.returnValue, {});
+      test('_getHumanMessages', () => {
+        assert.equal(
+            element._getHumanMessages(_.times(5, randomAutomated)).length, 0);
+        assert.equal(
+            element._getHumanMessages(_.times(5, randomMessage)).length, 5);
 
-      element.labels = {'my-label': {values: {}}};
-      assert.equal(computeSpy.callCount, 4);
-      assert.deepEqual(computeSpy.lastCall.returnValue, {});
+        let messages = _.shuffle(_.times(5, randomMessage)
+            .concat(_.times(5, randomAutomated)));
+        messages = element._getHumanMessages(messages);
+        assert.equal(messages.length, 5);
+        assert.isFalse(element._hasAutomatedMessages(messages));
+      });
 
-      element.labels = {'my-label': {values: {'-12': {}}}};
-      assert.equal(computeSpy.callCount, 5);
-      assert.deepEqual(computeSpy.lastCall.returnValue,
-          {'my-label': {min: -12, max: -12}});
+      test('initially show only 20 messages', () => {
+        sandbox.stub(element.$.reporting, 'reportInteraction',
+            (eventName, details) => {
+              assert.equal(typeof(eventName), 'string');
+              if (details) {
+                assert.equal(typeof(details), 'object');
+              }
+            });
+        const messages = Array.from(Array(23).keys())
+            .map(() => {
+              return {};
+            });
+        element._processedMessagesChanged(messages);
 
-      element.labels = {
-        'my-label': {values: {'-2': {}, '-1': {}, '0': {}, '+1': {}, '+2': {}}},
-      };
-      assert.equal(computeSpy.callCount, 6);
-      assert.deepEqual(computeSpy.lastCall.returnValue,
-          {'my-label': {min: -2, max: 2}});
+        assert.equal(element._visibleMessages.length, 20);
+      });
 
-      element.labels = {
-        'my-label': {values: {'-12': {}}},
-        'other-label': {values: {'-1': {}, ' 0': {}, '+1': {}}},
-      };
-      assert.equal(computeSpy.callCount, 7);
-      assert.deepEqual(computeSpy.lastCall.returnValue, {
-        'my-label': {min: -12, max: -12},
-        'other-label': {min: -1, max: 1},
+      test('_computeLabelExtremes', () => {
+        const computeSpy = sandbox.spy(element, '_computeLabelExtremes');
+
+        element.labels = null;
+        assert.isTrue(computeSpy.calledOnce);
+        assert.deepEqual(computeSpy.lastCall.returnValue, {});
+
+        element.labels = {};
+        assert.isTrue(computeSpy.calledTwice);
+        assert.deepEqual(computeSpy.lastCall.returnValue, {});
+
+        element.labels = {'my-label': {}};
+        assert.isTrue(computeSpy.calledThrice);
+        assert.deepEqual(computeSpy.lastCall.returnValue, {});
+
+        element.labels = {'my-label': {values: {}}};
+        assert.equal(computeSpy.callCount, 4);
+        assert.deepEqual(computeSpy.lastCall.returnValue, {});
+
+        element.labels = {'my-label': {values: {'-12': {}}}};
+        assert.equal(computeSpy.callCount, 5);
+        assert.deepEqual(computeSpy.lastCall.returnValue,
+            {'my-label': {min: -12, max: -12}});
+
+        element.labels = {
+          'my-label': {values: {'-2': {}, '-1': {}, '0': {}, '+1': {}, '+2': {}}},
+        };
+        assert.equal(computeSpy.callCount, 6);
+        assert.deepEqual(computeSpy.lastCall.returnValue,
+            {'my-label': {min: -2, max: 2}});
+
+        element.labels = {
+          'my-label': {values: {'-12': {}}},
+          'other-label': {values: {'-1': {}, ' 0': {}, '+1': {}}},
+        };
+        assert.equal(computeSpy.callCount, 7);
+        assert.deepEqual(computeSpy.lastCall.returnValue, {
+          'my-label': {min: -12, max: -12},
+          'other-label': {min: -1, max: 1},
+        });
       });
     });
   });
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.html b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.html
index 38b2fb9..8d900af 100644
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-related-changes-list.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-related-changes-list tests', () => {
+  suite('gr-related-changes-list tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog-it_test.html b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog-it_test.html
index 7d95323..ef0504e 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog-it_test.html
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog-it_test.html
@@ -24,6 +24,7 @@
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
 
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="../../plugins/gr-plugin-host/gr-plugin-host.html">
 <link rel="import" href="gr-reply-dialog.html">
@@ -43,7 +44,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-reply-dialog tests', () => {
+  suite('gr-reply-dialog tests', async () => {
+    await readyToTest();
     let element;
     let changeNum;
     let patchNum;
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.html b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.html
index 4c6c5bd..060df4ec 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.html
@@ -23,6 +23,8 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
+<link rel="import" href="/bower_components/iron-overlay-behavior/iron-overlay-manager.html">
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-reply-dialog.html">
 
@@ -54,7 +56,8 @@
     };
   }
 
-  suite('gr-reply-dialog tests', () => {
+  suite('gr-reply-dialog tests', async () => {
+    await readyToTest();
     let element;
     let changeNum;
     let patchNum;
diff --git a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.html b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.html
index 18f7bc5..60343e4 100644
--- a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-reviewer-list.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-reviewer-list tests', () => {
+  suite('gr-reviewer-list tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_test.html b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_test.html
index 3bc41ce..f703547 100644
--- a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-thread-list.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-thread-list tests', () => {
+  suite('gr-thread-list tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
     let threadElements;
diff --git a/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog_test.html b/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog_test.html
index 76377fb..3af5449 100644
--- a/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-upload-help-dialog.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-upload-help-dialog tests', () => {
+  suite('gr-upload-help-dialog tests', async () => {
+    await readyToTest();
     let element;
 
     setup(() => {
diff --git a/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown_test.html b/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown_test.html
index 9dafb74..0a11df1 100644
--- a/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown_test.html
+++ b/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-account-dropdown.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-account-dropdown tests', () => {
+  suite('gr-account-dropdown tests', async () => {
+    await readyToTest();
     let element;
 
     setup(() => {
diff --git a/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog_test.html b/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog_test.html
index dd4a71a..c87f8bb 100644
--- a/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog_test.html
+++ b/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-error-dialog.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-error-dialog tests', () => {
+  suite('gr-error-dialog tests', async () => {
+    await readyToTest();
     let element;
 
     setup(() => {
diff --git a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.html b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.html
index 8296804..2518d77 100644
--- a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.html
+++ b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.html
@@ -35,7 +35,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-error-manager tests', () => {
+  suite('gr-error-manager tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display_test.html b/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display_test.html
index e0d2d40..f682f0a 100644
--- a/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display_test.html
+++ b/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display_test.html
@@ -22,6 +22,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-key-binding-display.html">
 
@@ -34,7 +35,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-key-binding-display tests', () => {
+  suite('gr-key-binding-display tests', async () => {
+    await readyToTest();
     let element;
 
     setup(() => {
diff --git a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog_test.html b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog_test.html
index b713aa1..cc53db17 100644
--- a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog_test.html
+++ b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog_test.html
@@ -22,6 +22,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-keyboard-shortcuts-dialog.html">
 
@@ -34,7 +35,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-keyboard-shortcuts-dialog tests', () => {
+  suite('gr-keyboard-shortcuts-dialog tests', async () => {
+    await readyToTest();
     const kb = window.Gerrit.KeyboardShortcutBinder;
     let element;
 
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.html b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.html
index 403d9d5..da8b783 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.html
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-main-header.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-main-header tests', () => {
+  suite('gr-main-header tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation_test.html b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation_test.html
index ca44430..f58780c 100644
--- a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation_test.html
+++ b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation_test.html
@@ -23,10 +23,12 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 
 <script>
-  suite('gr-navigation tests', () => {
+  suite('gr-navigation tests', async () => {
+    await readyToTest();
     test('invalid patch ranges throw exceptions', () => {
       assert.throw(() => Gerrit.Nav.getUrlForChange('123', undefined, 12));
       assert.throw(() => Gerrit.Nav.getUrlForDiff('123', 'x.c', undefined, 12));
diff --git a/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting_test.html b/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting_test.html
index 11fe132..a4f7f8e 100644
--- a/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting_test.html
+++ b/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-reporting.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-reporting tests', () => {
+  suite('gr-reporting tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
     let clock;
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html b/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html
index 656f13a..3d93230 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-router.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-router tests', () => {
+  suite('gr-router tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.html b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.html
index 1b57ddb..cb8e142 100644
--- a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.html
+++ b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.html
@@ -19,6 +19,7 @@
 <link rel="import" href="../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html">
 <link rel="import" href="/bower_components/polymer/polymer.html">
 <link rel="import" href="../../shared/gr-autocomplete/gr-autocomplete.html">
+<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
 <link rel="import" href="../../../styles/shared-styles.html">
 
 <dom-module id="gr-search-bar">
@@ -47,6 +48,7 @@
           tab-complete
           vertical-offset="30"></gr-autocomplete>
     </form>
+    <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
   </template>
   <script src="gr-search-bar.js"></script>
 </dom-module>
diff --git a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.js b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.js
index 335813a..41caab5 100644
--- a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.js
+++ b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.js
@@ -57,7 +57,6 @@
     'is:assigned',
     'is:closed',
     'is:ignored',
-    'is:mergeable',
     'is:merged',
     'is:open',
     'is:owner',
@@ -97,8 +96,8 @@
   ];
 
   // All of the ops, with corresponding negations.
-  const SEARCH_OPERATORS_WITH_NEGATIONS =
-    SEARCH_OPERATORS.concat(SEARCH_OPERATORS.map(op => `-${op}`));
+  const SEARCH_OPERATORS_WITH_NEGATIONS_SET =
+    new Set(SEARCH_OPERATORS.concat(SEARCH_OPERATORS.map(op => `-${op}`)));
 
   const MAX_AUTOCOMPLETE_RESULTS = 10;
 
@@ -166,6 +165,27 @@
       };
     }
 
+    attached() {
+      super.attached();
+      this.$.restAPI.getConfig().then(serverConfig => {
+        const mergeability = serverConfig
+         && serverConfig.index
+          && serverConfig.index.mergeabilityComputationBehavior;
+        if (mergeability === 'API_REF_UPDATED_AND_CHANGE_REINDEX'
+        || mergeability === 'REF_UPDATED_AND_CHANGE_REINDEX') {
+          // add 'is:mergeable' to SEARCH_OPERATORS_WITH_NEGATIONS_SET
+          this._addOperator('is:mergeable');
+        }
+      });
+    }
+
+    _addOperator(name, include_neg = true) {
+      SEARCH_OPERATORS_WITH_NEGATIONS_SET.add(name);
+      if (include_neg) {
+        SEARCH_OPERATORS_WITH_NEGATIONS_SET.add(`-${name}`);
+      }
+    }
+
     keyboardShortcuts() {
       return {
         [this.Shortcut.SEARCH]: '_handleSearch',
@@ -200,9 +220,8 @@
       }
       const trimmedInput = this._inputVal && this._inputVal.trim();
       if (trimmedInput) {
-        const predefinedOpOnlyQuery = SEARCH_OPERATORS_WITH_NEGATIONS.some(
-            op => op.endsWith(':') && op === trimmedInput
-        );
+        const predefinedOpOnlyQuery = [...SEARCH_OPERATORS_WITH_NEGATIONS_SET]
+            .some(op => op.endsWith(':') && op === trimmedInput);
         if (predefinedOpOnlyQuery) {
           return;
         }
@@ -249,7 +268,7 @@
           return this.accountSuggestions(predicate, expression);
 
         default:
-          return Promise.resolve(SEARCH_OPERATORS_WITH_NEGATIONS
+          return Promise.resolve([...SEARCH_OPERATORS_WITH_NEGATIONS_SET]
               .filter(operator => operator.includes(input))
               .map(operator => { return {text: operator}; }));
       }
diff --git a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar_test.html b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar_test.html
index 9d60952..6a53bcc 100644
--- a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar_test.html
+++ b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar_test.html
@@ -23,13 +23,14 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="/bower_components/page/page.js"></script>
 
 <link rel="import" href="gr-search-bar.html">
 <script src="../../../scripts/util.js"></script>
 
-<script>void(0);</script>
+<script>void (0);</script>
 
 <test-fixture id="basic">
   <template>
@@ -38,16 +39,18 @@
 </test-fixture>
 
 <script>
-  suite('gr-search-bar tests', () => {
+  suite('gr-search-bar tests', async () => {
+    await readyToTest();
     const kb = window.Gerrit.KeyboardShortcutBinder;
     kb.bindShortcut(kb.Shortcut.SEARCH, '/');
 
     let element;
     let sandbox;
 
-    setup(() => {
+    setup(done => {
       sandbox = sinon.sandbox.create();
       element = fixture('basic');
+      flush(done);
     });
 
     teardown(() => {
@@ -188,6 +191,46 @@
           done();
         });
       });
+
+      test('Autocompltes without is:mergable when disabled', done => {
+        element._getSearchSuggestions('is:mergeab').then(s => {
+          assert.equal(s.length, 0);
+          done();
+        });
+      });
+    });
+
+    [
+      'API_REF_UPDATED_AND_CHANGE_REINDEX',
+      'REF_UPDATED_AND_CHANGE_REINDEX',
+    ].forEach(mergeability => {
+      suite(`mergeability as ${mergeability}`, () => {
+        setup(done => {
+          stub('gr-rest-api-interface', {
+            getConfig() {
+              return Promise.resolve({
+                index: {
+                  mergeabilityComputationBehavior: mergeability,
+                },
+              });
+            },
+          });
+
+          element = fixture('basic');
+          flush(done);
+        });
+
+        test('Autocompltes with is:mergable when enabled', done => {
+          element._getSearchSuggestions('is:mergeab').then(s => {
+            assert.equal(s.length, 2);
+            assert.equal(s[0].name, 'is:mergeable');
+            assert.equal(s[0].value, 'is:mergeable');
+            assert.equal(s[1].name, '-is:mergeable');
+            assert.equal(s[1].value, '-is:mergeable');
+            done();
+          });
+        });
+      });
     });
   });
-</script>
+</script>
\ No newline at end of file
diff --git a/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search_test.html b/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search_test.html
index 917c550..6fd00c7 100644
--- a/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search_test.html
+++ b/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-smart-search.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-smart-search tests', () => {
+  suite('gr-smart-search tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/custom-dark-theme_test.html b/polygerrit-ui/app/elements/custom-dark-theme_test.html
index 1cd042a..cd07a67 100644
--- a/polygerrit-ui/app/elements/custom-dark-theme_test.html
+++ b/polygerrit-ui/app/elements/custom-dark-theme_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../test/test-pre-setup.js"></script>
 <link rel="import" href="../test/common-test-setup.html"/>
 <link rel="import" href="./gr-app.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-app custom dark theme tests', () => {
+  suite('gr-app custom dark theme tests', async () => {
+    await readyToTest();
     let sandbox;
     let element;
 
diff --git a/polygerrit-ui/app/elements/custom-light-theme_test.html b/polygerrit-ui/app/elements/custom-light-theme_test.html
index 0cabd09..13b872e 100644
--- a/polygerrit-ui/app/elements/custom-light-theme_test.html
+++ b/polygerrit-ui/app/elements/custom-light-theme_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../test/test-pre-setup.js"></script>
 <link rel="import" href="../test/common-test-setup.html"/>
 <link rel="import" href="gr-app.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-app custom light theme tests', () => {
+  suite('gr-app custom light theme tests', async () => {
+    await readyToTest();
     let sandbox;
     let element;
 
diff --git a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.html b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.html
index 5a2193d..d4ab8f1 100644
--- a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.html
@@ -35,7 +35,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-apply-fix-dialog tests', () => {
+  suite('gr-apply-fix-dialog tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
     const ROBOT_COMMENT = {
diff --git a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api-mock.js b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api-mock.js
index 4abdb615..34abe76 100644
--- a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api-mock.js
+++ b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api-mock.js
@@ -17,38 +17,40 @@
 (function() {
   'use strict';
 
-  class CommentApiMock extends Polymer.GestureEventListeners(
-      Polymer.LegacyElementMixin(
-          Polymer.Element)) {
-    static get is() { return 'comment-api-mock'; }
+  window.addEventListener('HTMLImportsLoaded', () => {
+    class CommentApiMock extends Polymer.GestureEventListeners(
+        Polymer.LegacyElementMixin(
+            Polymer.Element)) {
+      static get is() { return 'comment-api-mock'; }
 
-    static get properties() {
-      return {
-        _changeComments: Object,
-      };
+      static get properties() {
+        return {
+          _changeComments: Object,
+        };
+      }
+
+      loadComments() {
+        return this._reloadComments();
+      }
+
+      /**
+       * For the purposes of the mock, _reloadDrafts is not included because its
+       * response is the same type as reloadComments, just makes less API
+       * requests. Since this is for test purposes/mocked data anyway, keep this
+       * file simpler by just using _reloadComments here instead.
+       */
+      _reloadDraftsWithCallback(e) {
+        return this._reloadComments().then(() => e.detail.resolve());
+      }
+
+      _reloadComments() {
+        return this.$.commentAPI.loadAll(this._changeNum)
+            .then(comments => {
+              this._changeComments = this.$.commentAPI._changeComments;
+            });
+      }
     }
 
-    loadComments() {
-      return this._reloadComments();
-    }
-
-    /**
-     * For the purposes of the mock, _reloadDrafts is not included because its
-     * response is the same type as reloadComments, just makes less API
-     * requests. Since this is for test purposes/mocked data anyway, keep this
-     * file simpler by just using _reloadComments here instead.
-     */
-    _reloadDraftsWithCallback(e) {
-      return this._reloadComments().then(() => e.detail.resolve());
-    }
-
-    _reloadComments() {
-      return this.$.commentAPI.loadAll(this._changeNum)
-          .then(comments => {
-            this._changeComments = this.$.commentAPI._changeComments;
-          });
-    }
-  }
-
-  customElements.define(CommentApiMock.is, CommentApiMock);
+    customElements.define(CommentApiMock.is, CommentApiMock);
+  });
 })();
diff --git a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_test.html b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_test.html
index 6f96a38..f2f7c0f 100644
--- a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 
 <link rel="import" href="./gr-comment-api.html">
@@ -36,7 +37,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-comment-api tests', () => {
+  suite('gr-comment-api tests', async () => {
+    await readyToTest();
     const PARENT = 'PARENT';
 
     let element;
diff --git a/polygerrit-ui/app/elements/diff/gr-coverage-layer/gr-coverage-layer_test.html b/polygerrit-ui/app/elements/diff/gr-coverage-layer/gr-coverage-layer_test.html
index 99c583d..ec68106 100644
--- a/polygerrit-ui/app/elements/diff/gr-coverage-layer/gr-coverage-layer_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-coverage-layer/gr-coverage-layer_test.html
@@ -24,6 +24,7 @@
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
 <script src="../gr-diff/gr-diff-line.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 
 <link rel="import" href="gr-coverage-layer.html">
@@ -37,7 +38,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-coverage-layer', () => {
+  suite('gr-coverage-layer', async () => {
+    await readyToTest();
     let element;
 
     setup(() => {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified_test.html b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified_test.html
index 4c44414..4f0a94f 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="../../../scripts/util.js"></script>
 <script src="../gr-diff/gr-diff-line.js"></script>
@@ -34,7 +35,8 @@
 <script>void(0);</script>
 
 <script>
-  suite('GrDiffBuilderUnified tests', () => {
+  suite('GrDiffBuilderUnified tests', async () => {
+    await readyToTest();
     let prefs;
     let outputEl;
     let diffBuilder;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html
index 320909c..838ac68 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="../../../scripts/util.js"></script>
 <script src="../gr-diff/gr-diff-line.js"></script>
@@ -59,7 +60,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-diff-builder tests', () => {
+  suite('gr-diff-builder tests', async () => {
+    await readyToTest();
     let prefs;
     let element;
     let builder;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.html b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.html
index 24ca3d1..cd92d7e 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="../../../scripts/util.js"></script>
 
@@ -49,7 +50,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-diff-cursor tests', () => {
+  suite('gr-diff-cursor tests', async () => {
+    await readyToTest();
     let sandbox;
     let cursorElement;
     let diffElement;
@@ -387,25 +389,25 @@
         done();
       });
     });
-  });
 
-  suite('gr-diff-cursor event tests', () => {
-    let sandbox;
-    let someEmptyDiv;
+    suite('gr-diff-cursor event tests', () => {
+      let sandbox;
+      let someEmptyDiv;
 
-    setup(() => {
-      sandbox = sinon.sandbox.create();
-      someEmptyDiv = fixture('empty');
-    });
-
-    teardown(() => sandbox.restore());
-
-    test('ready is fired after component is rendered', done => {
-      const cursorElement = document.createElement('gr-diff-cursor');
-      cursorElement.addEventListener('ready', () => {
-        done();
+      setup(() => {
+        sandbox = sinon.sandbox.create();
+        someEmptyDiv = fixture('empty');
       });
-      someEmptyDiv.appendChild(cursorElement);
+
+      teardown(() => sandbox.restore());
+
+      test('ready is fired after component is rendered', done => {
+        const cursorElement = document.createElement('gr-diff-cursor');
+        cursorElement.addEventListener('ready', () => {
+          done();
+        });
+        someEmptyDiv.appendChild(cursorElement);
+      });
     });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-annotation_test.html b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-annotation_test.html
index c7fe997..79e4036 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-annotation_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-annotation_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="gr-annotation.js"></script>
 
@@ -36,7 +37,8 @@
 </test-fixture>
 
 <script>
-  suite('annotation', () => {
+  suite('annotation', async () => {
+    await readyToTest();
     let str;
     let parent;
     let textNode;
@@ -201,9 +203,17 @@
     suite('annotateWithElement', () => {
       const fullText = '01234567890123456789';
       let mockSanitize;
+      let originalSanitizeDOMValue;
 
       setup(() => {
-        mockSanitize = sandbox.spy(window.Polymer, 'sanitizeDOMValue');
+        originalSanitizeDOMValue = window.Polymer.sanitizeDOMValue;
+        assert.isDefined(originalSanitizeDOMValue);
+        mockSanitize = sandbox.spy(originalSanitizeDOMValue);
+        window.Polymer.sanitizeDOMValue = mockSanitize;
+      });
+
+      teardown(() => {
+        window.Polymer.sanitizeDOMValue = originalSanitizeDOMValue;
       });
 
       test('annotates when fully contained', () => {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.html b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.html
index c1a696c..6712ba2 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-diff-highlight.html">
 
@@ -147,7 +148,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-diff-highlight', () => {
+  suite('gr-diff-highlight', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.html b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.html
index 5aee282..fd93cb4 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 
 <link rel="import" href="gr-diff-host.html">
@@ -36,7 +37,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-diff-host tests', () => {
+  suite('gr-diff-host tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
     let getLoggedIn;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector_test.html b/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector_test.html
index 333a3d6..2f3d262 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="/bower_components/page/page.js"></script>
 <script src="../../../scripts/util.js"></script>
@@ -38,7 +39,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-diff-mode-selector tests', () => {
+  suite('gr-diff-mode-selector tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor_test.html b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor_test.html
index 8eaaa4c..9b3f3b2 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-diff-processor.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-diff-processor tests', () => {
+  suite('gr-diff-processor tests', async () => {
+    await readyToTest();
     const WHOLE_FILE = -1;
     const loremIpsum =
         'Lorem ipsum dolor sit amet, ei nonumes vituperata ius. ' +
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection_test.html b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection_test.html
index 6fe319d..a8e85e2 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-diff-selection.html">
 
@@ -107,7 +108,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-diff-selection', () => {
+  suite('gr-diff-selection', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
index 6c20a6a..8e396f1 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
@@ -75,6 +75,12 @@
       header {
         padding: var(--spacing-s) var(--spacing-l);
       }
+      .changeNumberColon {
+        color: transparent;
+      }
+      .headerSubject {
+        margin-right: var(--spacing-m);
+      }
       .patchRangeLeft {
         align-items: center;
         display: flex;
@@ -215,16 +221,15 @@
     >
       <header>
         <h3>
-          <a href$="[[_computeChangePath(_change, _patchRange.*, _change.revisions)]]">
-            [[_changeNum]]</a><span>:</span>
-          <span>[[_change.subject]]</span>
-          <span class="dash">—</span>
+          <a href$="[[_computeChangePath(_change, _patchRange.*, _change.revisions)]]">[[_changeNum]]</a><!--
+       --><span class="changeNumberColon">:</span>
+          <span class="headerSubject">[[_change.subject]]</span>
           <input id="reviewed"
               class="reviewed hideOnEdit"
               type="checkbox"
               on-change="_handleReviewedChange"
-              hidden$="[[!_loggedIn]]" hidden>
-          <div class="jumpToFileContainer">
+              hidden$="[[!_loggedIn]]" hidden><!--
+       --><div class="jumpToFileContainer">
             <gr-dropdown-list
                 id="dropdown"
                 value="[[_path]]"
@@ -289,6 +294,7 @@
           <span class$="blameLoader [[_computeBlameLoaderClass(_isImageDiff, _path)]]">
             <gr-button
                 link
+                title="[[createTitle(Shortcut.TOGGLE_BLAME, ShortcutSection.DIFFS)]]"
                 disabled="[[_isBlameLoading]]"
                 on-click="_toggleBlame">[[_computeBlameToggleLabel(_isBlameLoaded, _isBlameLoading)]]</gr-button>
             <span class="separator"></span>
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
index e91c8b0..591e69e1 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
@@ -262,6 +262,7 @@
         [this.Shortcut.TOGGLE_FILE_REVIEWED]: '_handleToggleFileReviewed',
         [this.Shortcut.EXPAND_ALL_DIFF_CONTEXT]: '_handleExpandAllDiffContext',
         [this.Shortcut.NEXT_UNREVIEWED_FILE]: '_handleNextUnreviewedFile',
+        [this.Shortcut.TOGGLE_BLAME]: '_toggleBlame',
 
         // Final two are actually handled by gr-comment-thread.
         [this.Shortcut.EXPAND_ALL_COMMENT_THREADS]: null,
@@ -1140,7 +1141,10 @@
      * Load and display blame information if it has not already been loaded.
      * Otherwise hide it.
      */
-    _toggleBlame() {
+    _toggleBlame(e) {
+      if (this.shouldSuppressKeyboardShortcut(e) ||
+          this.modifierPressed(e)) { return; }
+
       if (this._isBlameLoaded) {
         this.$.diffHost.clearBlame();
         return;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html
index 1c32407..cbbb802 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="/bower_components/page/page.js"></script>
 <script src="../../../scripts/util.js"></script>
@@ -44,477 +45,100 @@
 </test-fixture>
 
 <script>
-  suite('gr-diff-view tests', () => {
-    const kb = window.Gerrit.KeyboardShortcutBinder;
-    kb.bindShortcut(kb.Shortcut.LEFT_PANE, 'shift+left');
-    kb.bindShortcut(kb.Shortcut.RIGHT_PANE, 'shift+right');
-    kb.bindShortcut(kb.Shortcut.NEXT_LINE, 'j', 'down');
-    kb.bindShortcut(kb.Shortcut.PREV_LINE, 'k', 'up');
-    kb.bindShortcut(kb.Shortcut.NEXT_FILE_WITH_COMMENTS, 'shift+j');
-    kb.bindShortcut(kb.Shortcut.PREV_FILE_WITH_COMMENTS, 'shift+k');
-    kb.bindShortcut(kb.Shortcut.NEW_COMMENT, 'c');
-    kb.bindShortcut(kb.Shortcut.SAVE_COMMENT, 'ctrl+s');
-    kb.bindShortcut(kb.Shortcut.NEXT_FILE, ']');
-    kb.bindShortcut(kb.Shortcut.PREV_FILE, '[');
-    kb.bindShortcut(kb.Shortcut.NEXT_CHUNK, 'n');
-    kb.bindShortcut(kb.Shortcut.NEXT_COMMENT_THREAD, 'shift+n');
-    kb.bindShortcut(kb.Shortcut.PREV_CHUNK, 'p');
-    kb.bindShortcut(kb.Shortcut.PREV_COMMENT_THREAD, 'shift+p');
-    kb.bindShortcut(kb.Shortcut.OPEN_REPLY_DIALOG, 'a');
-    kb.bindShortcut(kb.Shortcut.TOGGLE_LEFT_PANE, 'shift+a');
-    kb.bindShortcut(kb.Shortcut.UP_TO_CHANGE, 'u');
-    kb.bindShortcut(kb.Shortcut.OPEN_DIFF_PREFS, ',');
-    kb.bindShortcut(kb.Shortcut.TOGGLE_DIFF_MODE, 'm');
-    kb.bindShortcut(kb.Shortcut.TOGGLE_FILE_REVIEWED, 'r');
-    kb.bindShortcut(kb.Shortcut.EXPAND_ALL_DIFF_CONTEXT, 'shift+x');
-    kb.bindShortcut(kb.Shortcut.EXPAND_ALL_COMMENT_THREADS, 'e');
-    kb.bindShortcut(kb.Shortcut.COLLAPSE_ALL_COMMENT_THREADS, 'shift+e');
-    kb.bindShortcut(kb.Shortcut.NEXT_UNREVIEWED_FILE, 'shift+m');
+  suite('gr-diff-view tests', async () => {
+    await readyToTest();
 
-    let element;
-    let sandbox;
+    suite('basic tests', async () => {
+      const kb = window.Gerrit.KeyboardShortcutBinder;
+      kb.bindShortcut(kb.Shortcut.LEFT_PANE, 'shift+left');
+      kb.bindShortcut(kb.Shortcut.RIGHT_PANE, 'shift+right');
+      kb.bindShortcut(kb.Shortcut.NEXT_LINE, 'j', 'down');
+      kb.bindShortcut(kb.Shortcut.PREV_LINE, 'k', 'up');
+      kb.bindShortcut(kb.Shortcut.NEXT_FILE_WITH_COMMENTS, 'shift+j');
+      kb.bindShortcut(kb.Shortcut.PREV_FILE_WITH_COMMENTS, 'shift+k');
+      kb.bindShortcut(kb.Shortcut.NEW_COMMENT, 'c');
+      kb.bindShortcut(kb.Shortcut.SAVE_COMMENT, 'ctrl+s');
+      kb.bindShortcut(kb.Shortcut.NEXT_FILE, ']');
+      kb.bindShortcut(kb.Shortcut.PREV_FILE, '[');
+      kb.bindShortcut(kb.Shortcut.NEXT_CHUNK, 'n');
+      kb.bindShortcut(kb.Shortcut.NEXT_COMMENT_THREAD, 'shift+n');
+      kb.bindShortcut(kb.Shortcut.PREV_CHUNK, 'p');
+      kb.bindShortcut(kb.Shortcut.PREV_COMMENT_THREAD, 'shift+p');
+      kb.bindShortcut(kb.Shortcut.OPEN_REPLY_DIALOG, 'a');
+      kb.bindShortcut(kb.Shortcut.TOGGLE_LEFT_PANE, 'shift+a');
+      kb.bindShortcut(kb.Shortcut.UP_TO_CHANGE, 'u');
+      kb.bindShortcut(kb.Shortcut.OPEN_DIFF_PREFS, ',');
+      kb.bindShortcut(kb.Shortcut.TOGGLE_DIFF_MODE, 'm');
+      kb.bindShortcut(kb.Shortcut.TOGGLE_FILE_REVIEWED, 'r');
+      kb.bindShortcut(kb.Shortcut.EXPAND_ALL_DIFF_CONTEXT, 'shift+x');
+      kb.bindShortcut(kb.Shortcut.EXPAND_ALL_COMMENT_THREADS, 'e');
+      kb.bindShortcut(kb.Shortcut.COLLAPSE_ALL_COMMENT_THREADS, 'shift+e');
+      kb.bindShortcut(kb.Shortcut.NEXT_UNREVIEWED_FILE, 'shift+m');
 
-    const PARENT = 'PARENT';
+      let element;
+      let sandbox;
 
-    function getFilesFromFileList(fileList) {
-      const changeFilesByPath = fileList.reduce((files, path) => {
-        files[path] = {};
-        return files;
-      }, {});
-      return {
-        sortedFileList: fileList,
-        changeFilesByPath,
-      };
-    }
+      const PARENT = 'PARENT';
 
-    setup(() => {
-      sandbox = sinon.sandbox.create();
-
-      stub('gr-rest-api-interface', {
-        getConfig() { return Promise.resolve({change: {}}); },
-        getLoggedIn() { return Promise.resolve(false); },
-        getProjectConfig() { return Promise.resolve({}); },
-        getDiffChangeDetail() { return Promise.resolve({}); },
-        getChangeFiles() { return Promise.resolve({}); },
-        saveFileReviewed() { return Promise.resolve(); },
-        getDiffComments() { return Promise.resolve({}); },
-        getDiffRobotComments() { return Promise.resolve({}); },
-        getDiffDrafts() { return Promise.resolve({}); },
-        getReviewedFiles() { return Promise.resolve([]); },
-      });
-      element = fixture('basic');
-      return element._loadComments();
-    });
-
-    teardown(() => {
-      sandbox.restore();
-    });
-
-    test('params change triggers diffViewDisplayed()', () => {
-      sandbox.stub(element.$.reporting, 'diffViewDisplayed');
-      sandbox.stub(element.$.diffHost, 'reload').returns(Promise.resolve());
-      sandbox.spy(element, '_paramsChanged');
-      element.params = {
-        view: Gerrit.Nav.View.DIFF,
-        changeNum: '42',
-        patchNum: '2',
-        basePatchNum: '1',
-        path: '/COMMIT_MSG',
-      };
-
-      return element._paramsChanged.returnValues[0].then(() => {
-        assert.isTrue(element.$.reporting.diffViewDisplayed.calledOnce);
-      });
-    });
-
-    test('toggle left diff with a hotkey', () => {
-      const toggleLeftDiffStub = sandbox.stub(
-          element.$.diffHost, 'toggleLeftDiff');
-      MockInteractions.pressAndReleaseKeyOn(element, 65, 'shift', 'a');
-      assert.isTrue(toggleLeftDiffStub.calledOnce);
-    });
-
-    test('keyboard shortcuts', () => {
-      element._changeNum = '42';
-      element._patchRange = {
-        basePatchNum: PARENT,
-        patchNum: '10',
-      };
-      element._change = {
-        _number: 42,
-        revisions: {
-          a: {_number: 10, commit: {parents: []}},
-        },
-      };
-      element._files = getFilesFromFileList(
-          ['chell.go', 'glados.txt', 'wheatley.md']);
-      element._path = 'glados.txt';
-      element.changeViewState.selectedFileIndex = 1;
-      element._loggedIn = true;
-
-      const diffNavStub = sandbox.stub(Gerrit.Nav, 'navigateToDiff');
-      const changeNavStub = sandbox.stub(Gerrit.Nav, 'navigateToChange');
-
-      MockInteractions.pressAndReleaseKeyOn(element, 85, null, 'u');
-      assert(changeNavStub.lastCall.calledWith(element._change),
-          'Should navigate to /c/42/');
-
-      MockInteractions.pressAndReleaseKeyOn(element, 221, null, ']');
-      assert(diffNavStub.lastCall.calledWith(element._change, 'wheatley.md',
-          '10', PARENT), 'Should navigate to /c/42/10/wheatley.md');
-      element._path = 'wheatley.md';
-      assert.equal(element.changeViewState.selectedFileIndex, 2);
-      assert.isTrue(element._loading);
-
-      MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
-      assert(diffNavStub.lastCall.calledWith(element._change, 'glados.txt',
-          '10', PARENT), 'Should navigate to /c/42/10/glados.txt');
-      element._path = 'glados.txt';
-      assert.equal(element.changeViewState.selectedFileIndex, 1);
-      assert.isTrue(element._loading);
-
-      MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
-      assert(diffNavStub.lastCall.calledWith(element._change, 'chell.go', '10',
-          PARENT), 'Should navigate to /c/42/10/chell.go');
-      element._path = 'chell.go';
-      assert.equal(element.changeViewState.selectedFileIndex, 0);
-      assert.isTrue(element._loading);
-
-      MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
-      assert(changeNavStub.lastCall.calledWith(element._change),
-          'Should navigate to /c/42/');
-      assert.equal(element.changeViewState.selectedFileIndex, 0);
-      assert.isTrue(element._loading);
-
-      const showPrefsStub =
-          sandbox.stub(element.$.diffPreferencesDialog, 'open',
-              () => Promise.resolve());
-
-      MockInteractions.pressAndReleaseKeyOn(element, 188, null, ',');
-      assert(showPrefsStub.calledOnce);
-
-      element.disableDiffPrefs = true;
-      MockInteractions.pressAndReleaseKeyOn(element, 188, null, ',');
-      assert(showPrefsStub.calledOnce);
-
-      let scrollStub = sandbox.stub(element.$.cursor, 'moveToNextChunk');
-      MockInteractions.pressAndReleaseKeyOn(element, 78, null, 'n');
-      assert(scrollStub.calledOnce);
-
-      scrollStub = sandbox.stub(element.$.cursor, 'moveToPreviousChunk');
-      MockInteractions.pressAndReleaseKeyOn(element, 80, null, 'p');
-      assert(scrollStub.calledOnce);
-
-      scrollStub = sandbox.stub(element.$.cursor, 'moveToNextCommentThread');
-      MockInteractions.pressAndReleaseKeyOn(element, 78, 'shift', 'n');
-      assert(scrollStub.calledOnce);
-
-      scrollStub = sandbox.stub(element.$.cursor,
-          'moveToPreviousCommentThread');
-      MockInteractions.pressAndReleaseKeyOn(element, 80, 'shift', 'p');
-      assert(scrollStub.calledOnce);
-
-      const computeContainerClassStub = sandbox.stub(element.$.diffHost.$.diff,
-          '_computeContainerClass');
-      MockInteractions.pressAndReleaseKeyOn(element, 74, null, 'j');
-      assert(computeContainerClassStub.lastCall.calledWithExactly(
-          false, 'SIDE_BY_SIDE', true));
-
-      MockInteractions.pressAndReleaseKeyOn(element, 27, null, 'esc');
-      assert(computeContainerClassStub.lastCall.calledWithExactly(
-          false, 'SIDE_BY_SIDE', false));
-
-      sandbox.stub(element, '_setReviewed');
-      element.$.reviewed.checked = false;
-      MockInteractions.pressAndReleaseKeyOn(element, 82, 'shift', 'r');
-      assert.isFalse(element._setReviewed.called);
-
-      MockInteractions.pressAndReleaseKeyOn(element, 82, null, 'r');
-      assert.isTrue(element._setReviewed.called);
-      assert.equal(element._setReviewed.lastCall.args[0], true);
-    });
-
-    test('shift+x shortcut expands all diff context', () => {
-      const expandStub = sandbox.stub(element.$.diffHost, 'expandAllContext');
-      MockInteractions.pressAndReleaseKeyOn(element, 88, 'shift', 'x');
-      flushAsynchronousOperations();
-      assert.isTrue(expandStub.called);
-    });
-
-    test('keyboard shortcuts with patch range', () => {
-      element._changeNum = '42';
-      element._patchRange = {
-        basePatchNum: '5',
-        patchNum: '10',
-      };
-      element._change = {
-        _number: 42,
-        revisions: {
-          a: {_number: 10, commit: {parents: []}},
-          b: {_number: 5, commit: {parents: []}},
-        },
-      };
-      element._files = getFilesFromFileList(
-          ['chell.go', 'glados.txt', 'wheatley.md']);
-      element._path = 'glados.txt';
-
-      const diffNavStub = sandbox.stub(Gerrit.Nav, 'navigateToDiff');
-      const changeNavStub = sandbox.stub(Gerrit.Nav, 'navigateToChange');
-
-      MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
-      assert.isTrue(changeNavStub.notCalled, 'The `a` keyboard shortcut ' +
-          'should only work when the user is logged in.');
-      assert.isNull(window.sessionStorage.getItem(
-          'changeView.showReplyDialog'));
-
-      element._loggedIn = true;
-      MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
-      assert.isTrue(element.changeViewState.showReplyDialog);
-
-      assert(changeNavStub.lastCall.calledWithExactly(element._change, '10',
-          '5'), 'Should navigate to /c/42/5..10');
-
-      MockInteractions.pressAndReleaseKeyOn(element, 85, null, 'u');
-      assert(changeNavStub.lastCall.calledWithExactly(element._change, '10',
-          '5'), 'Should navigate to /c/42/5..10');
-
-      MockInteractions.pressAndReleaseKeyOn(element, 221, null, ']');
-      assert.isTrue(element._loading);
-      assert(diffNavStub.lastCall.calledWithExactly(element._change,
-          'wheatley.md', '10', '5'),
-      'Should navigate to /c/42/5..10/wheatley.md');
-      element._path = 'wheatley.md';
-
-      MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
-      assert.isTrue(element._loading);
-      assert(diffNavStub.lastCall.calledWithExactly(element._change,
-          'glados.txt', '10', '5'),
-      'Should navigate to /c/42/5..10/glados.txt');
-      element._path = 'glados.txt';
-
-      MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
-      assert.isTrue(element._loading);
-      assert(diffNavStub.lastCall.calledWithExactly(
-          element._change,
-          'chell.go',
-          '10',
-          '5'),
-      'Should navigate to /c/42/5..10/chell.go');
-      element._path = 'chell.go';
-
-      MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
-      assert.isTrue(element._loading);
-      assert(changeNavStub.lastCall.calledWithExactly(element._change, '10',
-          '5'),
-      'Should navigate to /c/42/5..10');
-    });
-
-    test('keyboard shortcuts with old patch number', () => {
-      element._changeNum = '42';
-      element._patchRange = {
-        basePatchNum: PARENT,
-        patchNum: '1',
-      };
-      element._change = {
-        _number: 42,
-        revisions: {
-          a: {_number: 1, commit: {parents: []}},
-          b: {_number: 2, commit: {parents: []}},
-        },
-      };
-      element._files = getFilesFromFileList(
-          ['chell.go', 'glados.txt', 'wheatley.md']);
-      element._path = 'glados.txt';
-
-      const diffNavStub = sandbox.stub(Gerrit.Nav, 'navigateToDiff');
-      const changeNavStub = sandbox.stub(Gerrit.Nav, 'navigateToChange');
-
-      MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
-      assert.isTrue(changeNavStub.notCalled, 'The `a` keyboard shortcut ' +
-          'should only work when the user is logged in.');
-      assert.isNull(window.sessionStorage.getItem(
-          'changeView.showReplyDialog'));
-
-      element._loggedIn = true;
-      MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
-      assert.isTrue(element.changeViewState.showReplyDialog);
-
-      assert(changeNavStub.lastCall.calledWithExactly(element._change, '1',
-          PARENT), 'Should navigate to /c/42/1');
-
-      MockInteractions.pressAndReleaseKeyOn(element, 85, null, 'u');
-      assert(changeNavStub.lastCall.calledWithExactly(element._change, '1',
-          PARENT), 'Should navigate to /c/42/1');
-
-      MockInteractions.pressAndReleaseKeyOn(element, 221, null, ']');
-      assert(diffNavStub.lastCall.calledWithExactly(element._change,
-          'wheatley.md', '1', PARENT),
-      'Should navigate to /c/42/1/wheatley.md');
-      element._path = 'wheatley.md';
-
-      MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
-      assert(diffNavStub.lastCall.calledWithExactly(element._change,
-          'glados.txt', '1', PARENT),
-      'Should navigate to /c/42/1/glados.txt');
-      element._path = 'glados.txt';
-
-      MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
-      assert(diffNavStub.lastCall.calledWithExactly(
-          element._change,
-          'chell.go',
-          '1',
-          PARENT), 'Should navigate to /c/42/1/chell.go');
-      element._path = 'chell.go';
-
-      MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
-      assert(changeNavStub.lastCall.calledWithExactly(element._change, '1',
-          PARENT), 'Should navigate to /c/42/1');
-    });
-
-    suite('diff prefs hidden', () => {
-      test('when no prefs or logged out', () => {
-        element.disableDiffPrefs = false;
-        element._loggedIn = false;
-        flushAsynchronousOperations();
-        assert.isTrue(element.$.diffPrefsContainer.hidden);
-
-        element._loggedIn = true;
-        flushAsynchronousOperations();
-        assert.isTrue(element.$.diffPrefsContainer.hidden);
-
-        element._loggedIn = false;
-        element._prefs = {font_size: '12'};
-        flushAsynchronousOperations();
-        assert.isTrue(element.$.diffPrefsContainer.hidden);
-
-        element._loggedIn = true;
-        flushAsynchronousOperations();
-        assert.isFalse(element.$.diffPrefsContainer.hidden);
-      });
-
-      test('when disableDiffPrefs is set', () => {
-        element._loggedIn = true;
-        element._prefs = {font_size: '12'};
-        element.disableDiffPrefs = false;
-        flushAsynchronousOperations();
-
-        assert.isFalse(element.$.diffPrefsContainer.hidden);
-        element.disableDiffPrefs = true;
-        flushAsynchronousOperations();
-
-        assert.isTrue(element.$.diffPrefsContainer.hidden);
-      });
-    });
-
-    test('prefsButton opens gr-diff-preferences', () => {
-      const handlePrefsTapSpy = sandbox.spy(element, '_handlePrefsTap');
-      const overlayOpenStub = sandbox.stub(element.$.diffPreferencesDialog,
-          'open');
-      const prefsButton =
-          Polymer.dom(element.root).querySelector('.prefsButton');
-
-      MockInteractions.tap(prefsButton);
-
-      assert.isTrue(handlePrefsTapSpy.called);
-      assert.isTrue(overlayOpenStub.called);
-    });
-
-    test('_computeCommentString', done => {
-      loadCommentSpy = sandbox.spy(element.$.commentAPI, 'loadAll');
-      const path = '/test';
-      element.$.commentAPI.loadAll().then(comments => {
-        const commentCountStub =
-            sandbox.stub(comments, 'computeCommentCount');
-        const unresolvedCountStub =
-            sandbox.stub(comments, 'computeUnresolvedNum');
-        commentCountStub.withArgs(1, path).returns(0);
-        commentCountStub.withArgs(2, path).returns(1);
-        commentCountStub.withArgs(3, path).returns(2);
-        commentCountStub.withArgs(4, path).returns(0);
-        unresolvedCountStub.withArgs(1, path).returns(1);
-        unresolvedCountStub.withArgs(2, path).returns(0);
-        unresolvedCountStub.withArgs(3, path).returns(2);
-        unresolvedCountStub.withArgs(4, path).returns(0);
-
-        assert.equal(element._computeCommentString(comments, 1, path, {}),
-            '1 unresolved');
-        assert.equal(
-            element._computeCommentString(comments, 2, path, {status: 'M'}),
-            '1 comment');
-        assert.equal(
-            element._computeCommentString(comments, 2, path, {status: 'U'}),
-            'no changes, 1 comment');
-        assert.equal(
-            element._computeCommentString(comments, 3, path, {status: 'A'}),
-            '2 comments, 2 unresolved');
-        assert.equal(
-            element._computeCommentString(comments, 4, path, {status: 'M'}), '');
-        assert.equal(
-            element._computeCommentString(comments, 4, path, {status: 'U'}),
-            'no changes');
-        done();
-      });
-    });
-
-    suite('url params', () => {
-      setup(() => {
-        sandbox.stub(
-            Gerrit.Nav,
-            'getUrlForDiff',
-            (c, p, pn, bpn) => `${c._number}-${p}-${pn}-${bpn}`);
-        sandbox.stub(
-            Gerrit.Nav
-            , 'getUrlForChange',
-            (c, pn, bpn) => `${c._number}-${pn}-${bpn}`);
-      });
-
-      test('_formattedFiles', () => {
-        element._changeNum = '42';
-        element._patchRange = {
-          basePatchNum: PARENT,
-          patchNum: '10',
+      function getFilesFromFileList(fileList) {
+        const changeFilesByPath = fileList.reduce((files, path) => {
+          files[path] = {};
+          return files;
+        }, {});
+        return {
+          sortedFileList: fileList,
+          changeFilesByPath,
         };
-        element._change = {_number: 42};
-        element._files = getFilesFromFileList(
-            ['chell.go', 'glados.txt', 'wheatley.md',
-              '/COMMIT_MSG', '/MERGE_LIST']);
-        element._path = 'glados.txt';
-        const expectedFormattedFiles = [
-          {
-            text: 'chell.go',
-            mobileText: 'chell.go',
-            value: 'chell.go',
-            bottomText: '',
-          }, {
-            text: 'glados.txt',
-            mobileText: 'glados.txt',
-            value: 'glados.txt',
-            bottomText: '',
-          }, {
-            text: 'wheatley.md',
-            mobileText: 'wheatley.md',
-            value: 'wheatley.md',
-            bottomText: '',
-          },
-          {
-            text: 'Commit message',
-            mobileText: 'Commit message',
-            value: '/COMMIT_MSG',
-            bottomText: '',
-          },
-          {
-            text: 'Merge list',
-            mobileText: 'Merge list',
-            value: '/MERGE_LIST',
-            bottomText: '',
-          },
-        ];
+      }
 
-        assert.deepEqual(element._formattedFiles, expectedFormattedFiles);
-        assert.equal(element._formattedFiles[1].value, element._path);
+      setup(() => {
+        sandbox = sinon.sandbox.create();
+
+        stub('gr-rest-api-interface', {
+          getConfig() { return Promise.resolve({change: {}}); },
+          getLoggedIn() { return Promise.resolve(false); },
+          getProjectConfig() { return Promise.resolve({}); },
+          getDiffChangeDetail() { return Promise.resolve({}); },
+          getChangeFiles() { return Promise.resolve({}); },
+          saveFileReviewed() { return Promise.resolve(); },
+          getDiffComments() { return Promise.resolve({}); },
+          getDiffRobotComments() { return Promise.resolve({}); },
+          getDiffDrafts() { return Promise.resolve({}); },
+          getReviewedFiles() { return Promise.resolve([]); },
+        });
+        element = fixture('basic');
+        return element._loadComments();
       });
 
-      test('prev/up/next links', () => {
+      teardown(() => {
+        sandbox.restore();
+      });
+
+      test('params change triggers diffViewDisplayed()', () => {
+        sandbox.stub(element.$.reporting, 'diffViewDisplayed');
+        sandbox.stub(element.$.diffHost, 'reload').returns(Promise.resolve());
+        sandbox.spy(element, '_paramsChanged');
+        element.params = {
+          view: Gerrit.Nav.View.DIFF,
+          changeNum: '42',
+          patchNum: '2',
+          basePatchNum: '1',
+          path: '/COMMIT_MSG',
+        };
+
+        return element._paramsChanged.returnValues[0].then(() => {
+          assert.isTrue(element.$.reporting.diffViewDisplayed.calledOnce);
+        });
+      });
+
+      test('toggle left diff with a hotkey', () => {
+        const toggleLeftDiffStub = sandbox.stub(
+            element.$.diffHost, 'toggleLeftDiff');
+        MockInteractions.pressAndReleaseKeyOn(element, 65, 'shift', 'a');
+        assert.isTrue(toggleLeftDiffStub.calledOnce);
+      });
+
+      test('keyboard shortcuts', () => {
         element._changeNum = '42';
         element._patchRange = {
           basePatchNum: PARENT,
@@ -529,34 +153,99 @@
         element._files = getFilesFromFileList(
             ['chell.go', 'glados.txt', 'wheatley.md']);
         element._path = 'glados.txt';
-        flushAsynchronousOperations();
-        const linkEls = Polymer.dom(element.root).querySelectorAll('.navLink');
-        assert.equal(linkEls.length, 3);
-        assert.equal(linkEls[0].getAttribute('href'), '42-chell.go-10-PARENT');
-        assert.equal(linkEls[1].getAttribute('href'), '42-undefined-undefined');
-        assert.equal(linkEls[2].getAttribute('href'),
-            '42-wheatley.md-10-PARENT');
+        element.changeViewState.selectedFileIndex = 1;
+        element._loggedIn = true;
+
+        const diffNavStub = sandbox.stub(Gerrit.Nav, 'navigateToDiff');
+        const changeNavStub = sandbox.stub(Gerrit.Nav, 'navigateToChange');
+
+        MockInteractions.pressAndReleaseKeyOn(element, 85, null, 'u');
+        assert(changeNavStub.lastCall.calledWith(element._change),
+            'Should navigate to /c/42/');
+
+        MockInteractions.pressAndReleaseKeyOn(element, 221, null, ']');
+        assert(diffNavStub.lastCall.calledWith(element._change, 'wheatley.md',
+            '10', PARENT), 'Should navigate to /c/42/10/wheatley.md');
         element._path = 'wheatley.md';
-        flushAsynchronousOperations();
-        assert.equal(linkEls[0].getAttribute('href'),
-            '42-glados.txt-10-PARENT');
-        assert.equal(linkEls[1].getAttribute('href'), '42-undefined-undefined');
-        assert.isFalse(linkEls[2].hasAttribute('href'));
+        assert.equal(element.changeViewState.selectedFileIndex, 2);
+        assert.isTrue(element._loading);
+
+        MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
+        assert(diffNavStub.lastCall.calledWith(element._change, 'glados.txt',
+            '10', PARENT), 'Should navigate to /c/42/10/glados.txt');
+        element._path = 'glados.txt';
+        assert.equal(element.changeViewState.selectedFileIndex, 1);
+        assert.isTrue(element._loading);
+
+        MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
+        assert(diffNavStub.lastCall.calledWith(element._change, 'chell.go', '10',
+            PARENT), 'Should navigate to /c/42/10/chell.go');
         element._path = 'chell.go';
-        flushAsynchronousOperations();
-        assert.isFalse(linkEls[0].hasAttribute('href'));
-        assert.equal(linkEls[1].getAttribute('href'), '42-undefined-undefined');
-        assert.equal(linkEls[2].getAttribute('href'),
-            '42-glados.txt-10-PARENT');
-        element._path = 'not_a_real_file';
-        flushAsynchronousOperations();
-        assert.equal(linkEls[0].getAttribute('href'),
-            '42-wheatley.md-10-PARENT');
-        assert.equal(linkEls[1].getAttribute('href'), '42-undefined-undefined');
-        assert.equal(linkEls[2].getAttribute('href'), '42-chell.go-10-PARENT');
+        assert.equal(element.changeViewState.selectedFileIndex, 0);
+        assert.isTrue(element._loading);
+
+        MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
+        assert(changeNavStub.lastCall.calledWith(element._change),
+            'Should navigate to /c/42/');
+        assert.equal(element.changeViewState.selectedFileIndex, 0);
+        assert.isTrue(element._loading);
+
+        const showPrefsStub =
+            sandbox.stub(element.$.diffPreferencesDialog, 'open',
+                () => Promise.resolve());
+
+        MockInteractions.pressAndReleaseKeyOn(element, 188, null, ',');
+        assert(showPrefsStub.calledOnce);
+
+        element.disableDiffPrefs = true;
+        MockInteractions.pressAndReleaseKeyOn(element, 188, null, ',');
+        assert(showPrefsStub.calledOnce);
+
+        let scrollStub = sandbox.stub(element.$.cursor, 'moveToNextChunk');
+        MockInteractions.pressAndReleaseKeyOn(element, 78, null, 'n');
+        assert(scrollStub.calledOnce);
+
+        scrollStub = sandbox.stub(element.$.cursor, 'moveToPreviousChunk');
+        MockInteractions.pressAndReleaseKeyOn(element, 80, null, 'p');
+        assert(scrollStub.calledOnce);
+
+        scrollStub = sandbox.stub(element.$.cursor, 'moveToNextCommentThread');
+        MockInteractions.pressAndReleaseKeyOn(element, 78, 'shift', 'n');
+        assert(scrollStub.calledOnce);
+
+        scrollStub = sandbox.stub(element.$.cursor,
+            'moveToPreviousCommentThread');
+        MockInteractions.pressAndReleaseKeyOn(element, 80, 'shift', 'p');
+        assert(scrollStub.calledOnce);
+
+        const computeContainerClassStub = sandbox.stub(element.$.diffHost.$.diff,
+            '_computeContainerClass');
+        MockInteractions.pressAndReleaseKeyOn(element, 74, null, 'j');
+        assert(computeContainerClassStub.lastCall.calledWithExactly(
+            false, 'SIDE_BY_SIDE', true));
+
+        MockInteractions.pressAndReleaseKeyOn(element, 27, null, 'esc');
+        assert(computeContainerClassStub.lastCall.calledWithExactly(
+            false, 'SIDE_BY_SIDE', false));
+
+        sandbox.stub(element, '_setReviewed');
+        element.$.reviewed.checked = false;
+        MockInteractions.pressAndReleaseKeyOn(element, 82, 'shift', 'r');
+        assert.isFalse(element._setReviewed.called);
+
+        MockInteractions.pressAndReleaseKeyOn(element, 82, null, 'r');
+        assert.isTrue(element._setReviewed.called);
+        assert.equal(element._setReviewed.lastCall.args[0], true);
       });
 
-      test('prev/up/next links with patch range', () => {
+      test('shift+x shortcut expands all diff context', () => {
+        const expandStub = sandbox.stub(element.$.diffHost, 'expandAllContext');
+        MockInteractions.pressAndReleaseKeyOn(element, 88, 'shift', 'x');
+        flushAsynchronousOperations();
+        assert.isTrue(expandStub.called);
+      });
+
+      test('keyboard shortcuts with patch range', () => {
         element._changeNum = '42';
         element._patchRange = {
           basePatchNum: '5',
@@ -565,782 +254,1104 @@
         element._change = {
           _number: 42,
           revisions: {
-            a: {_number: 5, commit: {parents: []}},
-            b: {_number: 10, commit: {parents: []}},
+            a: {_number: 10, commit: {parents: []}},
+            b: {_number: 5, commit: {parents: []}},
           },
         };
         element._files = getFilesFromFileList(
             ['chell.go', 'glados.txt', 'wheatley.md']);
         element._path = 'glados.txt';
-        flushAsynchronousOperations();
-        const linkEls = Polymer.dom(element.root).querySelectorAll('.navLink');
-        assert.equal(linkEls.length, 3);
-        assert.equal(linkEls[0].getAttribute('href'), '42-chell.go-10-5');
-        assert.equal(linkEls[1].getAttribute('href'), '42-10-5');
-        assert.equal(linkEls[2].getAttribute('href'), '42-wheatley.md-10-5');
+
+        const diffNavStub = sandbox.stub(Gerrit.Nav, 'navigateToDiff');
+        const changeNavStub = sandbox.stub(Gerrit.Nav, 'navigateToChange');
+
+        MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
+        assert.isTrue(changeNavStub.notCalled, 'The `a` keyboard shortcut ' +
+            'should only work when the user is logged in.');
+        assert.isNull(window.sessionStorage.getItem(
+            'changeView.showReplyDialog'));
+
+        element._loggedIn = true;
+        MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
+        assert.isTrue(element.changeViewState.showReplyDialog);
+
+        assert(changeNavStub.lastCall.calledWithExactly(element._change, '10',
+            '5'), 'Should navigate to /c/42/5..10');
+
+        MockInteractions.pressAndReleaseKeyOn(element, 85, null, 'u');
+        assert(changeNavStub.lastCall.calledWithExactly(element._change, '10',
+            '5'), 'Should navigate to /c/42/5..10');
+
+        MockInteractions.pressAndReleaseKeyOn(element, 221, null, ']');
+        assert.isTrue(element._loading);
+        assert(diffNavStub.lastCall.calledWithExactly(element._change,
+            'wheatley.md', '10', '5'),
+        'Should navigate to /c/42/5..10/wheatley.md');
         element._path = 'wheatley.md';
-        flushAsynchronousOperations();
-        assert.equal(linkEls[0].getAttribute('href'), '42-glados.txt-10-5');
-        assert.equal(linkEls[1].getAttribute('href'), '42-10-5');
-        assert.isFalse(linkEls[2].hasAttribute('href'));
+
+        MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
+        assert.isTrue(element._loading);
+        assert(diffNavStub.lastCall.calledWithExactly(element._change,
+            'glados.txt', '10', '5'),
+        'Should navigate to /c/42/5..10/glados.txt');
+        element._path = 'glados.txt';
+
+        MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
+        assert.isTrue(element._loading);
+        assert(diffNavStub.lastCall.calledWithExactly(
+            element._change,
+            'chell.go',
+            '10',
+            '5'),
+        'Should navigate to /c/42/5..10/chell.go');
         element._path = 'chell.go';
-        flushAsynchronousOperations();
-        assert.isFalse(linkEls[0].hasAttribute('href'));
-        assert.equal(linkEls[1].getAttribute('href'), '42-10-5');
-        assert.equal(linkEls[2].getAttribute('href'), '42-glados.txt-10-5');
+
+        MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
+        assert.isTrue(element._loading);
+        assert(changeNavStub.lastCall.calledWithExactly(element._change, '10',
+            '5'),
+        'Should navigate to /c/42/5..10');
       });
-    });
 
-    test('_handlePatchChange calls navigateToDiff correctly', () => {
-      const navigateStub = sandbox.stub(Gerrit.Nav, 'navigateToDiff');
-      element._change = {_number: 321, project: 'foo/bar'};
-      element._path = 'path/to/file.txt';
-
-      element._patchRange = {
-        basePatchNum: 'PARENT',
-        patchNum: '3',
-      };
-
-      const detail = {
-        basePatchNum: 'PARENT',
-        patchNum: '1',
-      };
-
-      element.$.rangeSelect.dispatchEvent(
-          new CustomEvent('patch-range-change', {detail, bubbles: false}));
-
-      assert(navigateStub.lastCall.calledWithExactly(element._change,
-          element._path, '1', 'PARENT'));
-    });
-
-    test('_prefs.manual_review is respected', () => {
-      const saveReviewedStub = sandbox.stub(element, '_saveReviewedState',
-          () => Promise.resolve());
-      const getReviewedStub = sandbox.stub(element, '_getReviewedStatus',
-          () => Promise.resolve());
-
-      sandbox.stub(element.$.diffHost, 'reload');
-      element._loggedIn = true;
-      element.params = {
-        view: Gerrit.Nav.View.DIFF,
-        changeNum: '42',
-        patchNum: '2',
-        basePatchNum: '1',
-        path: '/COMMIT_MSG',
-      };
-      element._prefs = {manual_review: true};
-      flushAsynchronousOperations();
-
-      assert.isFalse(saveReviewedStub.called);
-      assert.isTrue(getReviewedStub.called);
-
-      element._prefs = {};
-      flushAsynchronousOperations();
-
-      assert.isTrue(saveReviewedStub.called);
-      assert.isTrue(getReviewedStub.calledOnce);
-    });
-
-    test('file review status', () => {
-      const saveReviewedStub = sandbox.stub(element, '_saveReviewedState',
-          () => Promise.resolve());
-      sandbox.stub(element.$.diffHost, 'reload');
-
-      element._loggedIn = true;
-      element.params = {
-        view: Gerrit.Nav.View.DIFF,
-        changeNum: '42',
-        patchNum: '2',
-        basePatchNum: '1',
-        path: '/COMMIT_MSG',
-      };
-      element._prefs = {};
-      flushAsynchronousOperations();
-
-      const commitMsg = Polymer.dom(element.root).querySelector(
-          'input[type="checkbox"]');
-
-      assert.isTrue(commitMsg.checked);
-      MockInteractions.tap(commitMsg);
-      assert.isFalse(commitMsg.checked);
-      assert.isTrue(saveReviewedStub.lastCall.calledWithExactly(false));
-
-      MockInteractions.tap(commitMsg);
-      assert.isTrue(commitMsg.checked);
-      assert.isTrue(saveReviewedStub.lastCall.calledWithExactly(true));
-      const callCount = saveReviewedStub.callCount;
-
-      element.set('params.view', Gerrit.Nav.View.CHANGE);
-      flushAsynchronousOperations();
-
-      // saveReviewedState observer observes params, but should not fire when
-      // view !== Gerrit.Nav.View.DIFF.
-      assert.equal(saveReviewedStub.callCount, callCount);
-    });
-
-    test('file review status with edit loaded', () => {
-      const saveReviewedStub = sandbox.stub(element, '_saveReviewedState');
-
-      element._patchRange = {patchNum: element.EDIT_NAME};
-      flushAsynchronousOperations();
-
-      assert.isTrue(element._editMode);
-      element._setReviewed();
-      assert.isFalse(saveReviewedStub.called);
-    });
-
-    test('hash is determined from params', done => {
-      sandbox.stub(element.$.diffHost, 'reload');
-      sandbox.stub(element, '_initCursor');
-
-      element._loggedIn = true;
-      element.params = {
-        view: Gerrit.Nav.View.DIFF,
-        changeNum: '42',
-        patchNum: '2',
-        basePatchNum: '1',
-        path: '/COMMIT_MSG',
-        hash: 10,
-      };
-
-      flush(() => {
-        assert.isTrue(element._initCursor.calledOnce);
-        done();
-      });
-    });
-
-    test('diff mode selector correctly toggles the diff', () => {
-      const select = element.$.modeSelect;
-      const diffDisplay = element.$.diffHost;
-      element._userPrefs = {default_diff_view: 'SIDE_BY_SIDE'};
-
-      // The mode selected in the view state reflects the selected option.
-      assert.equal(element._getDiffViewMode(), select.mode);
-
-      // The mode selected in the view state reflects the view rednered in the
-      // diff.
-      assert.equal(select.mode, diffDisplay.viewMode);
-
-      // We will simulate a user change of the selected mode.
-      const newMode = 'UNIFIED_DIFF';
-
-      // Set the mode, and simulate the change event.
-      element.set('changeViewState.diffMode', newMode);
-
-      // Make sure the handler was called and the state is still coherent.
-      assert.equal(element._getDiffViewMode(), newMode);
-      assert.equal(element._getDiffViewMode(), select.mode);
-      assert.equal(element._getDiffViewMode(), diffDisplay.viewMode);
-    });
-
-    test('diff mode selector initializes from preferences', () => {
-      let resolvePrefs;
-      const prefsPromise = new Promise(resolve => {
-        resolvePrefs = resolve;
-      });
-      sandbox.stub(element.$.restAPI, 'getPreferences', () => prefsPromise);
-
-      // Attach a new gr-diff-view so we can intercept the preferences fetch.
-      const view = document.createElement('gr-diff-view');
-      fixture('blank').appendChild(view);
-      flushAsynchronousOperations();
-
-      // At this point the diff mode doesn't yet have the user's preference.
-      assert.equal(view._getDiffViewMode(), 'SIDE_BY_SIDE');
-
-      // Receive the overriding preference.
-      resolvePrefs({default_diff_view: 'UNIFIED'});
-      flushAsynchronousOperations();
-      assert.equal(element._getDiffViewMode(), 'SIDE_BY_SIDE');
-    });
-
-    suite('_commitRange', () => {
-      setup(() => {
-        sandbox.stub(element.$.diffHost, 'reload');
-        sandbox.stub(element, '_initCursor');
-        sandbox.stub(element, '_getChangeDetail').returns(Promise.resolve({
+      test('keyboard shortcuts with old patch number', () => {
+        element._changeNum = '42';
+        element._patchRange = {
+          basePatchNum: PARENT,
+          patchNum: '1',
+        };
+        element._change = {
           _number: 42,
           revisions: {
-            'commit-sha-1': {
-              _number: 1,
-              commit: {
-                parents: [{commit: 'sha-1-parent'}],
-              },
-            },
-            'commit-sha-2': {_number: 2},
-            'commit-sha-3': {_number: 3},
-            'commit-sha-4': {_number: 4},
-            'commit-sha-5': {
-              _number: 5,
-              commit: {
-                parents: [{commit: 'sha-5-parent'}],
-              },
-            },
+            a: {_number: 1, commit: {parents: []}},
+            b: {_number: 2, commit: {parents: []}},
           },
-        }));
+        };
+        element._files = getFilesFromFileList(
+            ['chell.go', 'glados.txt', 'wheatley.md']);
+        element._path = 'glados.txt';
+
+        const diffNavStub = sandbox.stub(Gerrit.Nav, 'navigateToDiff');
+        const changeNavStub = sandbox.stub(Gerrit.Nav, 'navigateToChange');
+
+        MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
+        assert.isTrue(changeNavStub.notCalled, 'The `a` keyboard shortcut ' +
+            'should only work when the user is logged in.');
+        assert.isNull(window.sessionStorage.getItem(
+            'changeView.showReplyDialog'));
+
+        element._loggedIn = true;
+        MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
+        assert.isTrue(element.changeViewState.showReplyDialog);
+
+        assert(changeNavStub.lastCall.calledWithExactly(element._change, '1',
+            PARENT), 'Should navigate to /c/42/1');
+
+        MockInteractions.pressAndReleaseKeyOn(element, 85, null, 'u');
+        assert(changeNavStub.lastCall.calledWithExactly(element._change, '1',
+            PARENT), 'Should navigate to /c/42/1');
+
+        MockInteractions.pressAndReleaseKeyOn(element, 221, null, ']');
+        assert(diffNavStub.lastCall.calledWithExactly(element._change,
+            'wheatley.md', '1', PARENT),
+        'Should navigate to /c/42/1/wheatley.md');
+        element._path = 'wheatley.md';
+
+        MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
+        assert(diffNavStub.lastCall.calledWithExactly(element._change,
+            'glados.txt', '1', PARENT),
+        'Should navigate to /c/42/1/glados.txt');
+        element._path = 'glados.txt';
+
+        MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
+        assert(diffNavStub.lastCall.calledWithExactly(
+            element._change,
+            'chell.go',
+            '1',
+            PARENT), 'Should navigate to /c/42/1/chell.go');
+        element._path = 'chell.go';
+
+        MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
+        assert(changeNavStub.lastCall.calledWithExactly(element._change, '1',
+            PARENT), 'Should navigate to /c/42/1');
       });
 
-      test('uses the patchNum and basePatchNum ', done => {
+      suite('diff prefs hidden', () => {
+        test('when no prefs or logged out', () => {
+          element.disableDiffPrefs = false;
+          element._loggedIn = false;
+          flushAsynchronousOperations();
+          assert.isTrue(element.$.diffPrefsContainer.hidden);
+
+          element._loggedIn = true;
+          flushAsynchronousOperations();
+          assert.isTrue(element.$.diffPrefsContainer.hidden);
+
+          element._loggedIn = false;
+          element._prefs = {font_size: '12'};
+          flushAsynchronousOperations();
+          assert.isTrue(element.$.diffPrefsContainer.hidden);
+
+          element._loggedIn = true;
+          flushAsynchronousOperations();
+          assert.isFalse(element.$.diffPrefsContainer.hidden);
+        });
+
+        test('when disableDiffPrefs is set', () => {
+          element._loggedIn = true;
+          element._prefs = {font_size: '12'};
+          element.disableDiffPrefs = false;
+          flushAsynchronousOperations();
+
+          assert.isFalse(element.$.diffPrefsContainer.hidden);
+          element.disableDiffPrefs = true;
+          flushAsynchronousOperations();
+
+          assert.isTrue(element.$.diffPrefsContainer.hidden);
+        });
+      });
+
+      test('prefsButton opens gr-diff-preferences', () => {
+        const handlePrefsTapSpy = sandbox.spy(element, '_handlePrefsTap');
+        const overlayOpenStub = sandbox.stub(element.$.diffPreferencesDialog,
+            'open');
+        const prefsButton =
+            Polymer.dom(element.root).querySelector('.prefsButton');
+
+        MockInteractions.tap(prefsButton);
+
+        assert.isTrue(handlePrefsTapSpy.called);
+        assert.isTrue(overlayOpenStub.called);
+      });
+
+      test('_computeCommentString', done => {
+        loadCommentSpy = sandbox.spy(element.$.commentAPI, 'loadAll');
+        const path = '/test';
+        element.$.commentAPI.loadAll().then(comments => {
+          const commentCountStub =
+              sandbox.stub(comments, 'computeCommentCount');
+          const unresolvedCountStub =
+              sandbox.stub(comments, 'computeUnresolvedNum');
+          commentCountStub.withArgs(1, path).returns(0);
+          commentCountStub.withArgs(2, path).returns(1);
+          commentCountStub.withArgs(3, path).returns(2);
+          commentCountStub.withArgs(4, path).returns(0);
+          unresolvedCountStub.withArgs(1, path).returns(1);
+          unresolvedCountStub.withArgs(2, path).returns(0);
+          unresolvedCountStub.withArgs(3, path).returns(2);
+          unresolvedCountStub.withArgs(4, path).returns(0);
+
+          assert.equal(element._computeCommentString(comments, 1, path, {}),
+              '1 unresolved');
+          assert.equal(
+              element._computeCommentString(comments, 2, path, {status: 'M'}),
+              '1 comment');
+          assert.equal(
+              element._computeCommentString(comments, 2, path, {status: 'U'}),
+              'no changes, 1 comment');
+          assert.equal(
+              element._computeCommentString(comments, 3, path, {status: 'A'}),
+              '2 comments, 2 unresolved');
+          assert.equal(
+              element._computeCommentString(
+                  comments, 4, path, {status: 'M'}
+              ), '');
+          assert.equal(
+              element._computeCommentString(comments, 4, path, {status: 'U'}),
+              'no changes');
+          done();
+        });
+      });
+
+      suite('url params', () => {
+        setup(() => {
+          sandbox.stub(
+              Gerrit.Nav,
+              'getUrlForDiff',
+              (c, p, pn, bpn) => `${c._number}-${p}-${pn}-${bpn}`);
+          sandbox.stub(
+              Gerrit.Nav
+              , 'getUrlForChange',
+              (c, pn, bpn) => `${c._number}-${pn}-${bpn}`);
+        });
+
+        test('_formattedFiles', () => {
+          element._changeNum = '42';
+          element._patchRange = {
+            basePatchNum: PARENT,
+            patchNum: '10',
+          };
+          element._change = {_number: 42};
+          element._files = getFilesFromFileList(
+              ['chell.go', 'glados.txt', 'wheatley.md',
+                '/COMMIT_MSG', '/MERGE_LIST']);
+          element._path = 'glados.txt';
+          const expectedFormattedFiles = [
+            {
+              text: 'chell.go',
+              mobileText: 'chell.go',
+              value: 'chell.go',
+              bottomText: '',
+            }, {
+              text: 'glados.txt',
+              mobileText: 'glados.txt',
+              value: 'glados.txt',
+              bottomText: '',
+            }, {
+              text: 'wheatley.md',
+              mobileText: 'wheatley.md',
+              value: 'wheatley.md',
+              bottomText: '',
+            },
+            {
+              text: 'Commit message',
+              mobileText: 'Commit message',
+              value: '/COMMIT_MSG',
+              bottomText: '',
+            },
+            {
+              text: 'Merge list',
+              mobileText: 'Merge list',
+              value: '/MERGE_LIST',
+              bottomText: '',
+            },
+          ];
+
+          assert.deepEqual(element._formattedFiles, expectedFormattedFiles);
+          assert.equal(element._formattedFiles[1].value, element._path);
+        });
+
+        test('prev/up/next links', () => {
+          element._changeNum = '42';
+          element._patchRange = {
+            basePatchNum: PARENT,
+            patchNum: '10',
+          };
+          element._change = {
+            _number: 42,
+            revisions: {
+              a: {_number: 10, commit: {parents: []}},
+            },
+          };
+          element._files = getFilesFromFileList(
+              ['chell.go', 'glados.txt', 'wheatley.md']);
+          element._path = 'glados.txt';
+          flushAsynchronousOperations();
+          const linkEls = Polymer.dom(element.root).querySelectorAll('.navLink');
+          assert.equal(linkEls.length, 3);
+          assert.equal(linkEls[0].getAttribute('href'), '42-chell.go-10-PARENT');
+          assert.equal(linkEls[1].getAttribute('href'), '42-undefined-undefined');
+          assert.equal(linkEls[2].getAttribute('href'),
+              '42-wheatley.md-10-PARENT');
+          element._path = 'wheatley.md';
+          flushAsynchronousOperations();
+          assert.equal(linkEls[0].getAttribute('href'),
+              '42-glados.txt-10-PARENT');
+          assert.equal(linkEls[1].getAttribute('href'), '42-undefined-undefined');
+          assert.isFalse(linkEls[2].hasAttribute('href'));
+          element._path = 'chell.go';
+          flushAsynchronousOperations();
+          assert.isFalse(linkEls[0].hasAttribute('href'));
+          assert.equal(linkEls[1].getAttribute('href'), '42-undefined-undefined');
+          assert.equal(linkEls[2].getAttribute('href'),
+              '42-glados.txt-10-PARENT');
+          element._path = 'not_a_real_file';
+          flushAsynchronousOperations();
+          assert.equal(linkEls[0].getAttribute('href'),
+              '42-wheatley.md-10-PARENT');
+          assert.equal(linkEls[1].getAttribute('href'), '42-undefined-undefined');
+          assert.equal(linkEls[2].getAttribute('href'), '42-chell.go-10-PARENT');
+        });
+
+        test('prev/up/next links with patch range', () => {
+          element._changeNum = '42';
+          element._patchRange = {
+            basePatchNum: '5',
+            patchNum: '10',
+          };
+          element._change = {
+            _number: 42,
+            revisions: {
+              a: {_number: 5, commit: {parents: []}},
+              b: {_number: 10, commit: {parents: []}},
+            },
+          };
+          element._files = getFilesFromFileList(
+              ['chell.go', 'glados.txt', 'wheatley.md']);
+          element._path = 'glados.txt';
+          flushAsynchronousOperations();
+          const linkEls = Polymer.dom(element.root).querySelectorAll('.navLink');
+          assert.equal(linkEls.length, 3);
+          assert.equal(linkEls[0].getAttribute('href'), '42-chell.go-10-5');
+          assert.equal(linkEls[1].getAttribute('href'), '42-10-5');
+          assert.equal(linkEls[2].getAttribute('href'), '42-wheatley.md-10-5');
+          element._path = 'wheatley.md';
+          flushAsynchronousOperations();
+          assert.equal(linkEls[0].getAttribute('href'), '42-glados.txt-10-5');
+          assert.equal(linkEls[1].getAttribute('href'), '42-10-5');
+          assert.isFalse(linkEls[2].hasAttribute('href'));
+          element._path = 'chell.go';
+          flushAsynchronousOperations();
+          assert.isFalse(linkEls[0].hasAttribute('href'));
+          assert.equal(linkEls[1].getAttribute('href'), '42-10-5');
+          assert.equal(linkEls[2].getAttribute('href'), '42-glados.txt-10-5');
+        });
+      });
+
+      test('_handlePatchChange calls navigateToDiff correctly', () => {
+        const navigateStub = sandbox.stub(Gerrit.Nav, 'navigateToDiff');
+        element._change = {_number: 321, project: 'foo/bar'};
+        element._path = 'path/to/file.txt';
+
+        element._patchRange = {
+          basePatchNum: 'PARENT',
+          patchNum: '3',
+        };
+
+        const detail = {
+          basePatchNum: 'PARENT',
+          patchNum: '1',
+        };
+
+        element.$.rangeSelect.dispatchEvent(
+            new CustomEvent('patch-range-change', {detail, bubbles: false}));
+
+        assert(navigateStub.lastCall.calledWithExactly(element._change,
+            element._path, '1', 'PARENT'));
+      });
+
+      test('_prefs.manual_review is respected', () => {
+        const saveReviewedStub = sandbox.stub(element, '_saveReviewedState',
+            () => Promise.resolve());
+        const getReviewedStub = sandbox.stub(element, '_getReviewedStatus',
+            () => Promise.resolve());
+
+        sandbox.stub(element.$.diffHost, 'reload');
+        element._loggedIn = true;
         element.params = {
           view: Gerrit.Nav.View.DIFF,
           changeNum: '42',
-          patchNum: '4',
-          basePatchNum: '2',
+          patchNum: '2',
+          basePatchNum: '1',
           path: '/COMMIT_MSG',
         };
-        flush(() => {
-          assert.deepEqual(element._commitRange, {
-            baseCommit: 'commit-sha-2',
-            commit: 'commit-sha-4',
-          });
-          done();
-        });
+        element._prefs = {manual_review: true};
+        flushAsynchronousOperations();
+
+        assert.isFalse(saveReviewedStub.called);
+        assert.isTrue(getReviewedStub.called);
+
+        element._prefs = {};
+        flushAsynchronousOperations();
+
+        assert.isTrue(saveReviewedStub.called);
+        assert.isTrue(getReviewedStub.calledOnce);
       });
 
-      test('uses the parent when there is no base patch num ', done => {
+      test('file review status', () => {
+        const saveReviewedStub = sandbox.stub(element, '_saveReviewedState',
+            () => Promise.resolve());
+        sandbox.stub(element.$.diffHost, 'reload');
+
+        element._loggedIn = true;
         element.params = {
           view: Gerrit.Nav.View.DIFF,
           changeNum: '42',
-          patchNum: '5',
+          patchNum: '2',
+          basePatchNum: '1',
           path: '/COMMIT_MSG',
         };
+        element._prefs = {};
+        flushAsynchronousOperations();
+
+        const commitMsg = Polymer.dom(element.root).querySelector(
+            'input[type="checkbox"]');
+
+        assert.isTrue(commitMsg.checked);
+        MockInteractions.tap(commitMsg);
+        assert.isFalse(commitMsg.checked);
+        assert.isTrue(saveReviewedStub.lastCall.calledWithExactly(false));
+
+        MockInteractions.tap(commitMsg);
+        assert.isTrue(commitMsg.checked);
+        assert.isTrue(saveReviewedStub.lastCall.calledWithExactly(true));
+        const callCount = saveReviewedStub.callCount;
+
+        element.set('params.view', Gerrit.Nav.View.CHANGE);
+        flushAsynchronousOperations();
+
+        // saveReviewedState observer observes params, but should not fire when
+        // view !== Gerrit.Nav.View.DIFF.
+        assert.equal(saveReviewedStub.callCount, callCount);
+      });
+
+      test('file review status with edit loaded', () => {
+        const saveReviewedStub = sandbox.stub(element, '_saveReviewedState');
+
+        element._patchRange = {patchNum: element.EDIT_NAME};
+        flushAsynchronousOperations();
+
+        assert.isTrue(element._editMode);
+        element._setReviewed();
+        assert.isFalse(saveReviewedStub.called);
+      });
+
+      test('hash is determined from params', done => {
+        sandbox.stub(element.$.diffHost, 'reload');
+        sandbox.stub(element, '_initCursor');
+
+        element._loggedIn = true;
+        element.params = {
+          view: Gerrit.Nav.View.DIFF,
+          changeNum: '42',
+          patchNum: '2',
+          basePatchNum: '1',
+          path: '/COMMIT_MSG',
+          hash: 10,
+        };
+
         flush(() => {
-          assert.deepEqual(element._commitRange, {
-            commit: 'commit-sha-5',
-            baseCommit: 'sha-5-parent',
+          assert.isTrue(element._initCursor.calledOnce);
+          done();
+        });
+      });
+
+      test('diff mode selector correctly toggles the diff', () => {
+        const select = element.$.modeSelect;
+        const diffDisplay = element.$.diffHost;
+        element._userPrefs = {default_diff_view: 'SIDE_BY_SIDE'};
+
+        // The mode selected in the view state reflects the selected option.
+        assert.equal(element._getDiffViewMode(), select.mode);
+
+        // The mode selected in the view state reflects the view rednered in the
+        // diff.
+        assert.equal(select.mode, diffDisplay.viewMode);
+
+        // We will simulate a user change of the selected mode.
+        const newMode = 'UNIFIED_DIFF';
+
+        // Set the mode, and simulate the change event.
+        element.set('changeViewState.diffMode', newMode);
+
+        // Make sure the handler was called and the state is still coherent.
+        assert.equal(element._getDiffViewMode(), newMode);
+        assert.equal(element._getDiffViewMode(), select.mode);
+        assert.equal(element._getDiffViewMode(), diffDisplay.viewMode);
+      });
+
+      test('diff mode selector initializes from preferences', () => {
+        let resolvePrefs;
+        const prefsPromise = new Promise(resolve => {
+          resolvePrefs = resolve;
+        });
+        sandbox.stub(element.$.restAPI, 'getPreferences', () => prefsPromise);
+
+        // Attach a new gr-diff-view so we can intercept the preferences fetch.
+        const view = document.createElement('gr-diff-view');
+        fixture('blank').appendChild(view);
+        flushAsynchronousOperations();
+
+        // At this point the diff mode doesn't yet have the user's preference.
+        assert.equal(view._getDiffViewMode(), 'SIDE_BY_SIDE');
+
+        // Receive the overriding preference.
+        resolvePrefs({default_diff_view: 'UNIFIED'});
+        flushAsynchronousOperations();
+        assert.equal(element._getDiffViewMode(), 'SIDE_BY_SIDE');
+      });
+
+      suite('_commitRange', () => {
+        setup(() => {
+          sandbox.stub(element.$.diffHost, 'reload');
+          sandbox.stub(element, '_initCursor');
+          sandbox.stub(element, '_getChangeDetail').returns(Promise.resolve({
+            _number: 42,
+            revisions: {
+              'commit-sha-1': {
+                _number: 1,
+                commit: {
+                  parents: [{commit: 'sha-1-parent'}],
+                },
+              },
+              'commit-sha-2': {_number: 2},
+              'commit-sha-3': {_number: 3},
+              'commit-sha-4': {_number: 4},
+              'commit-sha-5': {
+                _number: 5,
+                commit: {
+                  parents: [{commit: 'sha-5-parent'}],
+                },
+              },
+            },
+          }));
+        });
+
+        test('uses the patchNum and basePatchNum ', done => {
+          element.params = {
+            view: Gerrit.Nav.View.DIFF,
+            changeNum: '42',
+            patchNum: '4',
+            basePatchNum: '2',
+            path: '/COMMIT_MSG',
+          };
+          flush(() => {
+            assert.deepEqual(element._commitRange, {
+              baseCommit: 'commit-sha-2',
+              commit: 'commit-sha-4',
+            });
+            done();
           });
-          done();
         });
-      });
-    });
 
-    test('_initCursor', () => {
-      assert.isNotOk(element.$.cursor.initialLineNumber);
-
-      // Does nothing when params specify no cursor address:
-      element._initCursor({});
-      assert.isNotOk(element.$.cursor.initialLineNumber);
-
-      // Does nothing when params specify side but no number:
-      element._initCursor({leftSide: true});
-      assert.isNotOk(element.$.cursor.initialLineNumber);
-
-      // Revision hash: specifies lineNum but not side.
-      element._initCursor({lineNum: 234});
-      assert.equal(element.$.cursor.initialLineNumber, 234);
-      assert.equal(element.$.cursor.side, 'right');
-
-      // Base hash: specifies lineNum and side.
-      element._initCursor({leftSide: true, lineNum: 345});
-      assert.equal(element.$.cursor.initialLineNumber, 345);
-      assert.equal(element.$.cursor.side, 'left');
-
-      // Specifies right side:
-      element._initCursor({leftSide: false, lineNum: 123});
-      assert.equal(element.$.cursor.initialLineNumber, 123);
-      assert.equal(element.$.cursor.side, 'right');
-    });
-
-    test('_getLineOfInterest', () => {
-      assert.isNull(element._getLineOfInterest({}));
-
-      let result = element._getLineOfInterest({lineNum: 12});
-      assert.equal(result.number, 12);
-      assert.isNotOk(result.leftSide);
-
-      result = element._getLineOfInterest({lineNum: 12, leftSide: true});
-      assert.equal(result.number, 12);
-      assert.isOk(result.leftSide);
-    });
-
-    test('_onLineSelected', () => {
-      const getUrlStub = sandbox.stub(Gerrit.Nav, 'getUrlForDiffById');
-      const replaceStateStub = sandbox.stub(history, 'replaceState');
-      const moveStub = sandbox.stub(element.$.cursor, 'moveToLineNumber');
-      sandbox.stub(element.$.cursor, 'getAddress')
-          .returns({number: 123, isLeftSide: false});
-
-      element._changeNum = 321;
-      element._change = {_number: 321, project: 'foo/bar'};
-      element._patchRange = {
-        basePatchNum: '3',
-        patchNum: '5',
-      };
-      const e = {};
-      const detail = {number: 123, side: 'right'};
-
-      element._onLineSelected(e, detail);
-
-      assert.isTrue(moveStub.called);
-      assert.equal(moveStub.lastCall.args[0], detail.number);
-      assert.equal(moveStub.lastCall.args[1], detail.side);
-
-      assert.isTrue(replaceStateStub.called);
-      assert.isTrue(getUrlStub.called);
-    });
-
-    test('_onLineSelected w/o line address', () => {
-      const getUrlStub = sandbox.stub(Gerrit.Nav, 'getUrlForDiffById');
-      sandbox.stub(history, 'replaceState');
-      sandbox.stub(element.$.cursor, 'moveToLineNumber');
-      sandbox.stub(element.$.cursor, 'getAddress').returns(null);
-      element._changeNum = 321;
-      element._change = {_number: 321, project: 'foo/bar'};
-      element._patchRange = {basePatchNum: '3', patchNum: '5'};
-      element._onLineSelected({}, {number: 123, side: 'right'});
-      assert.isTrue(getUrlStub.calledOnce);
-      assert.isUndefined(getUrlStub.lastCall.args[5]);
-      assert.isUndefined(getUrlStub.lastCall.args[6]);
-    });
-
-    test('_getDiffViewMode', () => {
-      // No user prefs or change view state set.
-      assert.equal(element._getDiffViewMode(), 'SIDE_BY_SIDE');
-
-      // User prefs but no change view state set.
-      element._userPrefs = {default_diff_view: 'UNIFIED_DIFF'};
-      assert.equal(element._getDiffViewMode(), 'UNIFIED_DIFF');
-
-      // User prefs and change view state set.
-      element.changeViewState = {diffMode: 'SIDE_BY_SIDE'};
-      assert.equal(element._getDiffViewMode(), 'SIDE_BY_SIDE');
-    });
-
-    test('_handleToggleDiffMode', () => {
-      sandbox.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
-      const e = {preventDefault: () => {}};
-      // Initial state.
-      assert.equal(element._getDiffViewMode(), 'SIDE_BY_SIDE');
-
-      element._handleToggleDiffMode(e);
-      assert.equal(element._getDiffViewMode(), 'UNIFIED_DIFF');
-
-      element._handleToggleDiffMode(e);
-      assert.equal(element._getDiffViewMode(), 'SIDE_BY_SIDE');
-    });
-
-    suite('_loadComments', () => {
-      test('empty', done => {
-        element._loadComments().then(() => {
-          assert.equal(Object.keys(element._commentMap).length, 0);
-          done();
+        test('uses the parent when there is no base patch num ', done => {
+          element.params = {
+            view: Gerrit.Nav.View.DIFF,
+            changeNum: '42',
+            patchNum: '5',
+            path: '/COMMIT_MSG',
+          };
+          flush(() => {
+            assert.deepEqual(element._commitRange, {
+              commit: 'commit-sha-5',
+              baseCommit: 'sha-5-parent',
+            });
+            done();
+          });
         });
       });
 
-      test('has paths', done => {
-        sandbox.stub(element, '_getPaths').returns({
-          'path/to/file/one.cpp': [{patch_set: 3, message: 'lorem'}],
-          'path-to/file/two.py': [{patch_set: 5, message: 'ipsum'}],
-        });
-        sandbox.stub(element, '_getCommentsForPath').returns({meta: {}});
-        element._changeNum = '42';
+      test('_initCursor', () => {
+        assert.isNotOk(element.$.cursor.initialLineNumber);
+
+        // Does nothing when params specify no cursor address:
+        element._initCursor({});
+        assert.isNotOk(element.$.cursor.initialLineNumber);
+
+        // Does nothing when params specify side but no number:
+        element._initCursor({leftSide: true});
+        assert.isNotOk(element.$.cursor.initialLineNumber);
+
+        // Revision hash: specifies lineNum but not side.
+        element._initCursor({lineNum: 234});
+        assert.equal(element.$.cursor.initialLineNumber, 234);
+        assert.equal(element.$.cursor.side, 'right');
+
+        // Base hash: specifies lineNum and side.
+        element._initCursor({leftSide: true, lineNum: 345});
+        assert.equal(element.$.cursor.initialLineNumber, 345);
+        assert.equal(element.$.cursor.side, 'left');
+
+        // Specifies right side:
+        element._initCursor({leftSide: false, lineNum: 123});
+        assert.equal(element.$.cursor.initialLineNumber, 123);
+        assert.equal(element.$.cursor.side, 'right');
+      });
+
+      test('_getLineOfInterest', () => {
+        assert.isNull(element._getLineOfInterest({}));
+
+        let result = element._getLineOfInterest({lineNum: 12});
+        assert.equal(result.number, 12);
+        assert.isNotOk(result.leftSide);
+
+        result = element._getLineOfInterest({lineNum: 12, leftSide: true});
+        assert.equal(result.number, 12);
+        assert.isOk(result.leftSide);
+      });
+
+      test('_onLineSelected', () => {
+        const getUrlStub = sandbox.stub(Gerrit.Nav, 'getUrlForDiffById');
+        const replaceStateStub = sandbox.stub(history, 'replaceState');
+        const moveStub = sandbox.stub(element.$.cursor, 'moveToLineNumber');
+        sandbox.stub(element.$.cursor, 'getAddress')
+            .returns({number: 123, isLeftSide: false});
+
+        element._changeNum = 321;
+        element._change = {_number: 321, project: 'foo/bar'};
         element._patchRange = {
           basePatchNum: '3',
           patchNum: '5',
         };
-        element._loadComments().then(() => {
-          assert.deepEqual(Object.keys(element._commentMap),
-              ['path/to/file/one.cpp', 'path-to/file/two.py']);
-          done();
+        const e = {};
+        const detail = {number: 123, side: 'right'};
+
+        element._onLineSelected(e, detail);
+
+        assert.isTrue(moveStub.called);
+        assert.equal(moveStub.lastCall.args[0], detail.number);
+        assert.equal(moveStub.lastCall.args[1], detail.side);
+
+        assert.isTrue(replaceStateStub.called);
+        assert.isTrue(getUrlStub.called);
+      });
+
+      test('_onLineSelected w/o line address', () => {
+        const getUrlStub = sandbox.stub(Gerrit.Nav, 'getUrlForDiffById');
+        sandbox.stub(history, 'replaceState');
+        sandbox.stub(element.$.cursor, 'moveToLineNumber');
+        sandbox.stub(element.$.cursor, 'getAddress').returns(null);
+        element._changeNum = 321;
+        element._change = {_number: 321, project: 'foo/bar'};
+        element._patchRange = {basePatchNum: '3', patchNum: '5'};
+        element._onLineSelected({}, {number: 123, side: 'right'});
+        assert.isTrue(getUrlStub.calledOnce);
+        assert.isUndefined(getUrlStub.lastCall.args[5]);
+        assert.isUndefined(getUrlStub.lastCall.args[6]);
+      });
+
+      test('_getDiffViewMode', () => {
+        // No user prefs or change view state set.
+        assert.equal(element._getDiffViewMode(), 'SIDE_BY_SIDE');
+
+        // User prefs but no change view state set.
+        element._userPrefs = {default_diff_view: 'UNIFIED_DIFF'};
+        assert.equal(element._getDiffViewMode(), 'UNIFIED_DIFF');
+
+        // User prefs and change view state set.
+        element.changeViewState = {diffMode: 'SIDE_BY_SIDE'};
+        assert.equal(element._getDiffViewMode(), 'SIDE_BY_SIDE');
+      });
+
+      test('_handleToggleDiffMode', () => {
+        sandbox.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
+        const e = {preventDefault: () => {}};
+        // Initial state.
+        assert.equal(element._getDiffViewMode(), 'SIDE_BY_SIDE');
+
+        element._handleToggleDiffMode(e);
+        assert.equal(element._getDiffViewMode(), 'UNIFIED_DIFF');
+
+        element._handleToggleDiffMode(e);
+        assert.equal(element._getDiffViewMode(), 'SIDE_BY_SIDE');
+      });
+
+      suite('_loadComments', () => {
+        test('empty', done => {
+          element._loadComments().then(() => {
+            assert.equal(Object.keys(element._commentMap).length, 0);
+            done();
+          });
+        });
+
+        test('has paths', done => {
+          sandbox.stub(element, '_getPaths').returns({
+            'path/to/file/one.cpp': [{patch_set: 3, message: 'lorem'}],
+            'path-to/file/two.py': [{patch_set: 5, message: 'ipsum'}],
+          });
+          sandbox.stub(element, '_getCommentsForPath').returns({meta: {}});
+          element._changeNum = '42';
+          element._patchRange = {
+            basePatchNum: '3',
+            patchNum: '5',
+          };
+          element._loadComments().then(() => {
+            assert.deepEqual(Object.keys(element._commentMap),
+                ['path/to/file/one.cpp', 'path-to/file/two.py']);
+            done();
+          });
         });
       });
-    });
 
-    suite('_computeCommentSkips', () => {
-      test('empty file list', () => {
-        const commentMap = {
-          'path/one.jpg': true,
-          'path/three.wav': true,
-        };
-        const path = 'path/two.m4v';
-        const fileList = [];
-        const result = element._computeCommentSkips(commentMap, fileList, path);
-        assert.isNull(result.previous);
-        assert.isNull(result.next);
+      suite('_computeCommentSkips', () => {
+        test('empty file list', () => {
+          const commentMap = {
+            'path/one.jpg': true,
+            'path/three.wav': true,
+          };
+          const path = 'path/two.m4v';
+          const fileList = [];
+          const result = element._computeCommentSkips(commentMap, fileList, path);
+          assert.isNull(result.previous);
+          assert.isNull(result.next);
+        });
+
+        test('finds skips', () => {
+          const fileList = ['path/one.jpg', 'path/two.m4v', 'path/three.wav'];
+          let path = fileList[1];
+          const commentMap = {};
+          commentMap[fileList[0]] = true;
+          commentMap[fileList[1]] = false;
+          commentMap[fileList[2]] = true;
+
+          let result = element._computeCommentSkips(commentMap, fileList, path);
+          assert.equal(result.previous, fileList[0]);
+          assert.equal(result.next, fileList[2]);
+
+          commentMap[fileList[1]] = true;
+
+          result = element._computeCommentSkips(commentMap, fileList, path);
+          assert.equal(result.previous, fileList[0]);
+          assert.equal(result.next, fileList[2]);
+
+          path = fileList[0];
+
+          result = element._computeCommentSkips(commentMap, fileList, path);
+          assert.isNull(result.previous);
+          assert.equal(result.next, fileList[1]);
+
+          path = fileList[2];
+
+          result = element._computeCommentSkips(commentMap, fileList, path);
+          assert.equal(result.previous, fileList[1]);
+          assert.isNull(result.next);
+        });
+
+        suite('skip next/previous', () => {
+          let navToChangeStub;
+          let navToDiffStub;
+
+          setup(() => {
+            navToChangeStub = sandbox.stub(element, '_navToChangeView');
+            navToDiffStub = sandbox.stub(Gerrit.Nav, 'navigateToDiff');
+            element._files = getFilesFromFileList([
+              'path/one.jpg', 'path/two.m4v', 'path/three.wav',
+            ]);
+            element._patchRange = {patchNum: '2', basePatchNum: '1'};
+          });
+
+          suite('_moveToPreviousFileWithComment', () => {
+            test('no skips', () => {
+              element._moveToPreviousFileWithComment();
+              assert.isFalse(navToChangeStub.called);
+              assert.isFalse(navToDiffStub.called);
+            });
+
+            test('no previous', () => {
+              const commentMap = {};
+              commentMap[element._fileList[0]] = false;
+              commentMap[element._fileList[1]] = false;
+              commentMap[element._fileList[2]] = true;
+              element._commentMap = commentMap;
+              element._path = element._fileList[1];
+
+              element._moveToPreviousFileWithComment();
+              assert.isTrue(navToChangeStub.calledOnce);
+              assert.isFalse(navToDiffStub.called);
+            });
+
+            test('w/ previous', () => {
+              const commentMap = {};
+              commentMap[element._fileList[0]] = true;
+              commentMap[element._fileList[1]] = false;
+              commentMap[element._fileList[2]] = true;
+              element._commentMap = commentMap;
+              element._path = element._fileList[1];
+
+              element._moveToPreviousFileWithComment();
+              assert.isFalse(navToChangeStub.called);
+              assert.isTrue(navToDiffStub.calledOnce);
+            });
+          });
+
+          suite('_moveToNextFileWithComment', () => {
+            test('no skips', () => {
+              element._moveToNextFileWithComment();
+              assert.isFalse(navToChangeStub.called);
+              assert.isFalse(navToDiffStub.called);
+            });
+
+            test('no previous', () => {
+              const commentMap = {};
+              commentMap[element._fileList[0]] = true;
+              commentMap[element._fileList[1]] = false;
+              commentMap[element._fileList[2]] = false;
+              element._commentMap = commentMap;
+              element._path = element._fileList[1];
+
+              element._moveToNextFileWithComment();
+              assert.isTrue(navToChangeStub.calledOnce);
+              assert.isFalse(navToDiffStub.called);
+            });
+
+            test('w/ previous', () => {
+              const commentMap = {};
+              commentMap[element._fileList[0]] = true;
+              commentMap[element._fileList[1]] = false;
+              commentMap[element._fileList[2]] = true;
+              element._commentMap = commentMap;
+              element._path = element._fileList[1];
+
+              element._moveToNextFileWithComment();
+              assert.isFalse(navToChangeStub.called);
+              assert.isTrue(navToDiffStub.calledOnce);
+            });
+          });
+        });
       });
 
-      test('finds skips', () => {
-        const fileList = ['path/one.jpg', 'path/two.m4v', 'path/three.wav'];
-        let path = fileList[1];
-        const commentMap = {};
-        commentMap[fileList[0]] = true;
-        commentMap[fileList[1]] = false;
-        commentMap[fileList[2]] = true;
-
-        let result = element._computeCommentSkips(commentMap, fileList, path);
-        assert.equal(result.previous, fileList[0]);
-        assert.equal(result.next, fileList[2]);
-
-        commentMap[fileList[1]] = true;
-
-        result = element._computeCommentSkips(commentMap, fileList, path);
-        assert.equal(result.previous, fileList[0]);
-        assert.equal(result.next, fileList[2]);
-
-        path = fileList[0];
-
-        result = element._computeCommentSkips(commentMap, fileList, path);
-        assert.isNull(result.previous);
-        assert.equal(result.next, fileList[1]);
-
-        path = fileList[2];
-
-        result = element._computeCommentSkips(commentMap, fileList, path);
-        assert.equal(result.previous, fileList[1]);
-        assert.isNull(result.next);
+      test('_computeEditMode', () => {
+        const callCompute = range => element._computeEditMode({base: range});
+        assert.isFalse(callCompute({}));
+        assert.isFalse(callCompute({basePatchNum: 'PARENT', patchNum: 1}));
+        assert.isFalse(callCompute({basePatchNum: 'edit', patchNum: 1}));
+        assert.isTrue(callCompute({basePatchNum: 1, patchNum: 'edit'}));
       });
 
-      suite('skip next/previous', () => {
-        let navToChangeStub;
-        let navToDiffStub;
+      test('_computeFileNum', () => {
+        assert.equal(element._computeFileNum('/foo',
+            [{value: '/foo'}, {value: '/bar'}]), 1);
+        assert.equal(element._computeFileNum('/bar',
+            [{value: '/foo'}, {value: '/bar'}]), 2);
+      });
 
+      test('_computeFileNumClass', () => {
+        assert.equal(element._computeFileNumClass(0, []), '');
+        assert.equal(element._computeFileNumClass(1,
+            [{value: '/foo'}, {value: '/bar'}]), 'show');
+      });
+
+      test('_getReviewedStatus', () => {
+        const promises = [];
+        element.$.restAPI.getReviewedFiles.restore();
+
+        sandbox.stub(element.$.restAPI, 'getReviewedFiles')
+            .returns(Promise.resolve(['path']));
+
+        promises.push(element._getReviewedStatus(true, null, null, 'path')
+            .then(reviewed => assert.isFalse(reviewed)));
+
+        promises.push(element._getReviewedStatus(false, null, null, 'otherPath')
+            .then(reviewed => assert.isFalse(reviewed)));
+
+        promises.push(element._getReviewedStatus(false, null, null, 'path')
+            .then(reviewed => assert.isTrue(reviewed)));
+
+        return Promise.all(promises);
+      });
+
+      suite('editMode behavior', () => {
         setup(() => {
-          navToChangeStub = sandbox.stub(element, '_navToChangeView');
-          navToDiffStub = sandbox.stub(Gerrit.Nav, 'navigateToDiff');
-          element._files = getFilesFromFileList([
-            'path/one.jpg', 'path/two.m4v', 'path/three.wav',
-          ]);
-          element._patchRange = {patchNum: '2', basePatchNum: '1'};
+          element._loggedIn = true;
         });
 
-        suite('_moveToPreviousFileWithComment', () => {
-          test('no skips', () => {
-            element._moveToPreviousFileWithComment();
-            assert.isFalse(navToChangeStub.called);
-            assert.isFalse(navToDiffStub.called);
-          });
+        const isVisible = el => {
+          assert.ok(el);
+          return getComputedStyle(el).getPropertyValue('display') !== 'none';
+        };
 
-          test('no previous', () => {
-            const commentMap = {};
-            commentMap[element._fileList[0]] = false;
-            commentMap[element._fileList[1]] = false;
-            commentMap[element._fileList[2]] = true;
-            element._commentMap = commentMap;
-            element._path = element._fileList[1];
+        test('reviewed checkbox', () => {
+          sandbox.stub(element, '_handlePatchChange');
+          element._patchRange = {patchNum: '1'};
+          // Reviewed checkbox should be shown.
+          assert.isTrue(isVisible(element.$.reviewed));
+          element.set('_patchRange.patchNum', element.EDIT_NAME);
+          flushAsynchronousOperations();
 
-            element._moveToPreviousFileWithComment();
-            assert.isTrue(navToChangeStub.calledOnce);
-            assert.isFalse(navToDiffStub.called);
-          });
-
-          test('w/ previous', () => {
-            const commentMap = {};
-            commentMap[element._fileList[0]] = true;
-            commentMap[element._fileList[1]] = false;
-            commentMap[element._fileList[2]] = true;
-            element._commentMap = commentMap;
-            element._path = element._fileList[1];
-
-            element._moveToPreviousFileWithComment();
-            assert.isFalse(navToChangeStub.called);
-            assert.isTrue(navToDiffStub.calledOnce);
-          });
-        });
-
-        suite('_moveToNextFileWithComment', () => {
-          test('no skips', () => {
-            element._moveToNextFileWithComment();
-            assert.isFalse(navToChangeStub.called);
-            assert.isFalse(navToDiffStub.called);
-          });
-
-          test('no previous', () => {
-            const commentMap = {};
-            commentMap[element._fileList[0]] = true;
-            commentMap[element._fileList[1]] = false;
-            commentMap[element._fileList[2]] = false;
-            element._commentMap = commentMap;
-            element._path = element._fileList[1];
-
-            element._moveToNextFileWithComment();
-            assert.isTrue(navToChangeStub.calledOnce);
-            assert.isFalse(navToDiffStub.called);
-          });
-
-          test('w/ previous', () => {
-            const commentMap = {};
-            commentMap[element._fileList[0]] = true;
-            commentMap[element._fileList[1]] = false;
-            commentMap[element._fileList[2]] = true;
-            element._commentMap = commentMap;
-            element._path = element._fileList[1];
-
-            element._moveToNextFileWithComment();
-            assert.isFalse(navToChangeStub.called);
-            assert.isTrue(navToDiffStub.calledOnce);
-          });
+          assert.isFalse(isVisible(element.$.reviewed));
         });
       });
-    });
 
-    test('_computeEditMode', () => {
-      const callCompute = range => element._computeEditMode({base: range});
-      assert.isFalse(callCompute({}));
-      assert.isFalse(callCompute({basePatchNum: 'PARENT', patchNum: 1}));
-      assert.isFalse(callCompute({basePatchNum: 'edit', patchNum: 1}));
-      assert.isTrue(callCompute({basePatchNum: 1, patchNum: 'edit'}));
-    });
-
-    test('_computeFileNum', () => {
-      assert.equal(element._computeFileNum('/foo',
-          [{value: '/foo'}, {value: '/bar'}]), 1);
-      assert.equal(element._computeFileNum('/bar',
-          [{value: '/foo'}, {value: '/bar'}]), 2);
-    });
-
-    test('_computeFileNumClass', () => {
-      assert.equal(element._computeFileNumClass(0, []), '');
-      assert.equal(element._computeFileNumClass(1,
-          [{value: '/foo'}, {value: '/bar'}]), 'show');
-    });
-
-    test('_getReviewedStatus', () => {
-      const promises = [];
-      element.$.restAPI.getReviewedFiles.restore();
-
-      sandbox.stub(element.$.restAPI, 'getReviewedFiles')
-          .returns(Promise.resolve(['path']));
-
-      promises.push(element._getReviewedStatus(true, null, null, 'path')
-          .then(reviewed => assert.isFalse(reviewed)));
-
-      promises.push(element._getReviewedStatus(false, null, null, 'otherPath')
-          .then(reviewed => assert.isFalse(reviewed)));
-
-      promises.push(element._getReviewedStatus(false, null, null, 'path')
-          .then(reviewed => assert.isTrue(reviewed)));
-
-      return Promise.all(promises);
-    });
-
-    suite('editMode behavior', () => {
-      setup(() => {
-        element._loggedIn = true;
+      test('_paramsChanged sets in projectLookup', () => {
+        sandbox.stub(element, '_getLineOfInterest');
+        sandbox.stub(element, '_initCursor');
+        const setStub = sandbox.stub(element.$.restAPI, 'setInProjectLookup');
+        element._paramsChanged({
+          view: Gerrit.Nav.View.DIFF,
+          changeNum: 101,
+          project: 'test-project',
+          path: '',
+        });
+        assert.isTrue(setStub.calledOnce);
+        assert.isTrue(setStub.calledWith(101, 'test-project'));
       });
 
-      const isVisible = el => {
-        assert.ok(el);
-        return getComputedStyle(el).getPropertyValue('display') !== 'none';
-      };
-
-      test('reviewed checkbox', () => {
-        sandbox.stub(element, '_handlePatchChange');
-        element._patchRange = {patchNum: '1'};
-        // Reviewed checkbox should be shown.
-        assert.isTrue(isVisible(element.$.reviewed));
-        element.set('_patchRange.patchNum', element.EDIT_NAME);
+      test('shift+m navigates to next unreviewed file', () => {
+        element._files = getFilesFromFileList(['file1', 'file2', 'file3']);
+        element._reviewedFiles = new Set(['file1', 'file2']);
+        element._path = 'file1';
+        const reviewedStub = sandbox.stub(element, '_setReviewed');
+        const navStub = sandbox.stub(element, '_navToFile');
+        MockInteractions.pressAndReleaseKeyOn(element, 77, 'shift', 'm');
         flushAsynchronousOperations();
 
-        assert.isFalse(isVisible(element.$.reviewed));
-      });
-    });
-
-    test('_paramsChanged sets in projectLookup', () => {
-      sandbox.stub(element, '_getLineOfInterest');
-      sandbox.stub(element, '_initCursor');
-      const setStub = sandbox.stub(element.$.restAPI, 'setInProjectLookup');
-      element._paramsChanged({
-        view: Gerrit.Nav.View.DIFF,
-        changeNum: 101,
-        project: 'test-project',
-        path: '',
-      });
-      assert.isTrue(setStub.calledOnce);
-      assert.isTrue(setStub.calledWith(101, 'test-project'));
-    });
-
-    test('shift+m navigates to next unreviewed file', () => {
-      element._files = getFilesFromFileList(['file1', 'file2', 'file3']);
-      element._reviewedFiles = new Set(['file1', 'file2']);
-      element._path = 'file1';
-      const reviewedStub = sandbox.stub(element, '_setReviewed');
-      const navStub = sandbox.stub(element, '_navToFile');
-      MockInteractions.pressAndReleaseKeyOn(element, 77, 'shift', 'm');
-      flushAsynchronousOperations();
-
-      assert.isTrue(reviewedStub.lastCall.args[0]);
-      assert.deepEqual(navStub.lastCall.args, [
-        'file1',
-        ['file1', 'file3'],
-        1,
-      ]);
-    });
-
-    test('File change should trigger navigateToDiff once', () => {
-      element._files = getFilesFromFileList(['file1', 'file2', 'file3']);
-      sandbox.stub(element, '_getLineOfInterest');
-      sandbox.stub(element, '_initCursor');
-      sandbox.stub(Gerrit.Nav, 'navigateToDiff');
-
-      // Load file1
-      element._paramsChanged({
-        view: Gerrit.Nav.View.DIFF,
-        patchNum: 1,
-        changeNum: 101,
-        project: 'test-project',
-        path: 'file1',
-      });
-      assert.isTrue(Gerrit.Nav.navigateToDiff.notCalled);
-
-      // Switch to file2
-      element.$.dropdown.value = 'file2';
-      assert.isTrue(Gerrit.Nav.navigateToDiff.calledOnce);
-
-      // This is to mock the param change triggered by above navigate
-      element._paramsChanged({
-        view: Gerrit.Nav.View.DIFF,
-        patchNum: 1,
-        changeNum: 101,
-        project: 'test-project',
-        path: 'file2',
+        assert.isTrue(reviewedStub.lastCall.args[0]);
+        assert.deepEqual(navStub.lastCall.args, [
+          'file1',
+          ['file1', 'file3'],
+          1,
+        ]);
       });
 
-      // No extra call
-      assert.isTrue(Gerrit.Nav.navigateToDiff.calledOnce);
-    });
+      test('File change should trigger navigateToDiff once', () => {
+        element._files = getFilesFromFileList(['file1', 'file2', 'file3']);
+        sandbox.stub(element, '_getLineOfInterest');
+        sandbox.stub(element, '_initCursor');
+        sandbox.stub(Gerrit.Nav, 'navigateToDiff');
 
-    test('_computeDownloadDropdownLinks', () => {
-      const downloadLinks = [
-        {
-          url: '/changes/test~12/revisions/1/patch?zip&path=index.php',
-          name: 'Patch',
-        },
-        {
-          url: '/changes/test~12/revisions/1' +
-              '/files/index.php/download?parent=1',
-          name: 'Left Content',
-        },
-        {
-          url: '/changes/test~12/revisions/1' +
-              '/files/index.php/download',
-          name: 'Right Content',
-        },
-      ];
-
-      const side = {
-        meta_a: true,
-        meta_b: true,
-      };
-
-      const base = {
-        patchNum: 1,
-        basePatchNum: 'PARENT',
-      };
-
-      assert.deepEqual(
-          element._computeDownloadDropdownLinks(
-              'test', 12, base, 'index.php', side),
-          downloadLinks);
-    });
-
-    test('_computeDownloadDropdownLinks diff returns renamed', () => {
-      const downloadLinks = [
-        {
-          url: '/changes/test~12/revisions/3/patch?zip&path=index.php',
-          name: 'Patch',
-        },
-        {
-          url: '/changes/test~12/revisions/2' +
-              '/files/index2.php/download',
-          name: 'Left Content',
-        },
-        {
-          url: '/changes/test~12/revisions/3' +
-              '/files/index.php/download',
-          name: 'Right Content',
-        },
-      ];
-
-      const side = {
-        change_type: 'RENAMED',
-        meta_a: {
-          name: 'index2.php',
-        },
-        meta_b: true,
-      };
-
-      const base = {
-        patchNum: 3,
-        basePatchNum: 2,
-      };
-
-      assert.deepEqual(
-          element._computeDownloadDropdownLinks(
-              'test', 12, base, 'index.php', side),
-          downloadLinks);
-    });
-
-    test('_computeDownloadFileLink', () => {
-      const base = {
-        patchNum: 1,
-        basePatchNum: 'PARENT',
-      };
-
-      assert.equal(
-          element._computeDownloadFileLink(
-              'test', 12, base, 'index.php', true),
-          '/changes/test~12/revisions/1/files/index.php/download?parent=1');
-
-      assert.equal(
-          element._computeDownloadFileLink(
-              'test', 12, base, 'index.php', false),
-          '/changes/test~12/revisions/1/files/index.php/download');
-    });
-
-    test('_computeDownloadPatchLink', () => {
-      assert.equal(
-          element._computeDownloadPatchLink(
-              'test', 12, {patchNum: 1}, 'index.php'),
-          '/changes/test~12/revisions/1/patch?zip&path=index.php');
-    });
-  });
-
-  suite('gr-diff-view tests unmodified files with comments', () => {
-    setup(() => {
-      sandbox = sinon.sandbox.create();
-      const changedFiles = {
-        'file1.txt': {},
-        'a/b/test.c': {},
-      };
-      stub('gr-rest-api-interface', {
-        getConfig() { return Promise.resolve({change: {}}); },
-        getLoggedIn() { return Promise.resolve(false); },
-        getProjectConfig() { return Promise.resolve({}); },
-        getDiffChangeDetail() { return Promise.resolve({}); },
-        getChangeFiles() { return Promise.resolve(changedFiles); },
-        saveFileReviewed() { return Promise.resolve(); },
-        getDiffComments() { return Promise.resolve({}); },
-        getDiffRobotComments() { return Promise.resolve({}); },
-        getDiffDrafts() { return Promise.resolve({}); },
-        getReviewedFiles() { return Promise.resolve([]); },
-      });
-      element = fixture('basic');
-      return element._loadComments();
-    });
-
-    teardown(() => {
-      sandbox.restore();
-    });
-
-    test('_getFiles add files with comments without changes', () => {
-      const patchChangeRecord = {
-        base: {
-          basePatchNum: '5',
-          patchNum: '10',
-        },
-      };
-      const changeComments = {
-        getPaths: sandbox.stub().returns({'file2.txt': {}, 'file1.txt': {}}),
-      };
-      return element._getFiles(23, patchChangeRecord, changeComments).then(() => {
-        assert.deepEqual(element._files, {
-          sortedFileList: ['a/b/test.c', 'file1.txt', 'file2.txt'],
-          changeFilesByPath: {
-            'file1.txt': {},
-            'file2.txt': {status: 'U'},
-            'a/b/test.c': {},
-          },
+        // Load file1
+        element._paramsChanged({
+          view: Gerrit.Nav.View.DIFF,
+          patchNum: 1,
+          changeNum: 101,
+          project: 'test-project',
+          path: 'file1',
         });
+        assert.isTrue(Gerrit.Nav.navigateToDiff.notCalled);
+
+        // Switch to file2
+        element.$.dropdown.value = 'file2';
+        assert.isTrue(Gerrit.Nav.navigateToDiff.calledOnce);
+
+        // This is to mock the param change triggered by above navigate
+        element._paramsChanged({
+          view: Gerrit.Nav.View.DIFF,
+          patchNum: 1,
+          changeNum: 101,
+          project: 'test-project',
+          path: 'file2',
+        });
+
+        // No extra call
+        assert.isTrue(Gerrit.Nav.navigateToDiff.calledOnce);
+      });
+
+      test('_computeDownloadDropdownLinks', () => {
+        const downloadLinks = [
+          {
+            url: '/changes/test~12/revisions/1/patch?zip&path=index.php',
+            name: 'Patch',
+          },
+          {
+            url: '/changes/test~12/revisions/1' +
+                '/files/index.php/download?parent=1',
+            name: 'Left Content',
+          },
+          {
+            url: '/changes/test~12/revisions/1' +
+                '/files/index.php/download',
+            name: 'Right Content',
+          },
+        ];
+
+        const side = {
+          meta_a: true,
+          meta_b: true,
+        };
+
+        const base = {
+          patchNum: 1,
+          basePatchNum: 'PARENT',
+        };
+
+        assert.deepEqual(
+            element._computeDownloadDropdownLinks(
+                'test', 12, base, 'index.php', side),
+            downloadLinks);
+      });
+
+      test('_computeDownloadDropdownLinks diff returns renamed', () => {
+        const downloadLinks = [
+          {
+            url: '/changes/test~12/revisions/3/patch?zip&path=index.php',
+            name: 'Patch',
+          },
+          {
+            url: '/changes/test~12/revisions/2' +
+                '/files/index2.php/download',
+            name: 'Left Content',
+          },
+          {
+            url: '/changes/test~12/revisions/3' +
+                '/files/index.php/download',
+            name: 'Right Content',
+          },
+        ];
+
+        const side = {
+          change_type: 'RENAMED',
+          meta_a: {
+            name: 'index2.php',
+          },
+          meta_b: true,
+        };
+
+        const base = {
+          patchNum: 3,
+          basePatchNum: 2,
+        };
+
+        assert.deepEqual(
+            element._computeDownloadDropdownLinks(
+                'test', 12, base, 'index.php', side),
+            downloadLinks);
+      });
+
+      test('_computeDownloadFileLink', () => {
+        const base = {
+          patchNum: 1,
+          basePatchNum: 'PARENT',
+        };
+
+        assert.equal(
+            element._computeDownloadFileLink(
+                'test', 12, base, 'index.php', true),
+            '/changes/test~12/revisions/1/files/index.php/download?parent=1');
+
+        assert.equal(
+            element._computeDownloadFileLink(
+                'test', 12, base, 'index.php', false),
+            '/changes/test~12/revisions/1/files/index.php/download');
+      });
+
+      test('_computeDownloadPatchLink', () => {
+        assert.equal(
+            element._computeDownloadPatchLink(
+                'test', 12, {patchNum: 1}, 'index.php'),
+            '/changes/test~12/revisions/1/patch?zip&path=index.php');
+      });
+    });
+
+    suite('gr-diff-view tests unmodified files with comments', () => {
+      setup(() => {
+        sandbox = sinon.sandbox.create();
+        const changedFiles = {
+          'file1.txt': {},
+          'a/b/test.c': {},
+        };
+        stub('gr-rest-api-interface', {
+          getConfig() { return Promise.resolve({change: {}}); },
+          getLoggedIn() { return Promise.resolve(false); },
+          getProjectConfig() { return Promise.resolve({}); },
+          getDiffChangeDetail() { return Promise.resolve({}); },
+          getChangeFiles() { return Promise.resolve(changedFiles); },
+          saveFileReviewed() { return Promise.resolve(); },
+          getDiffComments() { return Promise.resolve({}); },
+          getDiffRobotComments() { return Promise.resolve({}); },
+          getDiffDrafts() { return Promise.resolve({}); },
+          getReviewedFiles() { return Promise.resolve([]); },
+        });
+        element = fixture('basic');
+        return element._loadComments();
+      });
+
+      teardown(() => {
+        sandbox.restore();
+      });
+
+      test('_getFiles add files with comments without changes', () => {
+        const patchChangeRecord = {
+          base: {
+            basePatchNum: '5',
+            patchNum: '10',
+          },
+        };
+        const changeComments = {
+          getPaths: sandbox.stub().returns({
+            'file2.txt': {},
+            'file1.txt': {},
+          }),
+        };
+        return element._getFiles(23, patchChangeRecord, changeComments)
+            .then(() => {
+              assert.deepEqual(element._files, {
+                sortedFileList: ['a/b/test.c', 'file1.txt', 'file2.txt'],
+                changeFilesByPath: {
+                  'file1.txt': {},
+                  'file2.txt': {status: 'U'},
+                  'a/b/test.c': {},
+                },
+              });
+            });
       });
     });
   });
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-group_test.html b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-group_test.html
index 686410c..00907d6 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-group_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-group_test.html
@@ -22,12 +22,14 @@
 <script src="/bower_components/webcomponentsjs/custom-elements-es5-adapter.js"></script>
 
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="gr-diff-line.js"></script>
 <script src="gr-diff-group.js"></script>
 
 <script>
-  suite('gr-diff-group tests', () => {
+  suite('gr-diff-group tests', async () => {
+    await readyToTest();
     test('delta line pairs', () => {
       let group = new GrDiffGroup(GrDiffGroup.Type.DELTA);
       const l1 = new GrDiffLine(GrDiffLine.Type.ADD, 0, 128);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html
index 4301ac2..8380984 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html
@@ -278,7 +278,7 @@
       td.blame > span.startOfRange {
         opacity: 1;
       }
-      td.blame .sha {
+      td.blame .blameDate {
         font-family: var(--monospace-font-family);
         color: var(--link-color);
         cursor: pointer;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
index 2805eb4..9fcf1ca 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
@@ -23,6 +23,8 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
+<script src="/components/web-component-tester/data/a11ySuite.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="../../../scripts/util.js"></script>
 
@@ -39,7 +41,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-diff tests', () => {
+  suite('gr-diff tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.html b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.html
index 4cb618f..a53d399 100644
--- a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="/bower_components/page/page.js"></script>
 
@@ -50,7 +51,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-patch-range-select tests', () => {
+  suite('gr-patch-range-select tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
     let commentApiWrapper;
diff --git a/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer_test.html b/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer_test.html
index 4ed744b..48883c1 100644
--- a/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="../gr-diff/gr-diff-line.js"></script>
 
@@ -37,7 +38,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-ranged-comment-layer', () => {
+  suite('gr-ranged-comment-layer', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box_test.html b/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box_test.html
index 57adf32..bb802f8 100644
--- a/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-selection-action-box.html">
 
@@ -38,7 +39,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-selection-action-box', () => {
+  suite('gr-selection-action-box', async () => {
+    await readyToTest();
     let container;
     let element;
     let sandbox;
diff --git a/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer_test.html b/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer_test.html
index 88fd3b9..62a3f1e 100644
--- a/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="../../shared/gr-rest-api-interface/mock-diff-response_test.html">
 <link rel="import" href="gr-syntax-layer.html">
@@ -36,7 +37,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-syntax-layer tests', () => {
+  suite('gr-syntax-layer tests', async () => {
+    await readyToTest();
     let sandbox;
     let diff;
     let element;
diff --git a/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search_test.html b/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search_test.html
index d604b1f..09268de 100644
--- a/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search_test.html
+++ b/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search_test.html
@@ -24,6 +24,7 @@
 <script src="/bower_components/page/page.js"></script>
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-documentation-search.html">
 
@@ -44,7 +45,8 @@
     };
   };
 
-  suite('gr-documentation-search tests', () => {
+  suite('gr-documentation-search tests', async () => {
+    await readyToTest();
     let element;
     let documentationSearches;
     let sandbox;
diff --git a/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor_test.html b/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor_test.html
index 4635b1c..228c70e 100644
--- a/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor_test.html
+++ b/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor_test.html
@@ -22,6 +22,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 
 <link rel="import" href="gr-default-editor.html">
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-default-editor tests', () => {
+  suite('gr-default-editor tests', async () => {
+    await readyToTest();
     let element;
 
     setup(() => {
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.html b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.html
index 277bb78..d66a8bb 100644
--- a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.html
+++ b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.html
@@ -22,6 +22,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 
 <link rel="import" href="gr-edit-controls.html">
@@ -35,338 +36,339 @@
 </test-fixture>
 
 <script>
-suite('gr-edit-controls tests', () => {
-  let element;
-  let sandbox;
-  let showDialogSpy;
-  let closeDialogSpy;
-  let queryStub;
-
-  setup(() => {
-    sandbox = sinon.sandbox.create();
-    element = fixture('basic');
-    element.change = {_number: '42'};
-    showDialogSpy = sandbox.spy(element, '_showDialog');
-    closeDialogSpy = sandbox.spy(element, '_closeDialog');
-    sandbox.stub(element, '_hideAllDialogs');
-    queryStub = sandbox.stub(element.$.restAPI, 'queryChangeFiles')
-        .returns(Promise.resolve([]));
-    flushAsynchronousOperations();
-  });
-
-  teardown(() => { sandbox.restore(); });
-
-  test('all actions exist', () => {
-    assert.equal(Polymer.dom(element.root).querySelectorAll('gr-button').length,
-        element._actions.length);
-  });
-
-  suite('edit button CUJ', () => {
-    let navStubs;
-    let openAutoCcmplete;
-
+  suite('gr-edit-controls tests', async () => {
+    await readyToTest();
+    let element;
+    let sandbox;
+    let showDialogSpy;
+    let closeDialogSpy;
+    let queryStub;
+  
     setup(() => {
-      navStubs = [
-        sandbox.stub(Gerrit.Nav, 'getEditUrlForDiff'),
-        sandbox.stub(Gerrit.Nav, 'navigateToRelativeUrl'),
-      ];
-      openAutoCcmplete = element.$.openDialog.querySelector('gr-autocomplete');
+      sandbox = sinon.sandbox.create();
+      element = fixture('basic');
+      element.change = {_number: '42'};
+      showDialogSpy = sandbox.spy(element, '_showDialog');
+      closeDialogSpy = sandbox.spy(element, '_closeDialog');
+      sandbox.stub(element, '_hideAllDialogs');
+      queryStub = sandbox.stub(element.$.restAPI, 'queryChangeFiles')
+          .returns(Promise.resolve([]));
+      flushAsynchronousOperations();
     });
-
-    test('_isValidPath', () => {
-      assert.isFalse(element._isValidPath(''));
-      assert.isFalse(element._isValidPath('test/'));
-      assert.isFalse(element._isValidPath('/'));
-      assert.isTrue(element._isValidPath('test/path.cpp'));
-      assert.isTrue(element._isValidPath('test.js'));
+  
+    teardown(() => { sandbox.restore(); });
+  
+    test('all actions exist', () => {
+      assert.equal(Polymer.dom(element.root).querySelectorAll('gr-button').length,
+          element._actions.length);
     });
-
-    test('open', () => {
-      MockInteractions.tap(element.shadowRoot.querySelector('#open'));
-      element.patchNum = 1;
-      return showDialogSpy.lastCall.returnValue.then(() => {
-        assert.isTrue(element._hideAllDialogs.called);
-        assert.isTrue(element.$.openDialog.disabled);
-        assert.isFalse(queryStub.called);
-        openAutoCcmplete.noDebounce = true;
-        openAutoCcmplete.text = 'src/test.cpp';
-        assert.isTrue(queryStub.called);
-        assert.isFalse(element.$.openDialog.disabled);
-        MockInteractions.tap(element.$.openDialog.$$('gr-button[primary]'));
-        for (const stub of navStubs) { assert.isTrue(stub.called); }
-        assert.deepEqual(Gerrit.Nav.getEditUrlForDiff.lastCall.args,
-            [element.change, 'src/test.cpp', element.patchNum]);
-        assert.isTrue(closeDialogSpy.called);
+  
+    suite('edit button CUJ', () => {
+      let navStubs;
+      let openAutoCcmplete;
+  
+      setup(() => {
+        navStubs = [
+          sandbox.stub(Gerrit.Nav, 'getEditUrlForDiff'),
+          sandbox.stub(Gerrit.Nav, 'navigateToRelativeUrl'),
+        ];
+        openAutoCcmplete = element.$.openDialog.querySelector('gr-autocomplete');
       });
-    });
-
-    test('cancel', () => {
-      MockInteractions.tap(element.shadowRoot.querySelector('#open'));
-      return showDialogSpy.lastCall.returnValue.then(() => {
-        assert.isTrue(element.$.openDialog.disabled);
-        openAutoCcmplete.noDebounce = true;
-        openAutoCcmplete.text = 'src/test.cpp';
-        assert.isFalse(element.$.openDialog.disabled);
-        MockInteractions.tap(element.$.openDialog.$$('gr-button'));
-        for (const stub of navStubs) { assert.isFalse(stub.called); }
-        assert.isTrue(closeDialogSpy.called);
-        assert.equal(element._path, 'src/test.cpp');
+  
+      test('_isValidPath', () => {
+        assert.isFalse(element._isValidPath(''));
+        assert.isFalse(element._isValidPath('test/'));
+        assert.isFalse(element._isValidPath('/'));
+        assert.isTrue(element._isValidPath('test/path.cpp'));
+        assert.isTrue(element._isValidPath('test.js'));
       });
-    });
-  });
-
-  suite('delete button CUJ', () => {
-    let navStub;
-    let deleteStub;
-    let deleteAutocomplete;
-
-    setup(() => {
-      navStub = sandbox.stub(Gerrit.Nav, 'navigateToChange');
-      deleteStub = sandbox.stub(element.$.restAPI, 'deleteFileInChangeEdit');
-      deleteAutocomplete =
-          element.$.deleteDialog.querySelector('gr-autocomplete');
-    });
-
-    test('delete', () => {
-      deleteStub.returns(Promise.resolve({ok: true}));
-      MockInteractions.tap(element.shadowRoot.querySelector('#delete'));
-      return showDialogSpy.lastCall.returnValue.then(() => {
-        assert.isTrue(element.$.deleteDialog.disabled);
-        assert.isFalse(queryStub.called);
-        deleteAutocomplete.noDebounce = true;
-        deleteAutocomplete.text = 'src/test.cpp';
-        assert.isTrue(queryStub.called);
-        assert.isFalse(element.$.deleteDialog.disabled);
-        MockInteractions.tap(element.$.deleteDialog.$$('gr-button[primary]'));
-        flushAsynchronousOperations();
-
-        assert.isTrue(deleteStub.called);
-
-        return deleteStub.lastCall.returnValue.then(() => {
-          assert.equal(element._path, '');
-          assert.isTrue(navStub.called);
+  
+      test('open', () => {
+        MockInteractions.tap(element.shadowRoot.querySelector('#open'));
+        element.patchNum = 1;
+        return showDialogSpy.lastCall.returnValue.then(() => {
+          assert.isTrue(element._hideAllDialogs.called);
+          assert.isTrue(element.$.openDialog.disabled);
+          assert.isFalse(queryStub.called);
+          openAutoCcmplete.noDebounce = true;
+          openAutoCcmplete.text = 'src/test.cpp';
+          assert.isTrue(queryStub.called);
+          assert.isFalse(element.$.openDialog.disabled);
+          MockInteractions.tap(element.$.openDialog.$$('gr-button[primary]'));
+          for (const stub of navStubs) { assert.isTrue(stub.called); }
+          assert.deepEqual(Gerrit.Nav.getEditUrlForDiff.lastCall.args,
+              [element.change, 'src/test.cpp', element.patchNum]);
           assert.isTrue(closeDialogSpy.called);
         });
       });
-    });
-
-    test('delete fails', () => {
-      deleteStub.returns(Promise.resolve({ok: false}));
-      MockInteractions.tap(element.shadowRoot.querySelector('#delete'));
-      return showDialogSpy.lastCall.returnValue.then(() => {
-        assert.isTrue(element.$.deleteDialog.disabled);
-        assert.isFalse(queryStub.called);
-        deleteAutocomplete.noDebounce = true;
-        deleteAutocomplete.text = 'src/test.cpp';
-        assert.isTrue(queryStub.called);
-        assert.isFalse(element.$.deleteDialog.disabled);
-        MockInteractions.tap(element.$.deleteDialog.$$('gr-button[primary]'));
-        flushAsynchronousOperations();
-
-        assert.isTrue(deleteStub.called);
-
-        return deleteStub.lastCall.returnValue.then(() => {
-          assert.isFalse(navStub.called);
-          assert.isFalse(closeDialogSpy.called);
-        });
-      });
-    });
-
-    test('cancel', () => {
-      MockInteractions.tap(element.shadowRoot.querySelector('#delete'));
-      return showDialogSpy.lastCall.returnValue.then(() => {
-        assert.isTrue(element.$.deleteDialog.disabled);
-        element.$.deleteDialog.querySelector('gr-autocomplete').text =
-            'src/test.cpp';
-        assert.isFalse(element.$.deleteDialog.disabled);
-        MockInteractions.tap(element.$.deleteDialog.$$('gr-button'));
-        assert.isFalse(navStub.called);
-        assert.isTrue(closeDialogSpy.called);
-        assert.equal(element._path, 'src/test.cpp');
-      });
-    });
-  });
-
-  suite('rename button CUJ', () => {
-    let navStub;
-    let renameStub;
-    let renameAutocomplete;
-    const inputSelector = Polymer.Element ?
-      '.newPathIronInput' :
-      '.newPathInput';
-
-    setup(() => {
-      navStub = sandbox.stub(Gerrit.Nav, 'navigateToChange');
-      renameStub = sandbox.stub(element.$.restAPI, 'renameFileInChangeEdit');
-      renameAutocomplete =
-          element.$.renameDialog.querySelector('gr-autocomplete');
-    });
-
-    test('rename', () => {
-      renameStub.returns(Promise.resolve({ok: true}));
-      MockInteractions.tap(element.shadowRoot.querySelector('#rename'));
-      return showDialogSpy.lastCall.returnValue.then(() => {
-        assert.isTrue(element.$.renameDialog.disabled);
-        assert.isFalse(queryStub.called);
-        renameAutocomplete.noDebounce = true;
-        renameAutocomplete.text = 'src/test.cpp';
-        assert.isTrue(queryStub.called);
-        assert.isTrue(element.$.renameDialog.disabled);
-
-        element.$.renameDialog.querySelector(inputSelector).bindValue =
-            'src/test.newPath';
-
-        assert.isFalse(element.$.renameDialog.disabled);
-        MockInteractions.tap(element.$.renameDialog.$$('gr-button[primary]'));
-        flushAsynchronousOperations();
-
-        assert.isTrue(renameStub.called);
-
-        return renameStub.lastCall.returnValue.then(() => {
-          assert.equal(element._path, '');
-          assert.isTrue(navStub.called);
+  
+      test('cancel', () => {
+        MockInteractions.tap(element.shadowRoot.querySelector('#open'));
+        return showDialogSpy.lastCall.returnValue.then(() => {
+          assert.isTrue(element.$.openDialog.disabled);
+          openAutoCcmplete.noDebounce = true;
+          openAutoCcmplete.text = 'src/test.cpp';
+          assert.isFalse(element.$.openDialog.disabled);
+          MockInteractions.tap(element.$.openDialog.$$('gr-button'));
+          for (const stub of navStubs) { assert.isFalse(stub.called); }
           assert.isTrue(closeDialogSpy.called);
+          assert.equal(element._path, 'src/test.cpp');
         });
       });
     });
-
-    test('rename fails', () => {
-      renameStub.returns(Promise.resolve({ok: false}));
-      MockInteractions.tap(element.shadowRoot.querySelector('#rename'));
-      return showDialogSpy.lastCall.returnValue.then(() => {
-        assert.isTrue(element.$.renameDialog.disabled);
-        assert.isFalse(queryStub.called);
-        renameAutocomplete.noDebounce = true;
-        renameAutocomplete.text = 'src/test.cpp';
-        assert.isTrue(queryStub.called);
-        assert.isTrue(element.$.renameDialog.disabled);
-
-        element.$.renameDialog.querySelector(inputSelector).bindValue =
-            'src/test.newPath';
-
-        assert.isFalse(element.$.renameDialog.disabled);
-        MockInteractions.tap(element.$.renameDialog.$$('gr-button[primary]'));
-        flushAsynchronousOperations();
-
-        assert.isTrue(renameStub.called);
-
-        return renameStub.lastCall.returnValue.then(() => {
+  
+    suite('delete button CUJ', () => {
+      let navStub;
+      let deleteStub;
+      let deleteAutocomplete;
+  
+      setup(() => {
+        navStub = sandbox.stub(Gerrit.Nav, 'navigateToChange');
+        deleteStub = sandbox.stub(element.$.restAPI, 'deleteFileInChangeEdit');
+        deleteAutocomplete =
+            element.$.deleteDialog.querySelector('gr-autocomplete');
+      });
+  
+      test('delete', () => {
+        deleteStub.returns(Promise.resolve({ok: true}));
+        MockInteractions.tap(element.shadowRoot.querySelector('#delete'));
+        return showDialogSpy.lastCall.returnValue.then(() => {
+          assert.isTrue(element.$.deleteDialog.disabled);
+          assert.isFalse(queryStub.called);
+          deleteAutocomplete.noDebounce = true;
+          deleteAutocomplete.text = 'src/test.cpp';
+          assert.isTrue(queryStub.called);
+          assert.isFalse(element.$.deleteDialog.disabled);
+          MockInteractions.tap(element.$.deleteDialog.$$('gr-button[primary]'));
+          flushAsynchronousOperations();
+  
+          assert.isTrue(deleteStub.called);
+  
+          return deleteStub.lastCall.returnValue.then(() => {
+            assert.equal(element._path, '');
+            assert.isTrue(navStub.called);
+            assert.isTrue(closeDialogSpy.called);
+          });
+        });
+      });
+  
+      test('delete fails', () => {
+        deleteStub.returns(Promise.resolve({ok: false}));
+        MockInteractions.tap(element.shadowRoot.querySelector('#delete'));
+        return showDialogSpy.lastCall.returnValue.then(() => {
+          assert.isTrue(element.$.deleteDialog.disabled);
+          assert.isFalse(queryStub.called);
+          deleteAutocomplete.noDebounce = true;
+          deleteAutocomplete.text = 'src/test.cpp';
+          assert.isTrue(queryStub.called);
+          assert.isFalse(element.$.deleteDialog.disabled);
+          MockInteractions.tap(element.$.deleteDialog.$$('gr-button[primary]'));
+          flushAsynchronousOperations();
+  
+          assert.isTrue(deleteStub.called);
+  
+          return deleteStub.lastCall.returnValue.then(() => {
+            assert.isFalse(navStub.called);
+            assert.isFalse(closeDialogSpy.called);
+          });
+        });
+      });
+  
+      test('cancel', () => {
+        MockInteractions.tap(element.shadowRoot.querySelector('#delete'));
+        return showDialogSpy.lastCall.returnValue.then(() => {
+          assert.isTrue(element.$.deleteDialog.disabled);
+          element.$.deleteDialog.querySelector('gr-autocomplete').text =
+              'src/test.cpp';
+          assert.isFalse(element.$.deleteDialog.disabled);
+          MockInteractions.tap(element.$.deleteDialog.$$('gr-button'));
           assert.isFalse(navStub.called);
-          assert.isFalse(closeDialogSpy.called);
-        });
-      });
-    });
-
-    test('cancel', () => {
-      MockInteractions.tap(element.shadowRoot.querySelector('#rename'));
-      return showDialogSpy.lastCall.returnValue.then(() => {
-        assert.isTrue(element.$.renameDialog.disabled);
-        element.$.renameDialog.querySelector('gr-autocomplete').text =
-            'src/test.cpp';
-        element.$.renameDialog.querySelector(inputSelector).bindValue =
-            'src/test.newPath';
-        assert.isFalse(element.$.renameDialog.disabled);
-        MockInteractions.tap(element.$.renameDialog.$$('gr-button'));
-        assert.isFalse(navStub.called);
-        assert.isTrue(closeDialogSpy.called);
-        assert.equal(element._path, 'src/test.cpp');
-        assert.equal(element._newPath, 'src/test.newPath');
-      });
-    });
-  });
-
-  suite('restore button CUJ', () => {
-    let navStub;
-    let restoreStub;
-
-    setup(() => {
-      navStub = sandbox.stub(Gerrit.Nav, 'navigateToChange');
-      restoreStub = sandbox.stub(element.$.restAPI, 'restoreFileInChangeEdit');
-    });
-
-    test('restore hidden by default', () => {
-      assert.isTrue(element.shadowRoot
-          .querySelector('#restore').classList.contains('invisible'));
-    });
-
-    test('restore', () => {
-      restoreStub.returns(Promise.resolve({ok: true}));
-      element._path = 'src/test.cpp';
-      MockInteractions.tap(element.shadowRoot.querySelector('#restore'));
-      return showDialogSpy.lastCall.returnValue.then(() => {
-        MockInteractions.tap(element.$.restoreDialog.$$('gr-button[primary]'));
-        flushAsynchronousOperations();
-
-        assert.isTrue(restoreStub.called);
-        assert.equal(restoreStub.lastCall.args[1], 'src/test.cpp');
-        return restoreStub.lastCall.returnValue.then(() => {
-          assert.equal(element._path, '');
-          assert.isTrue(navStub.called);
           assert.isTrue(closeDialogSpy.called);
+          assert.equal(element._path, 'src/test.cpp');
         });
       });
     });
-
-    test('restore fails', () => {
-      restoreStub.returns(Promise.resolve({ok: false}));
-      element._path = 'src/test.cpp';
-      MockInteractions.tap(element.shadowRoot.querySelector('#restore'));
-      return showDialogSpy.lastCall.returnValue.then(() => {
-        MockInteractions.tap(element.$.restoreDialog.$$('gr-button[primary]'));
-        flushAsynchronousOperations();
-
-        assert.isTrue(restoreStub.called);
-        assert.equal(restoreStub.lastCall.args[1], 'src/test.cpp');
-        return restoreStub.lastCall.returnValue.then(() => {
+  
+    suite('rename button CUJ', () => {
+      let navStub;
+      let renameStub;
+      let renameAutocomplete;
+      const inputSelector = Polymer.Element ?
+        '.newPathIronInput' :
+        '.newPathInput';
+  
+      setup(() => {
+        navStub = sandbox.stub(Gerrit.Nav, 'navigateToChange');
+        renameStub = sandbox.stub(element.$.restAPI, 'renameFileInChangeEdit');
+        renameAutocomplete =
+            element.$.renameDialog.querySelector('gr-autocomplete');
+      });
+  
+      test('rename', () => {
+        renameStub.returns(Promise.resolve({ok: true}));
+        MockInteractions.tap(element.shadowRoot.querySelector('#rename'));
+        return showDialogSpy.lastCall.returnValue.then(() => {
+          assert.isTrue(element.$.renameDialog.disabled);
+          assert.isFalse(queryStub.called);
+          renameAutocomplete.noDebounce = true;
+          renameAutocomplete.text = 'src/test.cpp';
+          assert.isTrue(queryStub.called);
+          assert.isTrue(element.$.renameDialog.disabled);
+  
+          element.$.renameDialog.querySelector(inputSelector).bindValue =
+              'src/test.newPath';
+  
+          assert.isFalse(element.$.renameDialog.disabled);
+          MockInteractions.tap(element.$.renameDialog.$$('gr-button[primary]'));
+          flushAsynchronousOperations();
+  
+          assert.isTrue(renameStub.called);
+  
+          return renameStub.lastCall.returnValue.then(() => {
+            assert.equal(element._path, '');
+            assert.isTrue(navStub.called);
+            assert.isTrue(closeDialogSpy.called);
+          });
+        });
+      });
+  
+      test('rename fails', () => {
+        renameStub.returns(Promise.resolve({ok: false}));
+        MockInteractions.tap(element.shadowRoot.querySelector('#rename'));
+        return showDialogSpy.lastCall.returnValue.then(() => {
+          assert.isTrue(element.$.renameDialog.disabled);
+          assert.isFalse(queryStub.called);
+          renameAutocomplete.noDebounce = true;
+          renameAutocomplete.text = 'src/test.cpp';
+          assert.isTrue(queryStub.called);
+          assert.isTrue(element.$.renameDialog.disabled);
+  
+          element.$.renameDialog.querySelector(inputSelector).bindValue =
+              'src/test.newPath';
+  
+          assert.isFalse(element.$.renameDialog.disabled);
+          MockInteractions.tap(element.$.renameDialog.$$('gr-button[primary]'));
+          flushAsynchronousOperations();
+  
+          assert.isTrue(renameStub.called);
+  
+          return renameStub.lastCall.returnValue.then(() => {
+            assert.isFalse(navStub.called);
+            assert.isFalse(closeDialogSpy.called);
+          });
+        });
+      });
+  
+      test('cancel', () => {
+        MockInteractions.tap(element.shadowRoot.querySelector('#rename'));
+        return showDialogSpy.lastCall.returnValue.then(() => {
+          assert.isTrue(element.$.renameDialog.disabled);
+          element.$.renameDialog.querySelector('gr-autocomplete').text =
+              'src/test.cpp';
+          element.$.renameDialog.querySelector(inputSelector).bindValue =
+              'src/test.newPath';
+          assert.isFalse(element.$.renameDialog.disabled);
+          MockInteractions.tap(element.$.renameDialog.$$('gr-button'));
           assert.isFalse(navStub.called);
-          assert.isFalse(closeDialogSpy.called);
+          assert.isTrue(closeDialogSpy.called);
+          assert.equal(element._path, 'src/test.cpp');
+          assert.equal(element._newPath, 'src/test.newPath');
         });
       });
     });
-
-    test('cancel', () => {
-      element._path = 'src/test.cpp';
-      MockInteractions.tap(element.shadowRoot.querySelector('#restore'));
-      return showDialogSpy.lastCall.returnValue.then(() => {
-        MockInteractions.tap(element.$.restoreDialog.$$('gr-button'));
-        assert.isFalse(navStub.called);
-        assert.isTrue(closeDialogSpy.called);
-        assert.equal(element._path, 'src/test.cpp');
+  
+    suite('restore button CUJ', () => {
+      let navStub;
+      let restoreStub;
+  
+      setup(() => {
+        navStub = sandbox.stub(Gerrit.Nav, 'navigateToChange');
+        restoreStub = sandbox.stub(element.$.restAPI, 'restoreFileInChangeEdit');
+      });
+  
+      test('restore hidden by default', () => {
+        assert.isTrue(element.shadowRoot
+            .querySelector('#restore').classList.contains('invisible'));
+      });
+  
+      test('restore', () => {
+        restoreStub.returns(Promise.resolve({ok: true}));
+        element._path = 'src/test.cpp';
+        MockInteractions.tap(element.shadowRoot.querySelector('#restore'));
+        return showDialogSpy.lastCall.returnValue.then(() => {
+          MockInteractions.tap(element.$.restoreDialog.$$('gr-button[primary]'));
+          flushAsynchronousOperations();
+  
+          assert.isTrue(restoreStub.called);
+          assert.equal(restoreStub.lastCall.args[1], 'src/test.cpp');
+          return restoreStub.lastCall.returnValue.then(() => {
+            assert.equal(element._path, '');
+            assert.isTrue(navStub.called);
+            assert.isTrue(closeDialogSpy.called);
+          });
+        });
+      });
+  
+      test('restore fails', () => {
+        restoreStub.returns(Promise.resolve({ok: false}));
+        element._path = 'src/test.cpp';
+        MockInteractions.tap(element.shadowRoot.querySelector('#restore'));
+        return showDialogSpy.lastCall.returnValue.then(() => {
+          MockInteractions.tap(element.$.restoreDialog.$$('gr-button[primary]'));
+          flushAsynchronousOperations();
+  
+          assert.isTrue(restoreStub.called);
+          assert.equal(restoreStub.lastCall.args[1], 'src/test.cpp');
+          return restoreStub.lastCall.returnValue.then(() => {
+            assert.isFalse(navStub.called);
+            assert.isFalse(closeDialogSpy.called);
+          });
+        });
+      });
+  
+      test('cancel', () => {
+        element._path = 'src/test.cpp';
+        MockInteractions.tap(element.shadowRoot.querySelector('#restore'));
+        return showDialogSpy.lastCall.returnValue.then(() => {
+          MockInteractions.tap(element.$.restoreDialog.$$('gr-button'));
+          assert.isFalse(navStub.called);
+          assert.isTrue(closeDialogSpy.called);
+          assert.equal(element._path, 'src/test.cpp');
+        });
       });
     });
+  
+    test('openOpenDialog', done => {
+      element.openOpenDialog('test/path.cpp')
+          .then(() => {
+            assert.isFalse(element.$.openDialog.hasAttribute('hidden'));
+            assert.equal(
+                element.$.openDialog.querySelector('gr-autocomplete').text,
+                'test/path.cpp');
+            done();
+          });
+    });
+  
+    test('_getDialogFromEvent', () => {
+      const spy = sandbox.spy(element, '_getDialogFromEvent');
+      element.addEventListener('tap', element._getDialogFromEvent);
+  
+      MockInteractions.tap(element.$.openDialog);
+      flushAsynchronousOperations();
+      assert.equal(spy.lastCall.returnValue.id, 'openDialog');
+  
+      MockInteractions.tap(element.$.deleteDialog);
+      flushAsynchronousOperations();
+      assert.equal(spy.lastCall.returnValue.id, 'deleteDialog');
+  
+      MockInteractions.tap(
+          element.$.deleteDialog.querySelector('gr-autocomplete'));
+      flushAsynchronousOperations();
+      assert.equal(spy.lastCall.returnValue.id, 'deleteDialog');
+  
+      MockInteractions.tap(element);
+      flushAsynchronousOperations();
+      assert.notOk(spy.lastCall.returnValue);
+    });
   });
-
-  test('openOpenDialog', done => {
-    element.openOpenDialog('test/path.cpp')
-        .then(() => {
-          assert.isFalse(element.$.openDialog.hasAttribute('hidden'));
-          assert.equal(
-              element.$.openDialog.querySelector('gr-autocomplete').text,
-              'test/path.cpp');
-          done();
-        });
-  });
-
-  test('_getDialogFromEvent', () => {
-    const spy = sandbox.spy(element, '_getDialogFromEvent');
-    element.addEventListener('tap', element._getDialogFromEvent);
-
-    MockInteractions.tap(element.$.openDialog);
-    flushAsynchronousOperations();
-    assert.equal(spy.lastCall.returnValue.id, 'openDialog');
-
-    MockInteractions.tap(element.$.deleteDialog);
-    flushAsynchronousOperations();
-    assert.equal(spy.lastCall.returnValue.id, 'deleteDialog');
-
-    MockInteractions.tap(
-        element.$.deleteDialog.querySelector('gr-autocomplete'));
-    flushAsynchronousOperations();
-    assert.equal(spy.lastCall.returnValue.id, 'deleteDialog');
-
-    MockInteractions.tap(element);
-    flushAsynchronousOperations();
-    assert.notOk(spy.lastCall.returnValue);
-  });
-});
 </script>
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls_test.html b/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls_test.html
index dc26468..bc1ee35 100644
--- a/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls_test.html
+++ b/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls_test.html
@@ -22,6 +22,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 
 <link rel="import" href="../gr-edit-constants.html">
@@ -36,70 +37,71 @@
 </test-fixture>
 
 <script>
-suite('gr-edit-file-controls tests', () => {
-  let element;
-  let sandbox;
-  let fileActionHandler;
-
-  setup(() => {
-    sandbox = sinon.sandbox.create();
-    element = fixture('basic');
-    fileActionHandler = sandbox.stub();
-    element.addEventListener('file-action-tap', fileActionHandler);
+  suite('gr-edit-file-controls tests', async () => {
+    await readyToTest();
+    let element;
+    let sandbox;
+    let fileActionHandler;
+  
+    setup(() => {
+      sandbox = sinon.sandbox.create();
+      element = fixture('basic');
+      fileActionHandler = sandbox.stub();
+      element.addEventListener('file-action-tap', fileActionHandler);
+    });
+  
+    teardown(() => { sandbox.restore(); });
+  
+    test('open tap emits event', () => {
+      const actions = element.$.actions;
+      element.filePath = 'foo';
+      actions._open();
+      flushAsynchronousOperations();
+  
+      MockInteractions.tap(actions.$$('li [data-id="open"]'));
+      assert.isTrue(fileActionHandler.called);
+      assert.deepEqual(fileActionHandler.lastCall.args[0].detail,
+          {action: GrEditConstants.Actions.OPEN.id, path: 'foo'});
+    });
+  
+    test('delete tap emits event', () => {
+      const actions = element.$.actions;
+      element.filePath = 'foo';
+      actions._open();
+      flushAsynchronousOperations();
+  
+      MockInteractions.tap(actions.$$('li [data-id="delete"]'));
+      assert.isTrue(fileActionHandler.called);
+      assert.deepEqual(fileActionHandler.lastCall.args[0].detail,
+          {action: GrEditConstants.Actions.DELETE.id, path: 'foo'});
+    });
+  
+    test('restore tap emits event', () => {
+      const actions = element.$.actions;
+      element.filePath = 'foo';
+      actions._open();
+      flushAsynchronousOperations();
+  
+      MockInteractions.tap(actions.$$('li [data-id="restore"]'));
+      assert.isTrue(fileActionHandler.called);
+      assert.deepEqual(fileActionHandler.lastCall.args[0].detail,
+          {action: GrEditConstants.Actions.RESTORE.id, path: 'foo'});
+    });
+  
+    test('rename tap emits event', () => {
+      const actions = element.$.actions;
+      element.filePath = 'foo';
+      actions._open();
+      flushAsynchronousOperations();
+  
+      MockInteractions.tap(actions.$$('li [data-id="rename"]'));
+      assert.isTrue(fileActionHandler.called);
+      assert.deepEqual(fileActionHandler.lastCall.args[0].detail,
+          {action: GrEditConstants.Actions.RENAME.id, path: 'foo'});
+    });
+  
+    test('computed properties', () => {
+      assert.equal(element._allFileActions.length, 4);
+    });
   });
-
-  teardown(() => { sandbox.restore(); });
-
-  test('open tap emits event', () => {
-    const actions = element.$.actions;
-    element.filePath = 'foo';
-    actions._open();
-    flushAsynchronousOperations();
-
-    MockInteractions.tap(actions.$$('li [data-id="open"]'));
-    assert.isTrue(fileActionHandler.called);
-    assert.deepEqual(fileActionHandler.lastCall.args[0].detail,
-        {action: GrEditConstants.Actions.OPEN.id, path: 'foo'});
-  });
-
-  test('delete tap emits event', () => {
-    const actions = element.$.actions;
-    element.filePath = 'foo';
-    actions._open();
-    flushAsynchronousOperations();
-
-    MockInteractions.tap(actions.$$('li [data-id="delete"]'));
-    assert.isTrue(fileActionHandler.called);
-    assert.deepEqual(fileActionHandler.lastCall.args[0].detail,
-        {action: GrEditConstants.Actions.DELETE.id, path: 'foo'});
-  });
-
-  test('restore tap emits event', () => {
-    const actions = element.$.actions;
-    element.filePath = 'foo';
-    actions._open();
-    flushAsynchronousOperations();
-
-    MockInteractions.tap(actions.$$('li [data-id="restore"]'));
-    assert.isTrue(fileActionHandler.called);
-    assert.deepEqual(fileActionHandler.lastCall.args[0].detail,
-        {action: GrEditConstants.Actions.RESTORE.id, path: 'foo'});
-  });
-
-  test('rename tap emits event', () => {
-    const actions = element.$.actions;
-    element.filePath = 'foo';
-    actions._open();
-    flushAsynchronousOperations();
-
-    MockInteractions.tap(actions.$$('li [data-id="rename"]'));
-    assert.isTrue(fileActionHandler.called);
-    assert.deepEqual(fileActionHandler.lastCall.args[0].detail,
-        {action: GrEditConstants.Actions.RENAME.id, path: 'foo'});
-  });
-
-  test('computed properties', () => {
-    assert.equal(element._allFileActions.length, 4);
-  });
-});
 </script>
diff --git a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.html b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.html
index ebd624e..1d264bc 100644
--- a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.html
+++ b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.html
@@ -22,6 +22,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 
 <link rel="import" href="gr-editor-view.html">
@@ -35,378 +36,379 @@
 </test-fixture>
 
 <script>
-suite('gr-editor-view tests', () => {
-  let element;
-  let sandbox;
-  let savePathStub;
-  let saveFileStub;
-  let changeDetailStub;
-  let navigateStub;
-  const mockParams = {
-    changeNum: '42',
-    path: 'foo/bar.baz',
-    patchNum: 'edit',
-  };
-
-  setup(() => {
-    stub('gr-rest-api-interface', {
-      getLoggedIn() { return Promise.resolve(true); },
-      getEditPreferences() { return Promise.resolve({}); },
-    });
-    sandbox = sinon.sandbox.create();
-    element = fixture('basic');
-    savePathStub = sandbox.stub(element.$.restAPI, 'renameFileInChangeEdit');
-    saveFileStub = sandbox.stub(element.$.restAPI, 'saveChangeEdit');
-    changeDetailStub = sandbox.stub(element.$.restAPI, 'getDiffChangeDetail');
-    navigateStub = sandbox.stub(element, '_viewEditInChangeView');
-  });
-
-  teardown(() => { sandbox.restore(); });
-
-  suite('_paramsChanged', () => {
-    test('incorrect view returns immediately', () => {
-      element._paramsChanged(
-          Object.assign({}, mockParams, {view: Gerrit.Nav.View.DIFF}));
-      assert.notOk(element._changeNum);
-    });
-
-    test('good params proceed', () => {
-      changeDetailStub.returns(Promise.resolve({}));
-      const fileStub = sandbox.stub(element, '_getFileData', () => {
-        element._content = 'text';
-        element._newContent = 'text';
-        element._type = 'application/octet-stream';
+  suite('gr-editor-view tests', async () => {
+    await readyToTest();
+    let element;
+    let sandbox;
+    let savePathStub;
+    let saveFileStub;
+    let changeDetailStub;
+    let navigateStub;
+    const mockParams = {
+      changeNum: '42',
+      path: 'foo/bar.baz',
+      patchNum: 'edit',
+    };
+  
+    setup(() => {
+      stub('gr-rest-api-interface', {
+        getLoggedIn() { return Promise.resolve(true); },
+        getEditPreferences() { return Promise.resolve({}); },
       });
-
-      const promises = element._paramsChanged(
-          Object.assign({}, mockParams, {view: Gerrit.Nav.View.EDIT}));
-
-      flushAsynchronousOperations();
-      assert.equal(element._changeNum, mockParams.changeNum);
-      assert.equal(element._path, mockParams.path);
-      assert.deepEqual(changeDetailStub.lastCall.args[0],
-          mockParams.changeNum);
-      assert.deepEqual(fileStub.lastCall.args,
-          [mockParams.changeNum, mockParams.path, mockParams.patchNum]);
-
-      return promises.then(() => {
-        assert.equal(element._content, 'text');
-        assert.equal(element._newContent, 'text');
-        assert.equal(element._type, 'application/octet-stream');
-      });
+      sandbox = sinon.sandbox.create();
+      element = fixture('basic');
+      savePathStub = sandbox.stub(element.$.restAPI, 'renameFileInChangeEdit');
+      saveFileStub = sandbox.stub(element.$.restAPI, 'saveChangeEdit');
+      changeDetailStub = sandbox.stub(element.$.restAPI, 'getDiffChangeDetail');
+      navigateStub = sandbox.stub(element, '_viewEditInChangeView');
     });
-  });
-
-  test('edit file path', () => {
-    element._changeNum = mockParams.changeNum;
-    element._path = mockParams.path;
-    savePathStub.onFirstCall().returns(Promise.resolve({}));
-    savePathStub.onSecondCall().returns(Promise.resolve({ok: true}));
-
-    // Calling with the same path should not navigate.
-    return element._handlePathChanged({detail: mockParams.path}).then(() => {
-      assert.isFalse(savePathStub.called);
-      // !ok response
-      element._handlePathChanged({detail: 'newPath'}).then(() => {
-        assert.isTrue(savePathStub.called);
-        assert.isFalse(navigateStub.called);
-        // ok response
-        element._handlePathChanged({detail: 'newPath'}).then(() => {
-          assert.isTrue(navigateStub.called);
-          assert.isTrue(element._successfulSave);
+  
+    teardown(() => { sandbox.restore(); });
+  
+    suite('_paramsChanged', () => {
+      test('incorrect view returns immediately', () => {
+        element._paramsChanged(
+            Object.assign({}, mockParams, {view: Gerrit.Nav.View.DIFF}));
+        assert.notOk(element._changeNum);
+      });
+  
+      test('good params proceed', () => {
+        changeDetailStub.returns(Promise.resolve({}));
+        const fileStub = sandbox.stub(element, '_getFileData', () => {
+          element._content = 'text';
+          element._newContent = 'text';
+          element._type = 'application/octet-stream';
+        });
+  
+        const promises = element._paramsChanged(
+            Object.assign({}, mockParams, {view: Gerrit.Nav.View.EDIT}));
+  
+        flushAsynchronousOperations();
+        assert.equal(element._changeNum, mockParams.changeNum);
+        assert.equal(element._path, mockParams.path);
+        assert.deepEqual(changeDetailStub.lastCall.args[0],
+            mockParams.changeNum);
+        assert.deepEqual(fileStub.lastCall.args,
+            [mockParams.changeNum, mockParams.path, mockParams.patchNum]);
+  
+        return promises.then(() => {
+          assert.equal(element._content, 'text');
+          assert.equal(element._newContent, 'text');
+          assert.equal(element._type, 'application/octet-stream');
         });
       });
     });
-  });
-
-  test('reacts to content-change event', () => {
-    const storeStub = sandbox.spy(element.$.storage, 'setEditableContentItem');
-    element._newContent = 'test';
-    element.$.editorEndpoint.dispatchEvent(new CustomEvent('content-change', {
-      bubbles: true, composed: true,
-      detail: {value: 'new content value'},
-    }));
-    element.flushDebouncer('store');
-    flushAsynchronousOperations();
-
-    assert.equal(element._newContent, 'new content value');
-    assert.isTrue(storeStub.called);
-    assert.equal(storeStub.lastCall.args[1], 'new content value');
-  });
-
-  suite('edit file content', () => {
-    const originalText = 'file text';
-    const newText = 'file text changed';
-
-    setup(() => {
+  
+    test('edit file path', () => {
       element._changeNum = mockParams.changeNum;
       element._path = mockParams.path;
-      element._content = originalText;
-      element._newContent = originalText;
+      savePathStub.onFirstCall().returns(Promise.resolve({}));
+      savePathStub.onSecondCall().returns(Promise.resolve({ok: true}));
+  
+      // Calling with the same path should not navigate.
+      return element._handlePathChanged({detail: mockParams.path}).then(() => {
+        assert.isFalse(savePathStub.called);
+        // !ok response
+        element._handlePathChanged({detail: 'newPath'}).then(() => {
+          assert.isTrue(savePathStub.called);
+          assert.isFalse(navigateStub.called);
+          // ok response
+          element._handlePathChanged({detail: 'newPath'}).then(() => {
+            assert.isTrue(navigateStub.called);
+            assert.isTrue(element._successfulSave);
+          });
+        });
+      });
+    });
+  
+    test('reacts to content-change event', () => {
+      const storeStub = sandbox.spy(element.$.storage, 'setEditableContentItem');
+      element._newContent = 'test';
+      element.$.editorEndpoint.dispatchEvent(new CustomEvent('content-change', {
+        bubbles: true, composed: true,
+        detail: {value: 'new content value'},
+      }));
+      element.flushDebouncer('store');
       flushAsynchronousOperations();
+  
+      assert.equal(element._newContent, 'new content value');
+      assert.isTrue(storeStub.called);
+      assert.equal(storeStub.lastCall.args[1], 'new content value');
     });
-
-    test('initial load', () => {
-      assert.equal(element.$.file.fileContent, originalText);
-      assert.isTrue(element.$.save.hasAttribute('disabled'));
-    });
-
-    test('file modification and save, !ok response', () => {
-      const saveSpy = sandbox.spy(element, '_saveEdit');
-      const eraseStub = sandbox.stub(element.$.storage,
-          'eraseEditableContentItem');
-      const alertStub = sandbox.stub(element, '_showAlert');
-      saveFileStub.returns(Promise.resolve({ok: false}));
-      element._newContent = newText;
-      flushAsynchronousOperations();
-
-      assert.isFalse(element.$.save.hasAttribute('disabled'));
-      assert.isFalse(element._saving);
-
-      MockInteractions.tap(element.$.save);
-      assert.isTrue(saveSpy.called);
-      assert.equal(alertStub.lastCall.args[0], 'Saving changes...');
-      assert.isTrue(element._saving);
-      assert.isTrue(element.$.save.hasAttribute('disabled'));
-
-      return saveSpy.lastCall.returnValue.then(() => {
-        assert.isTrue(saveFileStub.called);
-        assert.isTrue(eraseStub.called);
-        assert.isFalse(element._saving);
-        assert.equal(alertStub.lastCall.args[0], 'Failed to save changes');
-        assert.deepEqual(saveFileStub.lastCall.args,
-            [mockParams.changeNum, mockParams.path, newText]);
-        assert.isFalse(navigateStub.called);
-        assert.isFalse(element.$.save.hasAttribute('disabled'));
-        assert.notEqual(element._content, element._newContent);
-      });
-    });
-
-    test('file modification and save', () => {
-      const saveSpy = sandbox.spy(element, '_saveEdit');
-      const alertStub = sandbox.stub(element, '_showAlert');
-      saveFileStub.returns(Promise.resolve({ok: true}));
-      element._newContent = newText;
-      flushAsynchronousOperations();
-
-      assert.isFalse(element._saving);
-      assert.isFalse(element.$.save.hasAttribute('disabled'));
-
-      MockInteractions.tap(element.$.save);
-      assert.isTrue(saveSpy.called);
-      assert.equal(alertStub.lastCall.args[0], 'Saving changes...');
-      assert.isTrue(element._saving);
-      assert.isTrue(element.$.save.hasAttribute('disabled'));
-
-      return saveSpy.lastCall.returnValue.then(() => {
-        assert.isTrue(saveFileStub.called);
-        assert.isFalse(element._saving);
-        assert.equal(alertStub.lastCall.args[0], 'All changes saved');
-        assert.isFalse(navigateStub.called);
-        assert.isTrue(element.$.save.hasAttribute('disabled'));
-        assert.equal(element._content, element._newContent);
-        assert.isTrue(element._successfulSave);
-      });
-    });
-
-    test('file modification and close', () => {
-      const closeSpy = sandbox.spy(element, '_handleCloseTap');
-      element._newContent = newText;
-      flushAsynchronousOperations();
-
-      assert.isFalse(element.$.save.hasAttribute('disabled'));
-
-      MockInteractions.tap(element.$.close);
-      assert.isTrue(closeSpy.called);
-      assert.isFalse(saveFileStub.called);
-      assert.isTrue(navigateStub.called);
-    });
-  });
-
-  suite('_getFileData', () => {
-    setup(() => {
-      element._newContent = 'initial';
-      element._content = 'initial';
-      element._type = 'initial';
-      sandbox.stub(element.$.storage, 'getEditableContentItem').returns(null);
-    });
-
-    test('res.ok', () => {
-      sandbox.stub(element.$.restAPI, 'getFileContent')
-          .returns(Promise.resolve({
-            ok: true,
-            type: 'text/javascript',
-            content: 'new content',
-          }));
-
-      // Ensure no data is set with a bad response.
-      return element._getFileData('1', 'test/path', 'edit').then(() => {
-        assert.equal(element._newContent, 'new content');
-        assert.equal(element._content, 'new content');
-        assert.equal(element._type, 'text/javascript');
-      });
-    });
-
-    test('!res.ok', () => {
-      sandbox.stub(element.$.restAPI, 'getFileContent')
-          .returns(Promise.resolve({}));
-
-      // Ensure no data is set with a bad response.
-      return element._getFileData('1', 'test/path', 'edit').then(() => {
-        assert.equal(element._newContent, '');
-        assert.equal(element._content, '');
-        assert.equal(element._type, '');
-      });
-    });
-
-    test('content is undefined', () => {
-      sandbox.stub(element.$.restAPI, 'getFileContent')
-          .returns(Promise.resolve({
-            ok: true,
-            type: 'text/javascript',
-          }));
-
-      return element._getFileData('1', 'test/path', 'edit').then(() => {
-        assert.equal(element._newContent, '');
-        assert.equal(element._content, '');
-        assert.equal(element._type, 'text/javascript');
-      });
-    });
-
-    test('content and type is undefined', () => {
-      sandbox.stub(element.$.restAPI, 'getFileContent')
-          .returns(Promise.resolve({
-            ok: true,
-          }));
-
-      return element._getFileData('1', 'test/path', 'edit').then(() => {
-        assert.equal(element._newContent, '');
-        assert.equal(element._content, '');
-        assert.equal(element._type, '');
-      });
-    });
-  });
-
-  test('_showAlert', done => {
-    element.addEventListener('show-alert', e => {
-      assert.deepEqual(e.detail, {message: 'test message'});
-      assert.isTrue(e.bubbles);
-      done();
-    });
-
-    element._showAlert('test message');
-  });
-
-  test('_viewEditInChangeView respects _patchNum', () => {
-    navigateStub.restore();
-    const navStub = sandbox.stub(Gerrit.Nav, 'navigateToChange');
-    element._patchNum = element.EDIT_NAME;
-    element._viewEditInChangeView();
-    assert.equal(navStub.lastCall.args[1], element.EDIT_NAME);
-    element._patchNum = '1';
-    element._viewEditInChangeView();
-    assert.equal(navStub.lastCall.args[1], '1');
-    element._successfulSave = true;
-    element._viewEditInChangeView();
-    assert.equal(navStub.lastCall.args[1], element.EDIT_NAME);
-  });
-
-  suite('keyboard shortcuts', () => {
-    // Used as the spy on the handler for each entry in keyBindings.
-    let handleSpy;
-
-    suite('_handleSaveShortcut', () => {
-      let saveStub;
+  
+    suite('edit file content', () => {
+      const originalText = 'file text';
+      const newText = 'file text changed';
+  
       setup(() => {
-        handleSpy = sandbox.spy(element, '_handleSaveShortcut');
-        saveStub = sandbox.stub(element, '_saveEdit');
+        element._changeNum = mockParams.changeNum;
+        element._path = mockParams.path;
+        element._content = originalText;
+        element._newContent = originalText;
+        flushAsynchronousOperations();
       });
-
-      test('save enabled', () => {
-        element._content = '';
-        element._newContent = '_test';
-        MockInteractions.pressAndReleaseKeyOn(element, 83, 'ctrl', 's');
-        flushAsynchronousOperations();
-
-        assert.isTrue(handleSpy.calledOnce);
-        assert.isTrue(saveStub.calledOnce);
-
-        MockInteractions.pressAndReleaseKeyOn(element, 83, 'meta', 's');
-        flushAsynchronousOperations();
-
-        assert.equal(handleSpy.callCount, 2);
-        assert.equal(saveStub.callCount, 2);
+  
+      test('initial load', () => {
+        assert.equal(element.$.file.fileContent, originalText);
+        assert.isTrue(element.$.save.hasAttribute('disabled'));
       });
-
-      test('save disabled', () => {
-        MockInteractions.pressAndReleaseKeyOn(element, 83, 'ctrl', 's');
+  
+      test('file modification and save, !ok response', () => {
+        const saveSpy = sandbox.spy(element, '_saveEdit');
+        const eraseStub = sandbox.stub(element.$.storage,
+            'eraseEditableContentItem');
+        const alertStub = sandbox.stub(element, '_showAlert');
+        saveFileStub.returns(Promise.resolve({ok: false}));
+        element._newContent = newText;
         flushAsynchronousOperations();
-
-        assert.isTrue(handleSpy.calledOnce);
-        assert.isFalse(saveStub.called);
-
-        MockInteractions.pressAndReleaseKeyOn(element, 83, 'meta', 's');
+  
+        assert.isFalse(element.$.save.hasAttribute('disabled'));
+        assert.isFalse(element._saving);
+  
+        MockInteractions.tap(element.$.save);
+        assert.isTrue(saveSpy.called);
+        assert.equal(alertStub.lastCall.args[0], 'Saving changes...');
+        assert.isTrue(element._saving);
+        assert.isTrue(element.$.save.hasAttribute('disabled'));
+  
+        return saveSpy.lastCall.returnValue.then(() => {
+          assert.isTrue(saveFileStub.called);
+          assert.isTrue(eraseStub.called);
+          assert.isFalse(element._saving);
+          assert.equal(alertStub.lastCall.args[0], 'Failed to save changes');
+          assert.deepEqual(saveFileStub.lastCall.args,
+              [mockParams.changeNum, mockParams.path, newText]);
+          assert.isFalse(navigateStub.called);
+          assert.isFalse(element.$.save.hasAttribute('disabled'));
+          assert.notEqual(element._content, element._newContent);
+        });
+      });
+  
+      test('file modification and save', () => {
+        const saveSpy = sandbox.spy(element, '_saveEdit');
+        const alertStub = sandbox.stub(element, '_showAlert');
+        saveFileStub.returns(Promise.resolve({ok: true}));
+        element._newContent = newText;
         flushAsynchronousOperations();
-
-        assert.equal(handleSpy.callCount, 2);
-        assert.isFalse(saveStub.called);
+  
+        assert.isFalse(element._saving);
+        assert.isFalse(element.$.save.hasAttribute('disabled'));
+  
+        MockInteractions.tap(element.$.save);
+        assert.isTrue(saveSpy.called);
+        assert.equal(alertStub.lastCall.args[0], 'Saving changes...');
+        assert.isTrue(element._saving);
+        assert.isTrue(element.$.save.hasAttribute('disabled'));
+  
+        return saveSpy.lastCall.returnValue.then(() => {
+          assert.isTrue(saveFileStub.called);
+          assert.isFalse(element._saving);
+          assert.equal(alertStub.lastCall.args[0], 'All changes saved');
+          assert.isFalse(navigateStub.called);
+          assert.isTrue(element.$.save.hasAttribute('disabled'));
+          assert.equal(element._content, element._newContent);
+          assert.isTrue(element._successfulSave);
+        });
+      });
+  
+      test('file modification and close', () => {
+        const closeSpy = sandbox.spy(element, '_handleCloseTap');
+        element._newContent = newText;
+        flushAsynchronousOperations();
+  
+        assert.isFalse(element.$.save.hasAttribute('disabled'));
+  
+        MockInteractions.tap(element.$.close);
+        assert.isTrue(closeSpy.called);
+        assert.isFalse(saveFileStub.called);
+        assert.isTrue(navigateStub.called);
+      });
+    });
+  
+    suite('_getFileData', () => {
+      setup(() => {
+        element._newContent = 'initial';
+        element._content = 'initial';
+        element._type = 'initial';
+        sandbox.stub(element.$.storage, 'getEditableContentItem').returns(null);
+      });
+  
+      test('res.ok', () => {
+        sandbox.stub(element.$.restAPI, 'getFileContent')
+            .returns(Promise.resolve({
+              ok: true,
+              type: 'text/javascript',
+              content: 'new content',
+            }));
+  
+        // Ensure no data is set with a bad response.
+        return element._getFileData('1', 'test/path', 'edit').then(() => {
+          assert.equal(element._newContent, 'new content');
+          assert.equal(element._content, 'new content');
+          assert.equal(element._type, 'text/javascript');
+        });
+      });
+  
+      test('!res.ok', () => {
+        sandbox.stub(element.$.restAPI, 'getFileContent')
+            .returns(Promise.resolve({}));
+  
+        // Ensure no data is set with a bad response.
+        return element._getFileData('1', 'test/path', 'edit').then(() => {
+          assert.equal(element._newContent, '');
+          assert.equal(element._content, '');
+          assert.equal(element._type, '');
+        });
+      });
+  
+      test('content is undefined', () => {
+        sandbox.stub(element.$.restAPI, 'getFileContent')
+            .returns(Promise.resolve({
+              ok: true,
+              type: 'text/javascript',
+            }));
+  
+        return element._getFileData('1', 'test/path', 'edit').then(() => {
+          assert.equal(element._newContent, '');
+          assert.equal(element._content, '');
+          assert.equal(element._type, 'text/javascript');
+        });
+      });
+  
+      test('content and type is undefined', () => {
+        sandbox.stub(element.$.restAPI, 'getFileContent')
+            .returns(Promise.resolve({
+              ok: true,
+            }));
+  
+        return element._getFileData('1', 'test/path', 'edit').then(() => {
+          assert.equal(element._newContent, '');
+          assert.equal(element._content, '');
+          assert.equal(element._type, '');
+        });
+      });
+    });
+  
+    test('_showAlert', done => {
+      element.addEventListener('show-alert', e => {
+        assert.deepEqual(e.detail, {message: 'test message'});
+        assert.isTrue(e.bubbles);
+        done();
+      });
+  
+      element._showAlert('test message');
+    });
+  
+    test('_viewEditInChangeView respects _patchNum', () => {
+      navigateStub.restore();
+      const navStub = sandbox.stub(Gerrit.Nav, 'navigateToChange');
+      element._patchNum = element.EDIT_NAME;
+      element._viewEditInChangeView();
+      assert.equal(navStub.lastCall.args[1], element.EDIT_NAME);
+      element._patchNum = '1';
+      element._viewEditInChangeView();
+      assert.equal(navStub.lastCall.args[1], '1');
+      element._successfulSave = true;
+      element._viewEditInChangeView();
+      assert.equal(navStub.lastCall.args[1], element.EDIT_NAME);
+    });
+  
+    suite('keyboard shortcuts', () => {
+      // Used as the spy on the handler for each entry in keyBindings.
+      let handleSpy;
+  
+      suite('_handleSaveShortcut', () => {
+        let saveStub;
+        setup(() => {
+          handleSpy = sandbox.spy(element, '_handleSaveShortcut');
+          saveStub = sandbox.stub(element, '_saveEdit');
+        });
+  
+        test('save enabled', () => {
+          element._content = '';
+          element._newContent = '_test';
+          MockInteractions.pressAndReleaseKeyOn(element, 83, 'ctrl', 's');
+          flushAsynchronousOperations();
+  
+          assert.isTrue(handleSpy.calledOnce);
+          assert.isTrue(saveStub.calledOnce);
+  
+          MockInteractions.pressAndReleaseKeyOn(element, 83, 'meta', 's');
+          flushAsynchronousOperations();
+  
+          assert.equal(handleSpy.callCount, 2);
+          assert.equal(saveStub.callCount, 2);
+        });
+  
+        test('save disabled', () => {
+          MockInteractions.pressAndReleaseKeyOn(element, 83, 'ctrl', 's');
+          flushAsynchronousOperations();
+  
+          assert.isTrue(handleSpy.calledOnce);
+          assert.isFalse(saveStub.called);
+  
+          MockInteractions.pressAndReleaseKeyOn(element, 83, 'meta', 's');
+          flushAsynchronousOperations();
+  
+          assert.equal(handleSpy.callCount, 2);
+          assert.isFalse(saveStub.called);
+        });
+      });
+    });
+  
+    suite('gr-storage caching', () => {
+      test('local edit exists', () => {
+        sandbox.stub(element.$.storage, 'getEditableContentItem')
+            .returns({message: 'pending edit'});
+        sandbox.stub(element.$.restAPI, 'getFileContent')
+            .returns(Promise.resolve({
+              ok: true,
+              type: 'text/javascript',
+              content: 'old content',
+            }));
+  
+        const alertStub = sandbox.stub();
+        element.addEventListener('show-alert', alertStub);
+  
+        return element._getFileData(1, 'test', 1).then(() => {
+          flushAsynchronousOperations();
+  
+          assert.isTrue(alertStub.called);
+          assert.equal(element._newContent, 'pending edit');
+          assert.equal(element._content, 'old content');
+          assert.equal(element._type, 'text/javascript');
+        });
+      });
+  
+      test('local edit exists, is same as remote edit', () => {
+        sandbox.stub(element.$.storage, 'getEditableContentItem')
+            .returns({message: 'pending edit'});
+        sandbox.stub(element.$.restAPI, 'getFileContent')
+            .returns(Promise.resolve({
+              ok: true,
+              type: 'text/javascript',
+              content: 'pending edit',
+            }));
+  
+        const alertStub = sandbox.stub();
+        element.addEventListener('show-alert', alertStub);
+  
+        return element._getFileData(1, 'test', 1).then(() => {
+          flushAsynchronousOperations();
+  
+          assert.isFalse(alertStub.called);
+          assert.equal(element._newContent, 'pending edit');
+          assert.equal(element._content, 'pending edit');
+          assert.equal(element._type, 'text/javascript');
+        });
+      });
+  
+      test('storage key computation', () => {
+        element._changeNum = 1;
+        element._patchNum = 1;
+        element._path = 'test';
+        assert.equal(element.storageKey, 'c1_ps1_test');
       });
     });
   });
-
-  suite('gr-storage caching', () => {
-    test('local edit exists', () => {
-      sandbox.stub(element.$.storage, 'getEditableContentItem')
-          .returns({message: 'pending edit'});
-      sandbox.stub(element.$.restAPI, 'getFileContent')
-          .returns(Promise.resolve({
-            ok: true,
-            type: 'text/javascript',
-            content: 'old content',
-          }));
-
-      const alertStub = sandbox.stub();
-      element.addEventListener('show-alert', alertStub);
-
-      return element._getFileData(1, 'test', 1).then(() => {
-        flushAsynchronousOperations();
-
-        assert.isTrue(alertStub.called);
-        assert.equal(element._newContent, 'pending edit');
-        assert.equal(element._content, 'old content');
-        assert.equal(element._type, 'text/javascript');
-      });
-    });
-
-    test('local edit exists, is same as remote edit', () => {
-      sandbox.stub(element.$.storage, 'getEditableContentItem')
-          .returns({message: 'pending edit'});
-      sandbox.stub(element.$.restAPI, 'getFileContent')
-          .returns(Promise.resolve({
-            ok: true,
-            type: 'text/javascript',
-            content: 'pending edit',
-          }));
-
-      const alertStub = sandbox.stub();
-      element.addEventListener('show-alert', alertStub);
-
-      return element._getFileData(1, 'test', 1).then(() => {
-        flushAsynchronousOperations();
-
-        assert.isFalse(alertStub.called);
-        assert.equal(element._newContent, 'pending edit');
-        assert.equal(element._content, 'pending edit');
-        assert.equal(element._type, 'text/javascript');
-      });
-    });
-
-    test('storage key computation', () => {
-      element._changeNum = 1;
-      element._patchNum = 1;
-      element._path = 'test';
-      assert.equal(element.storageKey, 'c1_ps1_test');
-    });
-  });
-});
 </script>
diff --git a/polygerrit-ui/app/elements/font-roboto-local-loader.js b/polygerrit-ui/app/elements/font-roboto-local-loader.js
new file mode 100644
index 0000000..7000d13
--- /dev/null
+++ b/polygerrit-ui/app/elements/font-roboto-local-loader.js
@@ -0,0 +1,20 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Place all code related to font-roboto-local here
+import '@polymer/font-roboto-local/roboto.js';
+
diff --git a/polygerrit-ui/app/elements/gr-app-element.js b/polygerrit-ui/app/elements/gr-app-element.js
index 7e62b9d..306fbb9 100644
--- a/polygerrit-ui/app/elements/gr-app-element.js
+++ b/polygerrit-ui/app/elements/gr-app-element.js
@@ -309,6 +309,8 @@
           this.Shortcut.TOGGLE_ALL_INLINE_DIFFS, 'shift+i:keyup');
       this.bindShortcut(
           this.Shortcut.TOGGLE_INLINE_DIFF, 'i:keyup');
+      this.bindShortcut(
+          this.Shortcut.TOGGLE_BLAME, 'b');
 
       this.bindShortcut(
           this.Shortcut.OPEN_FIRST_FILE, ']');
diff --git a/polygerrit-ui/app/elements/gr-app.html b/polygerrit-ui/app/elements/gr-app.html
index f49d8aa..ce6a693 100644
--- a/polygerrit-ui/app/elements/gr-app.html
+++ b/polygerrit-ui/app/elements/gr-app.html
@@ -23,6 +23,7 @@
   }
   window.Gerrit = window.Gerrit || {};
 </script>
+<script src="./font-roboto-local-loader.js" type="module" />
 
 <link rel="import" href="/bower_components/polymer/polymer.html">
 <link rel="import" href="/bower_components/polymer-resin/standalone/polymer-resin.html">
diff --git a/polygerrit-ui/app/elements/gr-app_test.html b/polygerrit-ui/app/elements/gr-app_test.html
index 1014284..cc25e5a 100644
--- a/polygerrit-ui/app/elements/gr-app_test.html
+++ b/polygerrit-ui/app/elements/gr-app_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../test/test-pre-setup.js"></script>
 <link rel="import" href="../test/common-test-setup.html"/>
 
 <script>
@@ -41,7 +42,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-app tests', () => {
+  suite('gr-app tests', async () => {
+    await readyToTest();
     let sandbox;
     let element;
 
diff --git a/polygerrit-ui/app/elements/plugins/gr-admin-api/gr-admin-api_test.html b/polygerrit-ui/app/elements/plugins/gr-admin-api/gr-admin-api_test.html
index 10ba710..f10f922 100644
--- a/polygerrit-ui/app/elements/plugins/gr-admin-api/gr-admin-api_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-admin-api/gr-admin-api_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="../../shared/gr-js-api-interface/gr-js-api-interface.html">
 <link rel="import" href="gr-admin-api.html">
@@ -30,7 +31,8 @@
 <script>void(0);</script>
 
 <script>
-  suite('gr-admin-api tests', () => {
+  suite('gr-admin-api tests', async () => {
+    await readyToTest();
     let sandbox;
     let adminApi;
 
diff --git a/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper_test.html b/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper_test.html
index c95128b..87d3142 100644
--- a/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-attribute-helper.html"/>
 
@@ -30,16 +31,19 @@
 
 <dom-element id="some-element">
   <script>
-    Polymer({
-      is: 'some-element',
-      properties: {
-        fooBar: {
-          type: Object,
-          notify: true,
+    readyToTest().then(() => {
+      Polymer({
+        is: 'some-element',
+        properties: {
+          fooBar: {
+            type: Object,
+            notify: true,
+          },
         },
-      },
+      });
     });
   </script>
+
 </dom-element>
 
 <test-fixture id="basic">
@@ -49,7 +53,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-attribute-helper tests', () => {
+  suite('gr-attribute-helper tests', async () => {
+    await readyToTest();
     let element;
     let instance;
     let sandbox;
diff --git a/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks_test.html b/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks_test.html
index a00dc68..2477c6b 100644
--- a/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-dom-hooks.html"/>
 <link rel="import" href="../../shared/gr-js-api-interface/gr-js-api-interface.html">
@@ -36,7 +37,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-dom-hooks tests', () => {
+  suite('gr-dom-hooks tests', async () => {
+    await readyToTest();
     const PUBLIC_METHODS =
         ['onAttached', 'getLastAttached', 'getAllAttached', 'getModuleName'];
 
diff --git a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator_test.html b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator_test.html
index ae1c922..e0d91fa 100644
--- a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-endpoint-decorator.html">
 <link rel="import" href="../gr-endpoint-param/gr-endpoint-param.html">
@@ -46,7 +47,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-endpoint-decorator', () => {
+  suite('gr-endpoint-decorator', async () => {
+    await readyToTest();
     let container;
     let sandbox;
     let plugin;
diff --git a/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper_test.html b/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper_test.html
index a98a0d2..a6eaebf 100644
--- a/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-event-helper.html"/>
 
@@ -30,21 +31,24 @@
 
 <dom-element id="some-element">
   <script>
-    Polymer({
-      is: 'some-element',
+    readyToTest().then(() => {
+      Polymer({
+        is: 'some-element',
 
-      properties: {
-        fooBar: {
-          type: Object,
-          notify: true,
+        properties: {
+          fooBar: {
+            type: Object,
+            notify: true,
+          },
         },
-      },
 
-      behaviors: [
-        Gerrit.FireBehavior,
-      ],
+        behaviors: [
+          Gerrit.FireBehavior,
+        ],
+      });
     });
   </script>
+
 </dom-element>
 
 <test-fixture id="basic">
@@ -54,7 +58,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-event-helper tests', () => {
+  suite('gr-event-helper tests', async () => {
+    await readyToTest();
     let element;
     let instance;
     let sandbox;
diff --git a/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style_test.html b/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style_test.html
index 9f0c950..c3592f5 100644
--- a/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-external-style.html">
 
@@ -33,7 +34,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-external-style integration tests', () => {
+  suite('gr-external-style integration tests', async () => {
+    await readyToTest();
     const TEST_URL = 'http://some/plugin/url.html';
 
     let sandbox;
@@ -72,9 +74,7 @@
 
     setup(() => {
       sandbox = sinon.sandbox.create();
-      stub('gr-external-style', {
-        importHref: (url, resolve) => resolve(),
-      });
+      sandbox.stub(Polymer, 'importHref', (url, resolve) => resolve());
       sandbox.stub(Gerrit, 'awaitPluginsLoaded').returns(Promise.resolve());
     });
 
@@ -85,7 +85,7 @@
     test('imports plugin-provided module', async () => {
       lateRegister();
       await new Promise(flush);
-      assert.isTrue(element.importHref.calledWith(new URL(TEST_URL)));
+      assert.isTrue(Polymer.importHref.calledWith(new URL(TEST_URL)));
     });
 
     test('applies plugin-provided styles', async () => {
@@ -117,7 +117,7 @@
     test('loads and applies preloaded modules', async () => {
       earlyRegister();
       await new Promise(flush);
-      assert.isTrue(element.importHref.calledWith(new URL(TEST_URL)));
+      assert.isTrue(Polymer.importHref.calledWith(new URL(TEST_URL)));
       assert.isTrue(element._applyStyle.calledWith('some-module'));
     });
   });
diff --git a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host_test.html b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host_test.html
index 91f151f..9a5eb15 100644
--- a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-plugin-host.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-plugin-host tests', () => {
+  suite('gr-plugin-host tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
@@ -43,7 +45,7 @@
       element = fixture('basic');
       sandbox = sinon.sandbox.create();
       sandbox.stub(document.body, 'appendChild');
-      sandbox.stub(element, 'importHref');
+      sandbox.stub(Polymer, 'importHref');
     });
 
     teardown(() => {
diff --git a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup_test.html b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup_test.html
index e6f446b..1617cd5 100644
--- a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-plugin-popup.html"/>
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-plugin-popup tests', () => {
+  suite('gr-plugin-popup tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface_test.html b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface_test.html
index 20245e0..ffa3f2d 100644
--- a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-popup-interface.html"/>
 <link rel="import" href="../../shared/gr-js-api-interface/gr-js-api-interface.html">
@@ -39,11 +40,16 @@
   <template>
     <div id="barfoo">some test module</div>
   </template>
-  <script>Polymer({is: 'gr-user-test-popup'});</script>
+  <script>
+    readyToTest().then(() => {
+      Polymer({is: 'gr-user-test-popup'});
+    });
+  </script>
 </dom-module>
 
 <script>
-  suite('gr-popup-interface tests', () => {
+  suite('gr-popup-interface tests', async () => {
+    await readyToTest();
     let container;
     let instance;
     let plugin;
diff --git a/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api_test.html b/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api_test.html
index 5a47a85..915bd02 100644
--- a/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="../gr-endpoint-decorator/gr-endpoint-decorator.html">
 <link rel="import" href="gr-repo-api.html">
@@ -37,7 +38,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-repo-api tests', () => {
+  suite('gr-repo-api tests', async () => {
+    await readyToTest();
     let sandbox;
     let repoApi;
 
diff --git a/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api_test.html b/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api_test.html
index 6248d78..01278f1 100644
--- a/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="../gr-endpoint-decorator/gr-endpoint-decorator.html">
 <link rel="import" href="gr-settings-api.html">
@@ -39,7 +40,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-settings-api tests', () => {
+  suite('gr-settings-api tests', async () => {
+    await readyToTest();
     let sandbox;
     let settingsApi;
 
diff --git a/polygerrit-ui/app/elements/plugins/gr-styles-api/gr-styles-api_test.html b/polygerrit-ui/app/elements/plugins/gr-styles-api/gr-styles-api_test.html
index 7d14e21..e4a92f6 100644
--- a/polygerrit-ui/app/elements/plugins/gr-styles-api/gr-styles-api_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-styles-api/gr-styles-api_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="../../shared/gr-js-api-interface/gr-js-api-interface.html">
 <link rel="import" href="gr-styles-api.html">
@@ -33,11 +34,16 @@
   <template>
     <div id="wrapper"></div>
   </template>
-  <script>Polymer({is: 'gr-style-test-element'});</script>
+  <script>
+    readyToTest().then(() => {
+      Polymer({is: 'gr-style-test-element'});
+    });
+  </script>
 </dom-module>
 
 <script>
-  suite('gr-styles-api tests', () => {
+  suite('gr-styles-api tests', async () => {
+    await readyToTest();
     let sandbox;
     let stylesApi;
 
@@ -63,118 +69,118 @@
       const styleObject = stylesApi.css('background: red');
       assert.isDefined(styleObject);
     });
-  });
 
-  suite('GrStyleObject tests', () => {
-    let sandbox;
-    let stylesApi;
-    let displayInlineStyle;
-    let displayNoneStyle;
+    suite('GrStyleObject tests', () => {
+      let sandbox;
+      let stylesApi;
+      let displayInlineStyle;
+      let displayNoneStyle;
 
-    setup(() => {
-      sandbox = sinon.sandbox.create();
-      let plugin;
-      Gerrit.install(p => { plugin = p; }, '0.1',
-          'http://test.com/plugins/testplugin/static/test.js');
-      Gerrit._loadPlugins([]);
-      stylesApi = plugin.styles();
-      displayInlineStyle = stylesApi.css('display: inline');
-      displayNoneStyle = stylesApi.css('display: none');
-    });
+      setup(() => {
+        sandbox = sinon.sandbox.create();
+        let plugin;
+        Gerrit.install(p => { plugin = p; }, '0.1',
+            'http://test.com/plugins/testplugin/static/test.js');
+        Gerrit._loadPlugins([]);
+        stylesApi = plugin.styles();
+        displayInlineStyle = stylesApi.css('display: inline');
+        displayNoneStyle = stylesApi.css('display: none');
+      });
 
-    teardown(() => {
-      displayInlineStyle = null;
-      displayNoneStyle = null;
-      stylesApi = null;
-      sandbox.restore();
-    });
+      teardown(() => {
+        displayInlineStyle = null;
+        displayNoneStyle = null;
+        stylesApi = null;
+        sandbox.restore();
+      });
 
-    function createNestedElements(parentElement) {
-      /* parentElement
-      *  |--- element1
-      *  |--- element2
-      *       |--- element3
-      **/
-      const element1 = document.createElement('div');
-      const element2 = document.createElement('div');
-      const element3 = document.createElement('div');
-      Polymer.dom(parentElement).appendChild(element1);
-      Polymer.dom(parentElement).appendChild(element2);
-      Polymer.dom(element2).appendChild(element3);
+      function createNestedElements(parentElement) {
+        /* parentElement
+        *  |--- element1
+        *  |--- element2
+        *       |--- element3
+        **/
+        const element1 = document.createElement('div');
+        const element2 = document.createElement('div');
+        const element3 = document.createElement('div');
+        Polymer.dom(parentElement).appendChild(element1);
+        Polymer.dom(parentElement).appendChild(element2);
+        Polymer.dom(element2).appendChild(element3);
 
-      return [element1, element2, element3];
-    }
-
-    test('getClassName  - body level elements', () => {
-      const bodyLevelElements = createNestedElements(document.body);
-
-      testGetClassName(bodyLevelElements);
-    });
-
-    test('getClassName  - elements inside polymer element', () => {
-      const polymerElement = document.createElement('gr-style-test-element');
-      Polymer.dom(document.body).appendChild(polymerElement);
-      const contentElements = createNestedElements(polymerElement.$.wrapper);
-
-      testGetClassName(contentElements);
-    });
-
-    function testGetClassName(elements) {
-      assertAllElementsHaveDefaultStyle(elements);
-
-      const className1 = displayInlineStyle.getClassName(elements[0]);
-      const className2 = displayNoneStyle.getClassName(elements[1]);
-      const className3 = displayInlineStyle.getClassName(elements[2]);
-
-      assert.notEqual(className2, className1);
-      assert.equal(className3, className1);
-
-      assertAllElementsHaveDefaultStyle(elements);
-
-      elements[0].classList.add(className1);
-      elements[1].classList.add(className2);
-      elements[2].classList.add(className1);
-
-      assertDisplayPropertyValues(elements, ['inline', 'none', 'inline']);
-    }
-
-    test('apply - body level elements', () => {
-      const bodyLevelElements = createNestedElements(document.body);
-
-      testApply(bodyLevelElements);
-    });
-
-    test('apply - elements inside polymer element', () => {
-      const polymerElement = document.createElement('gr-style-test-element');
-      Polymer.dom(document.body).appendChild(polymerElement);
-      const contentElements = createNestedElements(polymerElement.$.wrapper);
-
-      testApply(contentElements);
-    });
-
-    function testApply(elements) {
-      assertAllElementsHaveDefaultStyle(elements);
-      displayInlineStyle.apply(elements[0]);
-      displayNoneStyle.apply(elements[1]);
-      displayInlineStyle.apply(elements[2]);
-      assertDisplayPropertyValues(elements, ['inline', 'none', 'inline']);
-    }
-
-    function assertAllElementsHaveDefaultStyle(elements) {
-      for (const element of elements) {
-        assert.equal(getComputedStyle(element).getPropertyValue('display'),
-            'block');
+        return [element1, element2, element3];
       }
-    }
 
-    function assertDisplayPropertyValues(elements, expectedDisplayValues) {
-      for (const key in elements) {
-        if (elements.hasOwnProperty(key)) {
-          assert.equal(
-              getComputedStyle(elements[key]).getPropertyValue('display'),
-              expectedDisplayValues[key]);
+      test('getClassName  - body level elements', () => {
+        const bodyLevelElements = createNestedElements(document.body);
+
+        testGetClassName(bodyLevelElements);
+      });
+
+      test('getClassName  - elements inside polymer element', () => {
+        const polymerElement = document.createElement('gr-style-test-element');
+        Polymer.dom(document.body).appendChild(polymerElement);
+        const contentElements = createNestedElements(polymerElement.$.wrapper);
+
+        testGetClassName(contentElements);
+      });
+
+      function testGetClassName(elements) {
+        assertAllElementsHaveDefaultStyle(elements);
+
+        const className1 = displayInlineStyle.getClassName(elements[0]);
+        const className2 = displayNoneStyle.getClassName(elements[1]);
+        const className3 = displayInlineStyle.getClassName(elements[2]);
+
+        assert.notEqual(className2, className1);
+        assert.equal(className3, className1);
+
+        assertAllElementsHaveDefaultStyle(elements);
+
+        elements[0].classList.add(className1);
+        elements[1].classList.add(className2);
+        elements[2].classList.add(className1);
+
+        assertDisplayPropertyValues(elements, ['inline', 'none', 'inline']);
+      }
+
+      test('apply - body level elements', () => {
+        const bodyLevelElements = createNestedElements(document.body);
+
+        testApply(bodyLevelElements);
+      });
+
+      test('apply - elements inside polymer element', () => {
+        const polymerElement = document.createElement('gr-style-test-element');
+        Polymer.dom(document.body).appendChild(polymerElement);
+        const contentElements = createNestedElements(polymerElement.$.wrapper);
+
+        testApply(contentElements);
+      });
+
+      function testApply(elements) {
+        assertAllElementsHaveDefaultStyle(elements);
+        displayInlineStyle.apply(elements[0]);
+        displayNoneStyle.apply(elements[1]);
+        displayInlineStyle.apply(elements[2]);
+        assertDisplayPropertyValues(elements, ['inline', 'none', 'inline']);
+      }
+
+      function assertAllElementsHaveDefaultStyle(elements) {
+        for (const element of elements) {
+          assert.equal(getComputedStyle(element).getPropertyValue('display'),
+              'block');
         }
       }
-    }
+
+      function assertDisplayPropertyValues(elements, expectedDisplayValues) {
+        for (const key in elements) {
+          if (elements.hasOwnProperty(key)) {
+            assert.equal(
+                getComputedStyle(elements[key]).getPropertyValue('display'),
+                expectedDisplayValues[key]);
+          }
+        }
+      }
+    });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api_test.html b/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api_test.html
index 588facb..80853f5 100644
--- a/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="../gr-endpoint-decorator/gr-endpoint-decorator.html">
 <link rel="import" href="gr-theme-api.html">
@@ -38,7 +39,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-theme-api tests', () => {
+  suite('gr-theme-api tests', async () => {
+    await readyToTest();
     let sandbox;
     let theme;
 
diff --git a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_test.html b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_test.html
index a9056b91..80c7399 100644
--- a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-account-info.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-account-info tests', () => {
+  suite('gr-account-info tests', async () => {
+    await readyToTest();
     let element;
     let account;
     let config;
diff --git a/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list_test.html b/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list_test.html
index cd5bc09..39b8663 100644
--- a/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-agreements-list.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-agreements-list tests', () => {
+  suite('gr-agreements-list tests', async () => {
+    await readyToTest();
     let element;
     let agreements;
 
diff --git a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_test.html b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_test.html
index ec37c03..7800d5a 100644
--- a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-change-table-editor.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-change-table-editor tests', () => {
+  suite('gr-change-table-editor tests', async () => {
+    await readyToTest();
     let element;
     let columns;
     let sandbox;
diff --git a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_test.html b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_test.html
index 13c4de4..d40d36d 100644
--- a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-cla-view.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-cla-view tests', () => {
+  suite('gr-cla-view tests', async () => {
+    await readyToTest();
     let element;
     const signedAgreements = [{
       name: 'CLA',
diff --git a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_test.html b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_test.html
index 8b0bf86..3c99977 100644
--- a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-edit-preferences.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-edit-preferences tests', () => {
+  suite('gr-edit-preferences tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
     let editPreferences;
diff --git a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_test.html b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_test.html
index e55ac97..5d4a69e 100644
--- a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-email-editor.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-email-editor tests', () => {
+  suite('gr-email-editor tests', async () => {
+    await readyToTest();
     let element;
 
     setup(done => {
diff --git a/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor_test.html b/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor_test.html
index c1c0d50..08c36fe 100644
--- a/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-gpg-editor.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-gpg-editor tests', () => {
+  suite('gr-gpg-editor tests', async () => {
+    await readyToTest();
     let element;
     let keys;
 
diff --git a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_test.html b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_test.html
index d8bf888..10b67ec 100644
--- a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-group-list.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-group-list tests', () => {
+  suite('gr-group-list tests', async () => {
+    await readyToTest();
     let sandbox;
     let element;
     let groups;
diff --git a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_test.html b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_test.html
index d66b231..974a0f2 100644
--- a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-http-password.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-http-password tests', () => {
+  suite('gr-http-password tests', async () => {
+    await readyToTest();
     let element;
     let account;
     let config;
diff --git a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_test.html b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_test.html
index e2f8cad..be73a0c 100644
--- a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-identities.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-identities tests', () => {
+  suite('gr-identities tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
     const ids = [
diff --git a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor_test.html b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor_test.html
index a82b703..4fae65a 100644
--- a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-menu-editor.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-menu-editor tests', () => {
+  suite('gr-menu-editor tests', async () => {
+    await readyToTest();
     let element;
     let menu;
 
diff --git a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_test.html b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_test.html
index 7f493c3..a3be75c 100644
--- a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-registration-dialog.html">
 
@@ -41,7 +42,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-registration-dialog tests', () => {
+  suite('gr-registration-dialog tests', async () => {
+    await readyToTest();
     let element;
     let account;
     let sandbox;
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.html b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.html
index 759e65b..cd268c6 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-settings-view.html">
 
@@ -41,7 +42,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-settings-view tests', () => {
+  suite('gr-settings-view tests', async () => {
+    await readyToTest();
     let element;
     let account;
     let preferences;
diff --git a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor_test.html b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor_test.html
index d7644f7..82d427d 100644
--- a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-ssh-editor.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-ssh-editor tests', () => {
+  suite('gr-ssh-editor tests', async () => {
+    await readyToTest();
     let element;
     let keys;
 
diff --git a/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor_test.html b/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor_test.html
index e28e858..5f31f4a 100644
--- a/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-watched-projects-editor.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-watched-projects-editor tests', () => {
+  suite('gr-watched-projects-editor tests', async () => {
+    await readyToTest();
     let element;
 
     setup(done => {
diff --git a/polygerrit-ui/app/elements/shared/gr-account-entry/gr-account-entry_test.html b/polygerrit-ui/app/elements/shared/gr-account-entry/gr-account-entry_test.html
index 3743820..d70457c 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-entry/gr-account-entry_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-account-entry/gr-account-entry_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="../../../scripts/util.js"></script>
 
@@ -37,7 +38,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-account-entry tests', () => {
+  suite('gr-account-entry tests', async () => {
+    await readyToTest();
     let sandbox;
 
     const suggestion1 = {
diff --git a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.html b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.html
index f369ae2..c933edc 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="../../../scripts/util.js"></script>
 
@@ -37,7 +38,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-account-label tests', () => {
+  suite('gr-account-label tests', async () => {
+    await readyToTest();
     let element;
 
     setup(() => {
diff --git a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link_test.html b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link_test.html
index e41304f..c648661 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-account-link.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-account-link tests', () => {
+  suite('gr-account-link tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list_test.html b/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list_test.html
index 3eab3c7..39d0a88 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-account-list.html">
 
@@ -45,7 +46,8 @@
     }
   }
 
-  suite('gr-account-list tests', () => {
+  suite('gr-account-list tests', async () => {
+    await readyToTest();
     let _nextAccountId = 0;
     const makeAccount = function() {
       const accountId = ++_nextAccountId;
diff --git a/polygerrit-ui/app/elements/shared/gr-alert/gr-alert_test.html b/polygerrit-ui/app/elements/shared/gr-alert/gr-alert_test.html
index bfcc431..381fa6b 100644
--- a/polygerrit-ui/app/elements/shared/gr-alert/gr-alert_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-alert/gr-alert_test.html
@@ -23,11 +23,13 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-alert.html">
 
 <script>
-  suite('gr-alert tests', () => {
+  suite('gr-alert tests', async () => {
+    await readyToTest();
     let element;
 
     setup(() => {
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.html b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.html
index c12aa72..649cd22 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.html
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.html
@@ -22,7 +22,6 @@
 <link rel="import" href="/bower_components/iron-dropdown/iron-dropdown.html">
 <link rel="import" href="/bower_components/iron-fit-behavior/iron-fit-behavior.html">
 <link rel="import" href="../../shared/gr-cursor-manager/gr-cursor-manager.html">
-<script src="../../../types/polymer-behaviors.js"></script>
 <script src="../../../scripts/rootElement.js"></script>
 <link rel="import" href="../../../styles/shared-styles.html">
 
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown_test.html b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown_test.html
index 5f2ce94..44f3713 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-autocomplete-dropdown.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-autocomplete-dropdown', () => {
+  suite('gr-autocomplete-dropdown', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html
index 12bc82f..9dbeb5a 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-autocomplete.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-autocomplete tests', () => {
+  suite('gr-autocomplete tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
     const focusOnInput = element => {
diff --git a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.html b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.html
index 4d49206..bd3f805 100644
--- a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-avatar.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-avatar tests', () => {
+  suite('gr-avatar tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
@@ -130,69 +132,28 @@
             element.style.backgroundImage.includes('/accounts/123/avatar?s=64'));
       });
     });
-  });
 
-  suite('plugin has avatars', () => {
-    let element;
-    let sandbox;
+    suite('plugin has avatars', () => {
+      let element;
+      let sandbox;
 
-    setup(() => {
-      sandbox = sinon.sandbox.create();
+      setup(() => {
+        sandbox = sinon.sandbox.create();
 
-      stub('gr-avatar', {
-        _getConfig: () => Promise.resolve({plugin: {has_avatars: true}}),
+        stub('gr-avatar', {
+          _getConfig: () => Promise.resolve({plugin: {has_avatars: true}}),
+        });
+
+        element = fixture('basic');
       });
 
-      element = fixture('basic');
-    });
-
-    teardown(() => {
-      sandbox.restore();
-    });
-
-    test('dom for non available account', () => {
-      assert.isFalse(element.hasAttribute('hidden'));
-
-      // Emulate plugins loaded.
-      Gerrit._loadPlugins([]);
-
-      return Promise.all([
-        element.$.restAPI.getConfig(),
-        Gerrit.awaitPluginsLoaded(),
-      ]).then(() => {
-        assert.isTrue(element.hasAttribute('hidden'));
-
-        assert.strictEqual(element.style.backgroundImage, '');
-      });
-    });
-  });
-
-  suite('config not set', () => {
-    let element;
-    let sandbox;
-
-    setup(() => {
-      sandbox = sinon.sandbox.create();
-
-      stub('gr-avatar', {
-        _getConfig: () => Promise.resolve({}),
+      teardown(() => {
+        sandbox.restore();
       });
 
-      element = fixture('basic');
-    });
-
-    teardown(() => {
-      sandbox.restore();
-    });
-
-    test('avatar hidden when account set', () => {
-      flush(() => {
+      test('dom for non available account', () => {
         assert.isFalse(element.hasAttribute('hidden'));
 
-        element.imageSize = 64;
-        element.account = {
-          _account_id: 123,
-        };
         // Emulate plugins loaded.
         Gerrit._loadPlugins([]);
 
@@ -201,6 +162,47 @@
           Gerrit.awaitPluginsLoaded(),
         ]).then(() => {
           assert.isTrue(element.hasAttribute('hidden'));
+
+          assert.strictEqual(element.style.backgroundImage, '');
+        });
+      });
+    });
+
+    suite('config not set', () => {
+      let element;
+      let sandbox;
+
+      setup(() => {
+        sandbox = sinon.sandbox.create();
+
+        stub('gr-avatar', {
+          _getConfig: () => Promise.resolve({}),
+        });
+
+        element = fixture('basic');
+      });
+
+      teardown(() => {
+        sandbox.restore();
+      });
+
+      test('avatar hidden when account set', () => {
+        flush(() => {
+          assert.isFalse(element.hasAttribute('hidden'));
+
+          element.imageSize = 64;
+          element.account = {
+            _account_id: 123,
+          };
+          // Emulate plugins loaded.
+          Gerrit._loadPlugins([]);
+
+          return Promise.all([
+            element.$.restAPI.getConfig(),
+            Gerrit.awaitPluginsLoaded(),
+          ]).then(() => {
+            assert.isTrue(element.hasAttribute('hidden'));
+          });
         });
       });
     });
diff --git a/polygerrit-ui/app/elements/shared/gr-button/gr-button_test.html b/polygerrit-ui/app/elements/shared/gr-button/gr-button_test.html
index bcb560a..6f8cdf6 100644
--- a/polygerrit-ui/app/elements/shared/gr-button/gr-button_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-button/gr-button_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-button.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-select tests', () => {
+  suite('gr-select tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star_test.html b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star_test.html
index 60c504a..f245dbc 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-change-star.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-change-star tests', () => {
+  suite('gr-change-star tests', async () => {
+    await readyToTest();
     let element;
 
     setup(() => {
diff --git a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_test.html b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_test.html
index 96a1840..65dadf8 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-change-status.html">
 
@@ -46,7 +47,8 @@
   const PRIVATE_TOOLTIP = 'This change is only visible to its owner and ' +
       'current reviewers (or anyone with "View Private Changes" permission).';
 
-  suite('gr-change-status tests', () => {
+  suite('gr-change-status tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.html b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.html
index c8627ba..e6f4835 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="../../../scripts/util.js"></script>
 
@@ -43,185 +44,189 @@
 </test-fixture>
 
 <script>
-  suite('gr-comment-thread tests', () => {
-    let element;
-    let sandbox;
+  suite('gr-comment-thread tests', async () => {
+    await readyToTest();
 
-    setup(() => {
-      sandbox = sinon.sandbox.create();
-      stub('gr-rest-api-interface', {
-        getLoggedIn() { return Promise.resolve(false); },
+    suite('basic test', () => {
+      let element;
+      let sandbox;
+
+      setup(() => {
+        sandbox = sinon.sandbox.create();
+        stub('gr-rest-api-interface', {
+          getLoggedIn() { return Promise.resolve(false); },
+        });
+        sandbox = sinon.sandbox.create();
+        element = fixture('basic');
       });
-      sandbox = sinon.sandbox.create();
-      element = fixture('basic');
-    });
 
-    teardown(() => {
-      sandbox.restore();
-    });
+      teardown(() => {
+        sandbox.restore();
+      });
 
-    test('comments are sorted correctly', () => {
-      const comments = [
-        {
+      test('comments are sorted correctly', () => {
+        const comments = [
+          {
+            message: 'i like you, too',
+            in_reply_to: 'sallys_confession',
+            __date: new Date('2015-12-25'),
+          }, {
+            id: 'sallys_confession',
+            message: 'i like you, jack',
+            updated: '2015-12-24 15:00:20.396000000',
+          }, {
+            id: 'sally_to_dr_finklestein',
+            message: 'i’m running away',
+            updated: '2015-10-31 09:00:20.396000000',
+          }, {
+            id: 'sallys_defiance',
+            in_reply_to: 'sally_to_dr_finklestein',
+            message: 'i will poison you so i can get away',
+            updated: '2015-10-31 15:00:20.396000000',
+          }, {
+            id: 'dr_finklesteins_response',
+            in_reply_to: 'sally_to_dr_finklestein',
+            message: 'no i will pull a thread and your arm will fall off',
+            updated: '2015-10-31 11:00:20.396000000',
+          }, {
+            id: 'sallys_mission',
+            message: 'i have to find santa',
+            updated: '2015-12-24 15:00:20.396000000',
+          },
+        ];
+        const results = element._sortedComments(comments);
+        assert.deepEqual(results, [
+          {
+            id: 'sally_to_dr_finklestein',
+            message: 'i’m running away',
+            updated: '2015-10-31 09:00:20.396000000',
+          }, {
+            id: 'dr_finklesteins_response',
+            in_reply_to: 'sally_to_dr_finklestein',
+            message: 'no i will pull a thread and your arm will fall off',
+            updated: '2015-10-31 11:00:20.396000000',
+          }, {
+            id: 'sallys_defiance',
+            in_reply_to: 'sally_to_dr_finklestein',
+            message: 'i will poison you so i can get away',
+            updated: '2015-10-31 15:00:20.396000000',
+          }, {
+            id: 'sallys_confession',
+            message: 'i like you, jack',
+            updated: '2015-12-24 15:00:20.396000000',
+          }, {
+            id: 'sallys_mission',
+            message: 'i have to find santa',
+            updated: '2015-12-24 15:00:20.396000000',
+          }, {
+            message: 'i like you, too',
+            in_reply_to: 'sallys_confession',
+            __date: new Date('2015-12-25'),
+          },
+        ]);
+      });
+
+      test('addOrEditDraft w/ edit draft', () => {
+        element.comments = [{
+          id: 'jacks_reply',
           message: 'i like you, too',
           in_reply_to: 'sallys_confession',
-          __date: new Date('2015-12-25'),
-        }, {
-          id: 'sallys_confession',
-          message: 'i like you, jack',
-          updated: '2015-12-24 15:00:20.396000000',
-        }, {
-          id: 'sally_to_dr_finklestein',
-          message: 'i’m running away',
-          updated: '2015-10-31 09:00:20.396000000',
-        }, {
-          id: 'sallys_defiance',
-          in_reply_to: 'sally_to_dr_finklestein',
-          message: 'i will poison you so i can get away',
-          updated: '2015-10-31 15:00:20.396000000',
-        }, {
-          id: 'dr_finklesteins_response',
-          in_reply_to: 'sally_to_dr_finklestein',
-          message: 'no i will pull a thread and your arm will fall off',
-          updated: '2015-10-31 11:00:20.396000000',
-        }, {
-          id: 'sallys_mission',
-          message: 'i have to find santa',
-          updated: '2015-12-24 15:00:20.396000000',
-        },
-      ];
-      const results = element._sortedComments(comments);
-      assert.deepEqual(results, [
-        {
-          id: 'sally_to_dr_finklestein',
-          message: 'i’m running away',
-          updated: '2015-10-31 09:00:20.396000000',
-        }, {
-          id: 'dr_finklesteins_response',
-          in_reply_to: 'sally_to_dr_finklestein',
-          message: 'no i will pull a thread and your arm will fall off',
-          updated: '2015-10-31 11:00:20.396000000',
-        }, {
-          id: 'sallys_defiance',
-          in_reply_to: 'sally_to_dr_finklestein',
-          message: 'i will poison you so i can get away',
-          updated: '2015-10-31 15:00:20.396000000',
-        }, {
-          id: 'sallys_confession',
-          message: 'i like you, jack',
-          updated: '2015-12-24 15:00:20.396000000',
-        }, {
-          id: 'sallys_mission',
-          message: 'i have to find santa',
-          updated: '2015-12-24 15:00:20.396000000',
-        }, {
-          message: 'i like you, too',
-          in_reply_to: 'sallys_confession',
-          __date: new Date('2015-12-25'),
-        },
-      ]);
-    });
+          updated: '2015-12-25 15:00:20.396000000',
+          __draft: true,
+        }];
+        const commentElStub = sandbox.stub(element, '_commentElWithDraftID',
+            () => { return {}; });
+        const addDraftStub = sandbox.stub(element, 'addDraft');
 
-    test('addOrEditDraft w/ edit draft', () => {
-      element.comments = [{
-        id: 'jacks_reply',
-        message: 'i like you, too',
-        in_reply_to: 'sallys_confession',
-        updated: '2015-12-25 15:00:20.396000000',
-        __draft: true,
-      }];
-      const commentElStub = sandbox.stub(element, '_commentElWithDraftID',
-          () => { return {}; });
-      const addDraftStub = sandbox.stub(element, 'addDraft');
+        element.addOrEditDraft(123);
 
-      element.addOrEditDraft(123);
-
-      assert.isTrue(commentElStub.called);
-      assert.isFalse(addDraftStub.called);
-    });
-
-    test('addOrEditDraft w/o edit draft', () => {
-      element.comments = [];
-      const commentElStub = sandbox.stub(element, '_commentElWithDraftID',
-          () => { return {}; });
-      const addDraftStub = sandbox.stub(element, 'addDraft');
-
-      element.addOrEditDraft(123);
-
-      assert.isFalse(commentElStub.called);
-      assert.isTrue(addDraftStub.called);
-    });
-
-    test('_shouldDisableAction', () => {
-      let showActions = true;
-      const lastComment = {};
-      assert.equal(
-          element._shouldDisableAction(showActions, lastComment), false);
-      showActions = false;
-      assert.equal(
-          element._shouldDisableAction(showActions, lastComment), true);
-      showActions = true;
-      lastComment.__draft = true;
-      assert.equal(
-          element._shouldDisableAction(showActions, lastComment), true);
-      const robotComment = {};
-      robotComment.robot_id = true;
-      assert.equal(
-          element._shouldDisableAction(showActions, robotComment), false);
-    });
-
-    test('_hideActions', () => {
-      let showActions = true;
-      const lastComment = {};
-      assert.equal(element._hideActions(showActions, lastComment), false);
-      showActions = false;
-      assert.equal(element._hideActions(showActions, lastComment), true);
-      showActions = true;
-      lastComment.__draft = true;
-      assert.equal(element._hideActions(showActions, lastComment), true);
-      const robotComment = {};
-      robotComment.robot_id = true;
-      assert.equal(element._hideActions(showActions, robotComment), true);
-    });
-
-    test('setting project name loads the project config', done => {
-      const projectName = 'foo/bar/baz';
-      const getProjectStub = sandbox.stub(element.$.restAPI, 'getProjectConfig')
-          .returns(Promise.resolve({}));
-      element.projectName = projectName;
-      flush(() => {
-        assert.isTrue(getProjectStub.calledWithExactly(projectName));
-        done();
+        assert.isTrue(commentElStub.called);
+        assert.isFalse(addDraftStub.called);
       });
-    });
 
-    test('optionally show file path', () => {
-      // Path info doesn't exist when showFilePath is false. Because it's in a
-      // dom-if it is not yet in the dom.
-      assert.isNotOk(element.$$('.pathInfo'));
+      test('addOrEditDraft w/o edit draft', () => {
+        element.comments = [];
+        const commentElStub = sandbox.stub(element, '_commentElWithDraftID',
+            () => { return {}; });
+        const addDraftStub = sandbox.stub(element, 'addDraft');
 
-      sandbox.stub(Gerrit.Nav, 'getUrlForDiffById');
-      element.changeNum = 123;
-      element.projectName = 'test project';
-      element.path = 'path/to/file';
-      element.patchNum = 3;
-      element.lineNum = 5;
-      element.showFilePath = true;
-      flushAsynchronousOperations();
-      assert.isOk(element.$$('.pathInfo'));
-      assert.notEqual(getComputedStyle(element.$$('.pathInfo')).display,
-          'none');
-      assert.isTrue(Gerrit.Nav.getUrlForDiffById.lastCall.calledWithExactly(
-          element.changeNum, element.projectName, element.path,
-          element.patchNum, null, element.lineNum));
-    });
+        element.addOrEditDraft(123);
 
-    test('_computeDisplayPath', () => {
-      const path = 'path/to/file';
-      assert.equal(element._computeDisplayPath(path), 'path/to/file');
+        assert.isFalse(commentElStub.called);
+        assert.isTrue(addDraftStub.called);
+      });
 
-      element.lineNum = 5;
-      assert.equal(element._computeDisplayPath(path), 'path/to/file#5');
+      test('_shouldDisableAction', () => {
+        let showActions = true;
+        const lastComment = {};
+        assert.equal(
+            element._shouldDisableAction(showActions, lastComment), false);
+        showActions = false;
+        assert.equal(
+            element._shouldDisableAction(showActions, lastComment), true);
+        showActions = true;
+        lastComment.__draft = true;
+        assert.equal(
+            element._shouldDisableAction(showActions, lastComment), true);
+        const robotComment = {};
+        robotComment.robot_id = true;
+        assert.equal(
+            element._shouldDisableAction(showActions, robotComment), false);
+      });
+
+      test('_hideActions', () => {
+        let showActions = true;
+        const lastComment = {};
+        assert.equal(element._hideActions(showActions, lastComment), false);
+        showActions = false;
+        assert.equal(element._hideActions(showActions, lastComment), true);
+        showActions = true;
+        lastComment.__draft = true;
+        assert.equal(element._hideActions(showActions, lastComment), true);
+        const robotComment = {};
+        robotComment.robot_id = true;
+        assert.equal(element._hideActions(showActions, robotComment), true);
+      });
+
+      test('setting project name loads the project config', done => {
+        const projectName = 'foo/bar/baz';
+        const getProjectStub = sandbox.stub(element.$.restAPI, 'getProjectConfig')
+            .returns(Promise.resolve({}));
+        element.projectName = projectName;
+        flush(() => {
+          assert.isTrue(getProjectStub.calledWithExactly(projectName));
+          done();
+        });
+      });
+
+      test('optionally show file path', () => {
+        // Path info doesn't exist when showFilePath is false. Because it's in a
+        // dom-if it is not yet in the dom.
+        assert.isNotOk(element.$$('.pathInfo'));
+
+        sandbox.stub(Gerrit.Nav, 'getUrlForDiffById');
+        element.changeNum = 123;
+        element.projectName = 'test project';
+        element.path = 'path/to/file';
+        element.patchNum = 3;
+        element.lineNum = 5;
+        element.showFilePath = true;
+        flushAsynchronousOperations();
+        assert.isOk(element.$$('.pathInfo'));
+        assert.notEqual(getComputedStyle(element.$$('.pathInfo')).display,
+            'none');
+        assert.isTrue(Gerrit.Nav.getUrlForDiffById.lastCall.calledWithExactly(
+            element.changeNum, element.projectName, element.path,
+            element.patchNum, null, element.lineNum));
+      });
+
+      test('_computeDisplayPath', () => {
+        const path = 'path/to/file';
+        assert.equal(element._computeDisplayPath(path), 'path/to/file');
+
+        element.lineNum = 5;
+        assert.equal(element._computeDisplayPath(path), 'path/to/file#5');
+      });
     });
   });
 
@@ -755,4 +760,4 @@
       assert.notOk(element.hasAttribute('range'));
     });
   });
-</script>
+</script>
\ No newline at end of file
diff --git a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.html b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.html
index 31de1ce..ea6c0de 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.html
+++ b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.html
@@ -328,6 +328,18 @@
         </div>
         <div class="robotActions" hidden$="[[!_showRobotActions]]">
           <template is="dom-if" if="[[isRobotComment]]">
+            <gr-endpoint-decorator name="robot-comment-controls">
+              <gr-endpoint-param name="comment" value="[[comment]]">
+              </gr-endpoint-param>
+            </gr-endpoint-decorator>
+            <gr-button
+                link
+                secondary
+                class="action show-fix"
+                hidden$="[[_hasNoFix(comment)]]"
+                on-click="_handleShowFix">
+              Show Fix
+            </gr-button>
             <template is="dom-if" if="[[!_hasHumanReply]]">
               <gr-button
                   link
@@ -337,18 +349,6 @@
                 Please Fix
               </gr-button>
             </template>
-            <gr-button
-                link
-                secondary
-                class="action show-fix"
-                hidden$="[[_hasNoFix(comment)]]"
-                on-click="_handleShowFix">
-              Show Fix
-            </gr-button>
-            <gr-endpoint-decorator name="robot-comment-controls">
-              <gr-endpoint-param name="comment" value="[[comment]]">
-              </gr-endpoint-param>
-            </gr-endpoint-decorator>
           </template>
         </div>
       </div>
diff --git a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.html b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.html
index e3391a0..8bc9518 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="/bower_components/page/page.js"></script>
 <script src="../../../scripts/util.js"></script>
@@ -49,981 +50,986 @@
     return getComputedStyle(el).getPropertyValue('display') !== 'none';
   }
 
-  suite('gr-comment tests', () => {
-    let element;
-    let sandbox;
-    setup(() => {
-      stub('gr-rest-api-interface', {
-        getAccount() { return Promise.resolve(null); },
-      });
-      element = fixture('basic');
-      element.comment = {
-        author: {
-          name: 'Mr. Peanutbutter',
-          email: 'tenn1sballchaser@aol.com',
-        },
-        id: 'baf0414d_60047215',
-        line: 5,
-        message: 'is this a crossover episode!?',
-        updated: '2015-12-08 19:48:33.843000000',
-      };
-      sandbox = sinon.sandbox.create();
-    });
+  suite('gr-comment tests', async () => {
+    await readyToTest();
 
-    teardown(() => {
-      sandbox.restore();
-    });
-
-    test('collapsible comments', () => {
-      // When a comment (not draft) is loaded, it should be collapsed
-      assert.isTrue(element.collapsed);
-      assert.isFalse(isVisible(element.$$('gr-formatted-text')),
-          'gr-formatted-text is not visible');
-      assert.isFalse(isVisible(element.$$('.actions')),
-          'actions are not visible');
-      assert.isNotOk(element.textarea, 'textarea is not visible');
-
-      // The header middle content is only visible when comments are collapsed.
-      // It shows the message in a condensed way, and limits to a single line.
-      assert.isTrue(isVisible(element.$$('.collapsedContent')),
-          'header middle content is visible');
-
-      // When the header row is clicked, the comment should expand
-      MockInteractions.tap(element.$.header);
-      assert.isFalse(element.collapsed);
-      assert.isTrue(isVisible(element.$$('gr-formatted-text')),
-          'gr-formatted-text is visible');
-      assert.isTrue(isVisible(element.$$('.actions')),
-          'actions are visible');
-      assert.isNotOk(element.textarea, 'textarea is not visible');
-      assert.isFalse(isVisible(element.$$('.collapsedContent')),
-          'header middle content is not visible');
-    });
-
-    test('clicking on date link fires event', () => {
-      element.side = 'PARENT';
-      const stub = sinon.stub();
-      element.addEventListener('comment-anchor-tap', stub);
-      const dateEl = element.$$('.date');
-      assert.ok(dateEl);
-      MockInteractions.tap(dateEl);
-
-      assert.isTrue(stub.called);
-      assert.deepEqual(stub.lastCall.args[0].detail,
-          {side: element.side, number: element.comment.line});
-    });
-
-    test('message is not retrieved from storage when other edits', done => {
-      const storageStub = sandbox.stub(element.$.storage, 'getDraftComment');
-      const loadSpy = sandbox.spy(element, '_loadLocalDraft');
-
-      element.changeNum = 1;
-      element.patchNum = 1;
-      element.comment = {
-        author: {
-          name: 'Mr. Peanutbutter',
-          email: 'tenn1sballchaser@aol.com',
-        },
-        line: 5,
-        __otherEditing: true,
-      };
-      flush(() => {
-        assert.isTrue(loadSpy.called);
-        assert.isFalse(storageStub.called);
-        done();
-      });
-    });
-
-    test('message is retrieved from storage when no other edits', done => {
-      const storageStub = sandbox.stub(element.$.storage, 'getDraftComment');
-      const loadSpy = sandbox.spy(element, '_loadLocalDraft');
-
-      element.changeNum = 1;
-      element.patchNum = 1;
-      element.comment = {
-        author: {
-          name: 'Mr. Peanutbutter',
-          email: 'tenn1sballchaser@aol.com',
-        },
-        line: 5,
-      };
-      flush(() => {
-        assert.isTrue(loadSpy.called);
-        assert.isTrue(storageStub.called);
-        done();
-      });
-    });
-
-    test('_getPatchNum', () => {
-      element.side = 'PARENT';
-      element.patchNum = 1;
-      assert.equal(element._getPatchNum(), 'PARENT');
-      element.side = 'REVISION';
-      assert.equal(element._getPatchNum(), 1);
-    });
-
-    test('comment expand and collapse', () => {
-      element.collapsed = true;
-      assert.isFalse(isVisible(element.$$('gr-formatted-text')),
-          'gr-formatted-text is not visible');
-      assert.isFalse(isVisible(element.$$('.actions')),
-          'actions are not visible');
-      assert.isNotOk(element.textarea, 'textarea is not visible');
-      assert.isTrue(isVisible(element.$$('.collapsedContent')),
-          'header middle content is visible');
-
-      element.collapsed = false;
-      assert.isFalse(element.collapsed);
-      assert.isTrue(isVisible(element.$$('gr-formatted-text')),
-          'gr-formatted-text is visible');
-      assert.isTrue(isVisible(element.$$('.actions')),
-          'actions are visible');
-      assert.isNotOk(element.textarea, 'textarea is not visible');
-      assert.isFalse(isVisible(element.$$('.collapsedContent')),
-          'header middle content is is not visible');
-    });
-
-    suite('while editing', () => {
+    suite('basic tests', () => {
+      let element;
+      let sandbox;
       setup(() => {
-        element.editing = true;
-        element._messageText = 'test';
-        sandbox.stub(element, '_handleCancel');
-        sandbox.stub(element, '_handleSave');
-        flushAsynchronousOperations();
+        stub('gr-rest-api-interface', {
+          getAccount() { return Promise.resolve(null); },
+        });
+        element = fixture('basic');
+        element.comment = {
+          author: {
+            name: 'Mr. Peanutbutter',
+            email: 'tenn1sballchaser@aol.com',
+          },
+          id: 'baf0414d_60047215',
+          line: 5,
+          message: 'is this a crossover episode!?',
+          updated: '2015-12-08 19:48:33.843000000',
+        };
+        sandbox = sinon.sandbox.create();
       });
 
-      suite('when text is empty', () => {
+      teardown(() => {
+        sandbox.restore();
+      });
+
+      test('collapsible comments', () => {
+        // When a comment (not draft) is loaded, it should be collapsed
+        assert.isTrue(element.collapsed);
+        assert.isFalse(isVisible(element.$$('gr-formatted-text')),
+            'gr-formatted-text is not visible');
+        assert.isFalse(isVisible(element.$$('.actions')),
+            'actions are not visible');
+        assert.isNotOk(element.textarea, 'textarea is not visible');
+
+        // The header middle content is only visible when comments are collapsed.
+        // It shows the message in a condensed way, and limits to a single line.
+        assert.isTrue(isVisible(element.$$('.collapsedContent')),
+            'header middle content is visible');
+
+        // When the header row is clicked, the comment should expand
+        MockInteractions.tap(element.$.header);
+        assert.isFalse(element.collapsed);
+        assert.isTrue(isVisible(element.$$('gr-formatted-text')),
+            'gr-formatted-text is visible');
+        assert.isTrue(isVisible(element.$$('.actions')),
+            'actions are visible');
+        assert.isNotOk(element.textarea, 'textarea is not visible');
+        assert.isFalse(isVisible(element.$$('.collapsedContent')),
+            'header middle content is not visible');
+      });
+
+      test('clicking on date link fires event', () => {
+        element.side = 'PARENT';
+        const stub = sinon.stub();
+        element.addEventListener('comment-anchor-tap', stub);
+        const dateEl = element.$$('.date');
+        assert.ok(dateEl);
+        MockInteractions.tap(dateEl);
+
+        assert.isTrue(stub.called);
+        assert.deepEqual(stub.lastCall.args[0].detail,
+            {side: element.side, number: element.comment.line});
+      });
+
+      test('message is not retrieved from storage when other edits', done => {
+        const storageStub = sandbox.stub(element.$.storage, 'getDraftComment');
+        const loadSpy = sandbox.spy(element, '_loadLocalDraft');
+
+        element.changeNum = 1;
+        element.patchNum = 1;
+        element.comment = {
+          author: {
+            name: 'Mr. Peanutbutter',
+            email: 'tenn1sballchaser@aol.com',
+          },
+          line: 5,
+          __otherEditing: true,
+        };
+        flush(() => {
+          assert.isTrue(loadSpy.called);
+          assert.isFalse(storageStub.called);
+          done();
+        });
+      });
+
+      test('message is retrieved from storage when no other edits', done => {
+        const storageStub = sandbox.stub(element.$.storage, 'getDraftComment');
+        const loadSpy = sandbox.spy(element, '_loadLocalDraft');
+
+        element.changeNum = 1;
+        element.patchNum = 1;
+        element.comment = {
+          author: {
+            name: 'Mr. Peanutbutter',
+            email: 'tenn1sballchaser@aol.com',
+          },
+          line: 5,
+        };
+        flush(() => {
+          assert.isTrue(loadSpy.called);
+          assert.isTrue(storageStub.called);
+          done();
+        });
+      });
+
+      test('_getPatchNum', () => {
+        element.side = 'PARENT';
+        element.patchNum = 1;
+        assert.equal(element._getPatchNum(), 'PARENT');
+        element.side = 'REVISION';
+        assert.equal(element._getPatchNum(), 1);
+      });
+
+      test('comment expand and collapse', () => {
+        element.collapsed = true;
+        assert.isFalse(isVisible(element.$$('gr-formatted-text')),
+            'gr-formatted-text is not visible');
+        assert.isFalse(isVisible(element.$$('.actions')),
+            'actions are not visible');
+        assert.isNotOk(element.textarea, 'textarea is not visible');
+        assert.isTrue(isVisible(element.$$('.collapsedContent')),
+            'header middle content is visible');
+
+        element.collapsed = false;
+        assert.isFalse(element.collapsed);
+        assert.isTrue(isVisible(element.$$('gr-formatted-text')),
+            'gr-formatted-text is visible');
+        assert.isTrue(isVisible(element.$$('.actions')),
+            'actions are visible');
+        assert.isNotOk(element.textarea, 'textarea is not visible');
+        assert.isFalse(isVisible(element.$$('.collapsedContent')),
+            'header middle content is is not visible');
+      });
+
+      suite('while editing', () => {
         setup(() => {
-          element._messageText = '';
-          element.comment = {};
+          element.editing = true;
+          element._messageText = 'test';
+          sandbox.stub(element, '_handleCancel');
+          sandbox.stub(element, '_handleSave');
+          flushAsynchronousOperations();
         });
 
-        test('esc closes comment when text is empty', () => {
+        suite('when text is empty', () => {
+          setup(() => {
+            element._messageText = '';
+            element.comment = {};
+          });
+
+          test('esc closes comment when text is empty', () => {
+            MockInteractions.pressAndReleaseKeyOn(
+                element.textarea, 27); // esc
+            assert.isTrue(element._handleCancel.called);
+          });
+
+          test('ctrl+enter does not save', () => {
+            MockInteractions.pressAndReleaseKeyOn(
+                element.textarea, 13, 'ctrl'); // ctrl + enter
+            assert.isFalse(element._handleSave.called);
+          });
+
+          test('meta+enter does not save', () => {
+            MockInteractions.pressAndReleaseKeyOn(
+                element.textarea, 13, 'meta'); // meta + enter
+            assert.isFalse(element._handleSave.called);
+          });
+
+          test('ctrl+s does not save', () => {
+            MockInteractions.pressAndReleaseKeyOn(
+                element.textarea, 83, 'ctrl'); // ctrl + s
+            assert.isFalse(element._handleSave.called);
+          });
+        });
+
+        test('esc does not close comment that has content', () => {
           MockInteractions.pressAndReleaseKeyOn(
               element.textarea, 27); // esc
-          assert.isTrue(element._handleCancel.called);
+          assert.isFalse(element._handleCancel.called);
         });
 
-        test('ctrl+enter does not save', () => {
+        test('ctrl+enter saves', () => {
           MockInteractions.pressAndReleaseKeyOn(
               element.textarea, 13, 'ctrl'); // ctrl + enter
-          assert.isFalse(element._handleSave.called);
+          assert.isTrue(element._handleSave.called);
         });
 
-        test('meta+enter does not save', () => {
+        test('meta+enter saves', () => {
           MockInteractions.pressAndReleaseKeyOn(
               element.textarea, 13, 'meta'); // meta + enter
-          assert.isFalse(element._handleSave.called);
+          assert.isTrue(element._handleSave.called);
         });
 
-        test('ctrl+s does not save', () => {
+        test('ctrl+s saves', () => {
           MockInteractions.pressAndReleaseKeyOn(
               element.textarea, 83, 'ctrl'); // ctrl + s
-          assert.isFalse(element._handleSave.called);
+          assert.isTrue(element._handleSave.called);
         });
       });
-
-      test('esc does not close comment that has content', () => {
-        MockInteractions.pressAndReleaseKeyOn(
-            element.textarea, 27); // esc
-        assert.isFalse(element._handleCancel.called);
+      test('delete comment button for non-admins is hidden', () => {
+        element._isAdmin = false;
+        assert.isFalse(element.$$('.action.delete')
+            .classList.contains('showDeleteButtons'));
       });
 
-      test('ctrl+enter saves', () => {
-        MockInteractions.pressAndReleaseKeyOn(
-            element.textarea, 13, 'ctrl'); // ctrl + enter
-        assert.isTrue(element._handleSave.called);
+      test('delete comment button for admins with draft is hidden', () => {
+        element._isAdmin = false;
+        element.draft = true;
+        assert.isFalse(element.$$('.action.delete')
+            .classList.contains('showDeleteButtons'));
       });
 
-      test('meta+enter saves', () => {
-        MockInteractions.pressAndReleaseKeyOn(
-            element.textarea, 13, 'meta'); // meta + enter
-        assert.isTrue(element._handleSave.called);
-      });
-
-      test('ctrl+s saves', () => {
-        MockInteractions.pressAndReleaseKeyOn(
-            element.textarea, 83, 'ctrl'); // ctrl + s
-        assert.isTrue(element._handleSave.called);
-      });
-    });
-    test('delete comment button for non-admins is hidden', () => {
-      element._isAdmin = false;
-      assert.isFalse(element.$$('.action.delete')
-          .classList.contains('showDeleteButtons'));
-    });
-
-    test('delete comment button for admins with draft is hidden', () => {
-      element._isAdmin = false;
-      element.draft = true;
-      assert.isFalse(element.$$('.action.delete')
-          .classList.contains('showDeleteButtons'));
-    });
-
-    test('delete comment', done => {
-      sandbox.stub(
-          element.$.restAPI, 'deleteComment').returns(Promise.resolve({}));
-      sandbox.spy(element.confirmDeleteOverlay, 'open');
-      element.changeNum = 42;
-      element.patchNum = 0xDEADBEEF;
-      element._isAdmin = true;
-      assert.isTrue(element.$$('.action.delete')
-          .classList.contains('showDeleteButtons'));
-      MockInteractions.tap(element.$$('.action.delete'));
-      flush(() => {
-        element.confirmDeleteOverlay.open.lastCall.returnValue.then(() => {
-          const dialog =
-              window.confirmDeleteOverlay.querySelector('#confirmDeleteComment');
-          dialog.message = 'removal reason';
-          element._handleConfirmDeleteComment();
-          assert.isTrue(element.$.restAPI.deleteComment.calledWith(
-              42, 0xDEADBEEF, 'baf0414d_60047215', 'removal reason'));
-          done();
-        });
-      });
-    });
-
-    suite('draft update reporting', () => {
-      let endStub;
-      let getTimerStub;
-      let mockEvent;
-
-      setup(() => {
-        mockEvent = {preventDefault() {}};
-        sandbox.stub(element, 'save')
-            .returns(Promise.resolve({}));
-        sandbox.stub(element, '_discardDraft')
-            .returns(Promise.resolve({}));
-        endStub = sinon.stub();
-        getTimerStub = sandbox.stub(element.$.reporting, 'getTimer')
-            .returns({end: endStub});
-      });
-
-      test('create', () => {
-        element.comment = {};
-        return element._handleSave(mockEvent).then(() => {
-          assert.isTrue(endStub.calledOnce);
-          assert.isTrue(getTimerStub.calledOnce);
-          assert.equal(getTimerStub.lastCall.args[0], 'CreateDraftComment');
-        });
-      });
-
-      test('update', () => {
-        element.comment = {id: 'abc_123'};
-        return element._handleSave(mockEvent).then(() => {
-          assert.isTrue(endStub.calledOnce);
-          assert.isTrue(getTimerStub.calledOnce);
-          assert.equal(getTimerStub.lastCall.args[0], 'UpdateDraftComment');
-        });
-      });
-
-      test('discard', () => {
-        element.comment = {id: 'abc_123'};
-        sandbox.stub(element, '_closeConfirmDiscardOverlay');
-        return element._handleConfirmDiscard(mockEvent).then(() => {
-          assert.isTrue(endStub.calledOnce);
-          assert.isTrue(getTimerStub.calledOnce);
-          assert.equal(getTimerStub.lastCall.args[0], 'DiscardDraftComment');
-        });
-      });
-    });
-
-    test('edit reports interaction', () => {
-      const reportStub = sandbox.stub(element.$.reporting,
-          'recordDraftInteraction');
-      MockInteractions.tap(element.$$('.edit'));
-      assert.isTrue(reportStub.calledOnce);
-    });
-
-    test('discard reports interaction', () => {
-      const reportStub = sandbox.stub(element.$.reporting,
-          'recordDraftInteraction');
-      element.draft = true;
-      MockInteractions.tap(element.$$('.discard'));
-      assert.isTrue(reportStub.calledOnce);
-    });
-  });
-
-  suite('gr-comment draft tests', () => {
-    let element;
-    let sandbox;
-
-    setup(() => {
-      stub('gr-rest-api-interface', {
-        getAccount() { return Promise.resolve(null); },
-        saveDiffDraft() {
-          return Promise.resolve({
-            ok: true,
-            text() {
-              return Promise.resolve(
-                  ')]}\'\n{' +
-                  '"id": "baf0414d_40572e03",' +
-                  '"path": "/path/to/file",' +
-                  '"line": 5,' +
-                  '"updated": "2015-12-08 21:52:36.177000000",' +
-                  '"message": "saved!"' +
-                '}'
-              );
-            },
+      test('delete comment', done => {
+        sandbox.stub(
+            element.$.restAPI, 'deleteComment').returns(Promise.resolve({}));
+        sandbox.spy(element.confirmDeleteOverlay, 'open');
+        element.changeNum = 42;
+        element.patchNum = 0xDEADBEEF;
+        element._isAdmin = true;
+        assert.isTrue(element.$$('.action.delete')
+            .classList.contains('showDeleteButtons'));
+        MockInteractions.tap(element.$$('.action.delete'));
+        flush(() => {
+          element.confirmDeleteOverlay.open.lastCall.returnValue.then(() => {
+            const dialog =
+                window.confirmDeleteOverlay
+                    .querySelector('#confirmDeleteComment');
+            dialog.message = 'removal reason';
+            element._handleConfirmDeleteComment();
+            assert.isTrue(element.$.restAPI.deleteComment.calledWith(
+                42, 0xDEADBEEF, 'baf0414d_60047215', 'removal reason'));
+            done();
           });
-        },
-        removeChangeReviewer() {
-          return Promise.resolve({ok: true});
-        },
-      });
-      stub('gr-storage', {
-        getDraftComment() { return null; },
-      });
-      element = fixture('draft');
-      element.changeNum = 42;
-      element.patchNum = 1;
-      element.editing = false;
-      element.comment = {
-        __commentSide: 'right',
-        __draft: true,
-        __draftID: 'temp_draft_id',
-        path: '/path/to/file',
-        line: 5,
-      };
-      element.commentSide = 'right';
-      sandbox = sinon.sandbox.create();
-    });
-
-    teardown(() => {
-      sandbox.restore();
-    });
-
-    test('button visibility states', () => {
-      element.showActions = false;
-      assert.isTrue(element.$$('.humanActions').hasAttribute('hidden'));
-      assert.isTrue(element.$$('.robotActions').hasAttribute('hidden'));
-
-      element.showActions = true;
-      assert.isFalse(element.$$('.humanActions').hasAttribute('hidden'));
-      assert.isTrue(element.$$('.robotActions').hasAttribute('hidden'));
-
-      element.draft = true;
-      assert.isTrue(isVisible(element.$$('.edit')), 'edit is visible');
-      assert.isTrue(isVisible(element.$$('.discard')), 'discard is visible');
-      assert.isFalse(isVisible(element.$$('.save')), 'save is not visible');
-      assert.isFalse(isVisible(element.$$('.cancel')), 'cancel is not visible');
-      assert.isTrue(isVisible(element.$$('.resolve')), 'resolve is visible');
-      assert.isFalse(element.$$('.humanActions').hasAttribute('hidden'));
-      assert.isTrue(element.$$('.robotActions').hasAttribute('hidden'));
-
-      element.editing = true;
-      flushAsynchronousOperations();
-      assert.isFalse(isVisible(element.$$('.edit')), 'edit is not visible');
-      assert.isFalse(isVisible(element.$$('.discard')), 'discard not visible');
-      assert.isTrue(isVisible(element.$$('.save')), 'save is visible');
-      assert.isTrue(isVisible(element.$$('.cancel')), 'cancel is visible');
-      assert.isTrue(isVisible(element.$$('.resolve')), 'resolve is visible');
-      assert.isFalse(element.$$('.humanActions').hasAttribute('hidden'));
-      assert.isTrue(element.$$('.robotActions').hasAttribute('hidden'));
-
-      element.draft = false;
-      element.editing = false;
-      flushAsynchronousOperations();
-      assert.isFalse(isVisible(element.$$('.edit')), 'edit is not visible');
-      assert.isFalse(isVisible(element.$$('.discard')),
-          'discard is not visible');
-      assert.isFalse(isVisible(element.$$('.save')), 'save is not visible');
-      assert.isFalse(isVisible(element.$$('.cancel')), 'cancel is not visible');
-      assert.isFalse(element.$$('.humanActions').hasAttribute('hidden'));
-      assert.isTrue(element.$$('.robotActions').hasAttribute('hidden'));
-
-      element.comment.id = 'foo';
-      element.draft = true;
-      element.editing = true;
-      flushAsynchronousOperations();
-      assert.isTrue(isVisible(element.$$('.cancel')), 'cancel is visible');
-      assert.isFalse(element.$$('.humanActions').hasAttribute('hidden'));
-      assert.isTrue(element.$$('.robotActions').hasAttribute('hidden'));
-
-      // Delete button is not hidden by default
-      assert.isFalse(element.shadowRoot.querySelector('#deleteBtn').hidden);
-
-      element.isRobotComment = true;
-      element.draft = true;
-      assert.isTrue(element.$$('.humanActions').hasAttribute('hidden'));
-      assert.isFalse(element.$$('.robotActions').hasAttribute('hidden'));
-
-      // It is not expected to see Robot comment drafts, but if they appear,
-      // they will behave the same as non-drafts.
-      element.draft = false;
-      assert.isTrue(element.$$('.humanActions').hasAttribute('hidden'));
-      assert.isFalse(element.$$('.robotActions').hasAttribute('hidden'));
-
-      // A robot comment with run ID should display plain text.
-      element.set(['comment', 'robot_run_id'], 'text');
-      element.editing = false;
-      element.collapsed = false;
-      flushAsynchronousOperations();
-      assert.isTrue(element.$$('.robotRun.link').textContent === 'Run Details');
-
-      // A robot comment with run ID and url should display a link.
-      element.set(['comment', 'url'], '/path/to/run');
-      flushAsynchronousOperations();
-      assert.notEqual(getComputedStyle(element.$$('.robotRun.link')).display,
-          'none');
-
-      // Delete button is hidden for robot comments
-      assert.isTrue(element.shadowRoot.querySelector('#deleteBtn').hidden);
-    });
-
-    test('collapsible drafts', () => {
-      assert.isTrue(element.collapsed);
-      assert.isFalse(isVisible(element.$$('gr-formatted-text')),
-          'gr-formatted-text is not visible');
-      assert.isFalse(isVisible(element.$$('.actions')),
-          'actions are not visible');
-      assert.isNotOk(element.textarea, 'textarea is not visible');
-      assert.isTrue(isVisible(element.$$('.collapsedContent')),
-          'header middle content is visible');
-
-      MockInteractions.tap(element.$.header);
-      assert.isFalse(element.collapsed);
-      assert.isTrue(isVisible(element.$$('gr-formatted-text')),
-          'gr-formatted-text is visible');
-      assert.isTrue(isVisible(element.$$('.actions')),
-          'actions are visible');
-      assert.isNotOk(element.textarea, 'textarea is not visible');
-      assert.isFalse(isVisible(element.$$('.collapsedContent')),
-          'header middle content is is not visible');
-
-      // When the edit button is pressed, should still see the actions
-      // and also textarea
-      MockInteractions.tap(element.$$('.edit'));
-      flushAsynchronousOperations();
-      assert.isFalse(element.collapsed);
-      assert.isFalse(isVisible(element.$$('gr-formatted-text')),
-          'gr-formatted-text is not visible');
-      assert.isTrue(isVisible(element.$$('.actions')),
-          'actions are visible');
-      assert.isTrue(isVisible(element.textarea), 'textarea is visible');
-      assert.isFalse(isVisible(element.$$('.collapsedContent')),
-          'header middle content is not visible');
-
-      // When toggle again, everything should be hidden except for textarea
-      // and header middle content should be visible
-      MockInteractions.tap(element.$.header);
-      assert.isTrue(element.collapsed);
-      assert.isFalse(isVisible(element.$$('gr-formatted-text')),
-          'gr-formatted-text is not visible');
-      assert.isFalse(isVisible(element.$$('.actions')),
-          'actions are not visible');
-      assert.isFalse(isVisible(element.$$('gr-textarea')),
-          'textarea is not visible');
-      assert.isTrue(isVisible(element.$$('.collapsedContent')),
-          'header middle content is visible');
-
-      // When toggle again, textarea should remain open in the state it was
-      // before
-      MockInteractions.tap(element.$.header);
-      assert.isFalse(isVisible(element.$$('gr-formatted-text')),
-          'gr-formatted-text is not visible');
-      assert.isTrue(isVisible(element.$$('.actions')),
-          'actions are visible');
-      assert.isTrue(isVisible(element.textarea), 'textarea is visible');
-      assert.isFalse(isVisible(element.$$('.collapsedContent')),
-          'header middle content is not visible');
-    });
-
-    test('robot comment layout', () => {
-      const comment = Object.assign({
-        robot_id: 'happy_robot_id',
-        url: '/robot/comment',
-        author: {
-          name: 'Happy Robot',
-        },
-      }, element.comment);
-      element.comment = comment;
-      element.collapsed = false;
-      flushAsynchronousOperations();
-
-      let runIdMessage;
-      runIdMessage = element.$$('.runIdMessage');
-      assert.isFalse(runIdMessage.hidden);
-
-      const runDetailsLink = element.$$('.robotRunLink');
-      assert.isTrue(runDetailsLink.href.indexOf(element.comment.url) !== -1);
-
-      const robotServiceName = element.$$('.authorName');
-      assert.isTrue(robotServiceName.textContent === 'happy_robot_id');
-
-      const authorName = element.$$('.robotId');
-      assert.isTrue(authorName.innerText === 'Happy Robot');
-
-      element.collapsed = true;
-      flushAsynchronousOperations();
-      runIdMessage = element.$$('.runIdMessage');
-      assert.isTrue(runIdMessage.hidden);
-    });
-
-    test('draft creation/cancellation', done => {
-      assert.isFalse(element.editing);
-      MockInteractions.tap(element.$$('.edit'));
-      assert.isTrue(element.editing);
-
-      element._messageText = '';
-      const eraseMessageDraftSpy = sandbox.spy(element, '_eraseDraftComment');
-
-      // Save should be disabled on an empty message.
-      let disabled = element.$$('.save').hasAttribute('disabled');
-      assert.isTrue(disabled, 'save button should be disabled.');
-      element._messageText = '     ';
-      disabled = element.$$('.save').hasAttribute('disabled');
-      assert.isTrue(disabled, 'save button should be disabled.');
-
-      const updateStub = sinon.stub();
-      element.addEventListener('comment-update', updateStub);
-
-      let numDiscardEvents = 0;
-      element.addEventListener('comment-discard', e => {
-        numDiscardEvents++;
-        assert.isFalse(eraseMessageDraftSpy.called);
-        if (numDiscardEvents === 2) {
-          assert.isFalse(updateStub.called);
-          done();
-        }
-      });
-      MockInteractions.tap(element.$$('.cancel'));
-      element.flushDebouncer('fire-update');
-      element._messageText = '';
-      flushAsynchronousOperations();
-      MockInteractions.pressAndReleaseKeyOn(element.textarea, 27); // esc
-    });
-
-    test('draft discard removes message from storage', done => {
-      element._messageText = '';
-      const eraseMessageDraftSpy = sandbox.spy(element, '_eraseDraftComment');
-      sandbox.stub(element, '_closeConfirmDiscardOverlay');
-
-      element.addEventListener('comment-discard', e => {
-        assert.isTrue(eraseMessageDraftSpy.called);
-        done();
-      });
-      element._handleConfirmDiscard({preventDefault: sinon.stub()});
-    });
-
-    test('storage is cleared only after save success', () => {
-      element._messageText = 'test';
-      const eraseStub = sandbox.stub(element, '_eraseDraftComment');
-      sandbox.stub(element.$.restAPI, 'getResponseObject')
-          .returns(Promise.resolve({}));
-
-      sandbox.stub(element, '_saveDraft').returns(Promise.resolve({ok: false}));
-
-      const savePromise = element.save();
-      assert.isFalse(eraseStub.called);
-      return savePromise.then(() => {
-        assert.isFalse(eraseStub.called);
-
-        element._saveDraft.restore();
-        sandbox.stub(element, '_saveDraft')
-            .returns(Promise.resolve({ok: true}));
-        return element.save().then(() => {
-          assert.isTrue(eraseStub.called);
         });
       });
+
+      suite('draft update reporting', () => {
+        let endStub;
+        let getTimerStub;
+        let mockEvent;
+
+        setup(() => {
+          mockEvent = {preventDefault() {}};
+          sandbox.stub(element, 'save')
+              .returns(Promise.resolve({}));
+          sandbox.stub(element, '_discardDraft')
+              .returns(Promise.resolve({}));
+          endStub = sinon.stub();
+          getTimerStub = sandbox.stub(element.$.reporting, 'getTimer')
+              .returns({end: endStub});
+        });
+
+        test('create', () => {
+          element.comment = {};
+          return element._handleSave(mockEvent).then(() => {
+            assert.isTrue(endStub.calledOnce);
+            assert.isTrue(getTimerStub.calledOnce);
+            assert.equal(getTimerStub.lastCall.args[0], 'CreateDraftComment');
+          });
+        });
+
+        test('update', () => {
+          element.comment = {id: 'abc_123'};
+          return element._handleSave(mockEvent).then(() => {
+            assert.isTrue(endStub.calledOnce);
+            assert.isTrue(getTimerStub.calledOnce);
+            assert.equal(getTimerStub.lastCall.args[0], 'UpdateDraftComment');
+          });
+        });
+
+        test('discard', () => {
+          element.comment = {id: 'abc_123'};
+          sandbox.stub(element, '_closeConfirmDiscardOverlay');
+          return element._handleConfirmDiscard(mockEvent).then(() => {
+            assert.isTrue(endStub.calledOnce);
+            assert.isTrue(getTimerStub.calledOnce);
+            assert.equal(getTimerStub.lastCall.args[0], 'DiscardDraftComment');
+          });
+        });
+      });
+
+      test('edit reports interaction', () => {
+        const reportStub = sandbox.stub(element.$.reporting,
+            'recordDraftInteraction');
+        MockInteractions.tap(element.$$('.edit'));
+        assert.isTrue(reportStub.calledOnce);
+      });
+
+      test('discard reports interaction', () => {
+        const reportStub = sandbox.stub(element.$.reporting,
+            'recordDraftInteraction');
+        element.draft = true;
+        MockInteractions.tap(element.$$('.discard'));
+        assert.isTrue(reportStub.calledOnce);
+      });
     });
 
-    test('_computeSaveDisabled', () => {
-      const comment = {unresolved: true};
-      const msgComment = {message: 'test', unresolved: true};
-      assert.equal(element._computeSaveDisabled('', comment, false), true);
-      assert.equal(element._computeSaveDisabled('test', comment, false), false);
-      assert.equal(element._computeSaveDisabled('', msgComment, false), true);
-      assert.equal(
-          element._computeSaveDisabled('test', msgComment, false), false);
-      assert.equal(
-          element._computeSaveDisabled('test2', msgComment, false), false);
-      assert.equal(element._computeSaveDisabled('test', comment, true), false);
-      assert.equal(element._computeSaveDisabled('', comment, true), true);
-      assert.equal(element._computeSaveDisabled('', comment, false), true);
-    });
-
-    suite('confirm discard', () => {
-      let discardStub;
-      let overlayStub;
-      let mockEvent;
+    suite('gr-comment draft tests', () => {
+      let element;
+      let sandbox;
 
       setup(() => {
-        discardStub = sandbox.stub(element, '_discardDraft');
-        overlayStub = sandbox.stub(element, '_openOverlay')
-            .returns(Promise.resolve());
-        mockEvent = {preventDefault: sinon.stub()};
-      });
-
-      test('confirms discard of comments with message text', () => {
-        element._messageText = 'test';
-        element._handleDiscard(mockEvent);
-        assert.isTrue(overlayStub.calledWith(element.confirmDiscardOverlay));
-        assert.isFalse(discardStub.called);
-      });
-
-      test('no confirmation for comments without message text', () => {
-        element._messageText = '';
-        element._handleDiscard(mockEvent);
-        assert.isFalse(overlayStub.called);
-        assert.isTrue(discardStub.calledOnce);
-      });
-    });
-
-    test('ctrl+s saves comment', done => {
-      const stub = sinon.stub(element, 'save', () => {
-        assert.isTrue(stub.called);
-        stub.restore();
-        done();
-        return Promise.resolve();
-      });
-      element._messageText = 'is that the horse from horsing around??';
-      element.editing = true;
-      flushAsynchronousOperations();
-      MockInteractions.pressAndReleaseKeyOn(
-          element.textarea.$.textarea.textarea,
-          83, 'ctrl'); // 'ctrl + s'
-    });
-
-    test('draft saving/editing', done => {
-      const fireStub = sinon.stub(element, 'fire');
-      const cancelDebounce = sandbox.stub(element, 'cancelDebouncer');
-
-      element.draft = true;
-      MockInteractions.tap(element.$$('.edit'));
-      element._messageText = 'good news, everyone!';
-      element.flushDebouncer('fire-update');
-      element.flushDebouncer('store');
-      assert(fireStub.calledWith('comment-update'),
-          'comment-update should be sent');
-      assert.isTrue(fireStub.calledOnce);
-
-      element._messageText = 'good news, everyone!';
-      element.flushDebouncer('fire-update');
-      element.flushDebouncer('store');
-      assert.isTrue(fireStub.calledOnce,
-          'No events should fire for text editing');
-
-      MockInteractions.tap(element.$$('.save'));
-
-      assert.isTrue(element.disabled,
-          'Element should be disabled when creating draft.');
-
-      element._xhrPromise.then(draft => {
-        assert(fireStub.calledWith('comment-save'),
-            'comment-save should be sent');
-        assert(cancelDebounce.calledWith('store'));
-
-        assert.deepEqual(fireStub.lastCall.args[1], {
-          comment: {
-            __commentSide: 'right',
-            __draft: true,
-            __draftID: 'temp_draft_id',
-            id: 'baf0414d_40572e03',
-            line: 5,
-            message: 'saved!',
-            path: '/path/to/file',
-            updated: '2015-12-08 21:52:36.177000000',
+        stub('gr-rest-api-interface', {
+          getAccount() { return Promise.resolve(null); },
+          saveDiffDraft() {
+            return Promise.resolve({
+              ok: true,
+              text() {
+                return Promise.resolve(
+                    ')]}\'\n{' +
+                    '"id": "baf0414d_40572e03",' +
+                    '"path": "/path/to/file",' +
+                    '"line": 5,' +
+                    '"updated": "2015-12-08 21:52:36.177000000",' +
+                    '"message": "saved!"' +
+                  '}'
+                );
+              },
+            });
           },
-          patchNum: 1,
+          removeChangeReviewer() {
+            return Promise.resolve({ok: true});
+          },
         });
-        assert.isFalse(element.disabled,
-            'Element should be enabled when done creating draft.');
-        assert.equal(draft.message, 'saved!');
-        assert.isFalse(element.editing);
-      }).then(() => {
+        stub('gr-storage', {
+          getDraftComment() { return null; },
+        });
+        element = fixture('draft');
+        element.changeNum = 42;
+        element.patchNum = 1;
+        element.editing = false;
+        element.comment = {
+          __commentSide: 'right',
+          __draft: true,
+          __draftID: 'temp_draft_id',
+          path: '/path/to/file',
+          line: 5,
+        };
+        element.commentSide = 'right';
+        sandbox = sinon.sandbox.create();
+      });
+
+      teardown(() => {
+        sandbox.restore();
+      });
+
+      test('button visibility states', () => {
+        element.showActions = false;
+        assert.isTrue(element.$$('.humanActions').hasAttribute('hidden'));
+        assert.isTrue(element.$$('.robotActions').hasAttribute('hidden'));
+
+        element.showActions = true;
+        assert.isFalse(element.$$('.humanActions').hasAttribute('hidden'));
+        assert.isTrue(element.$$('.robotActions').hasAttribute('hidden'));
+
+        element.draft = true;
+        assert.isTrue(isVisible(element.$$('.edit')), 'edit is visible');
+        assert.isTrue(isVisible(element.$$('.discard')), 'discard is visible');
+        assert.isFalse(isVisible(element.$$('.save')), 'save is not visible');
+        assert.isFalse(isVisible(element.$$('.cancel')), 'cancel is not visible');
+        assert.isTrue(isVisible(element.$$('.resolve')), 'resolve is visible');
+        assert.isFalse(element.$$('.humanActions').hasAttribute('hidden'));
+        assert.isTrue(element.$$('.robotActions').hasAttribute('hidden'));
+
+        element.editing = true;
+        flushAsynchronousOperations();
+        assert.isFalse(isVisible(element.$$('.edit')), 'edit is not visible');
+        assert.isFalse(isVisible(element.$$('.discard')), 'discard not visible');
+        assert.isTrue(isVisible(element.$$('.save')), 'save is visible');
+        assert.isTrue(isVisible(element.$$('.cancel')), 'cancel is visible');
+        assert.isTrue(isVisible(element.$$('.resolve')), 'resolve is visible');
+        assert.isFalse(element.$$('.humanActions').hasAttribute('hidden'));
+        assert.isTrue(element.$$('.robotActions').hasAttribute('hidden'));
+
+        element.draft = false;
+        element.editing = false;
+        flushAsynchronousOperations();
+        assert.isFalse(isVisible(element.$$('.edit')), 'edit is not visible');
+        assert.isFalse(isVisible(element.$$('.discard')),
+            'discard is not visible');
+        assert.isFalse(isVisible(element.$$('.save')), 'save is not visible');
+        assert.isFalse(isVisible(element.$$('.cancel')), 'cancel is not visible');
+        assert.isFalse(element.$$('.humanActions').hasAttribute('hidden'));
+        assert.isTrue(element.$$('.robotActions').hasAttribute('hidden'));
+
+        element.comment.id = 'foo';
+        element.draft = true;
+        element.editing = true;
+        flushAsynchronousOperations();
+        assert.isTrue(isVisible(element.$$('.cancel')), 'cancel is visible');
+        assert.isFalse(element.$$('.humanActions').hasAttribute('hidden'));
+        assert.isTrue(element.$$('.robotActions').hasAttribute('hidden'));
+
+        // Delete button is not hidden by default
+        assert.isFalse(element.shadowRoot.querySelector('#deleteBtn').hidden);
+
+        element.isRobotComment = true;
+        element.draft = true;
+        assert.isTrue(element.$$('.humanActions').hasAttribute('hidden'));
+        assert.isFalse(element.$$('.robotActions').hasAttribute('hidden'));
+
+        // It is not expected to see Robot comment drafts, but if they appear,
+        // they will behave the same as non-drafts.
+        element.draft = false;
+        assert.isTrue(element.$$('.humanActions').hasAttribute('hidden'));
+        assert.isFalse(element.$$('.robotActions').hasAttribute('hidden'));
+
+        // A robot comment with run ID should display plain text.
+        element.set(['comment', 'robot_run_id'], 'text');
+        element.editing = false;
+        element.collapsed = false;
+        flushAsynchronousOperations();
+        assert.isTrue(element.$$('.robotRun.link').textContent === 'Run Details');
+
+        // A robot comment with run ID and url should display a link.
+        element.set(['comment', 'url'], '/path/to/run');
+        flushAsynchronousOperations();
+        assert.notEqual(getComputedStyle(element.$$('.robotRun.link')).display,
+            'none');
+
+        // Delete button is hidden for robot comments
+        assert.isTrue(element.shadowRoot.querySelector('#deleteBtn').hidden);
+      });
+
+      test('collapsible drafts', () => {
+        assert.isTrue(element.collapsed);
+        assert.isFalse(isVisible(element.$$('gr-formatted-text')),
+            'gr-formatted-text is not visible');
+        assert.isFalse(isVisible(element.$$('.actions')),
+            'actions are not visible');
+        assert.isNotOk(element.textarea, 'textarea is not visible');
+        assert.isTrue(isVisible(element.$$('.collapsedContent')),
+            'header middle content is visible');
+
+        MockInteractions.tap(element.$.header);
+        assert.isFalse(element.collapsed);
+        assert.isTrue(isVisible(element.$$('gr-formatted-text')),
+            'gr-formatted-text is visible');
+        assert.isTrue(isVisible(element.$$('.actions')),
+            'actions are visible');
+        assert.isNotOk(element.textarea, 'textarea is not visible');
+        assert.isFalse(isVisible(element.$$('.collapsedContent')),
+            'header middle content is is not visible');
+
+        // When the edit button is pressed, should still see the actions
+        // and also textarea
         MockInteractions.tap(element.$$('.edit'));
-        element._messageText = 'You’ll be delivering a package to Chapek 9, ' +
-            'a world where humans are killed on sight.';
+        flushAsynchronousOperations();
+        assert.isFalse(element.collapsed);
+        assert.isFalse(isVisible(element.$$('gr-formatted-text')),
+            'gr-formatted-text is not visible');
+        assert.isTrue(isVisible(element.$$('.actions')),
+            'actions are visible');
+        assert.isTrue(isVisible(element.textarea), 'textarea is visible');
+        assert.isFalse(isVisible(element.$$('.collapsedContent')),
+            'header middle content is not visible');
+
+        // When toggle again, everything should be hidden except for textarea
+        // and header middle content should be visible
+        MockInteractions.tap(element.$.header);
+        assert.isTrue(element.collapsed);
+        assert.isFalse(isVisible(element.$$('gr-formatted-text')),
+            'gr-formatted-text is not visible');
+        assert.isFalse(isVisible(element.$$('.actions')),
+            'actions are not visible');
+        assert.isFalse(isVisible(element.$$('gr-textarea')),
+            'textarea is not visible');
+        assert.isTrue(isVisible(element.$$('.collapsedContent')),
+            'header middle content is visible');
+
+        // When toggle again, textarea should remain open in the state it was
+        // before
+        MockInteractions.tap(element.$.header);
+        assert.isFalse(isVisible(element.$$('gr-formatted-text')),
+            'gr-formatted-text is not visible');
+        assert.isTrue(isVisible(element.$$('.actions')),
+            'actions are visible');
+        assert.isTrue(isVisible(element.textarea), 'textarea is visible');
+        assert.isFalse(isVisible(element.$$('.collapsedContent')),
+            'header middle content is not visible');
+      });
+
+      test('robot comment layout', () => {
+        const comment = Object.assign({
+          robot_id: 'happy_robot_id',
+          url: '/robot/comment',
+          author: {
+            name: 'Happy Robot',
+          },
+        }, element.comment);
+        element.comment = comment;
+        element.collapsed = false;
+        flushAsynchronousOperations();
+
+        let runIdMessage;
+        runIdMessage = element.$$('.runIdMessage');
+        assert.isFalse(runIdMessage.hidden);
+
+        const runDetailsLink = element.$$('.robotRunLink');
+        assert.isTrue(runDetailsLink.href.indexOf(element.comment.url) !== -1);
+
+        const robotServiceName = element.$$('.authorName');
+        assert.isTrue(robotServiceName.textContent === 'happy_robot_id');
+
+        const authorName = element.$$('.robotId');
+        assert.isTrue(authorName.innerText === 'Happy Robot');
+
+        element.collapsed = true;
+        flushAsynchronousOperations();
+        runIdMessage = element.$$('.runIdMessage');
+        assert.isTrue(runIdMessage.hidden);
+      });
+
+      test('draft creation/cancellation', done => {
+        assert.isFalse(element.editing);
+        MockInteractions.tap(element.$$('.edit'));
+        assert.isTrue(element.editing);
+
+        element._messageText = '';
+        const eraseMessageDraftSpy = sandbox.spy(element, '_eraseDraftComment');
+
+        // Save should be disabled on an empty message.
+        let disabled = element.$$('.save').hasAttribute('disabled');
+        assert.isTrue(disabled, 'save button should be disabled.');
+        element._messageText = '     ';
+        disabled = element.$$('.save').hasAttribute('disabled');
+        assert.isTrue(disabled, 'save button should be disabled.');
+
+        const updateStub = sinon.stub();
+        element.addEventListener('comment-update', updateStub);
+
+        let numDiscardEvents = 0;
+        element.addEventListener('comment-discard', e => {
+          numDiscardEvents++;
+          assert.isFalse(eraseMessageDraftSpy.called);
+          if (numDiscardEvents === 2) {
+            assert.isFalse(updateStub.called);
+            done();
+          }
+        });
+        MockInteractions.tap(element.$$('.cancel'));
+        element.flushDebouncer('fire-update');
+        element._messageText = '';
+        flushAsynchronousOperations();
+        MockInteractions.pressAndReleaseKeyOn(element.textarea, 27); // esc
+      });
+
+      test('draft discard removes message from storage', done => {
+        element._messageText = '';
+        const eraseMessageDraftSpy = sandbox.spy(element, '_eraseDraftComment');
+        sandbox.stub(element, '_closeConfirmDiscardOverlay');
+
+        element.addEventListener('comment-discard', e => {
+          assert.isTrue(eraseMessageDraftSpy.called);
+          done();
+        });
+        element._handleConfirmDiscard({preventDefault: sinon.stub()});
+      });
+
+      test('storage is cleared only after save success', () => {
+        element._messageText = 'test';
+        const eraseStub = sandbox.stub(element, '_eraseDraftComment');
+        sandbox.stub(element.$.restAPI, 'getResponseObject')
+            .returns(Promise.resolve({}));
+
+        sandbox.stub(element, '_saveDraft').returns(Promise.resolve({ok: false}));
+
+        const savePromise = element.save();
+        assert.isFalse(eraseStub.called);
+        return savePromise.then(() => {
+          assert.isFalse(eraseStub.called);
+
+          element._saveDraft.restore();
+          sandbox.stub(element, '_saveDraft')
+              .returns(Promise.resolve({ok: true}));
+          return element.save().then(() => {
+            assert.isTrue(eraseStub.called);
+          });
+        });
+      });
+
+      test('_computeSaveDisabled', () => {
+        const comment = {unresolved: true};
+        const msgComment = {message: 'test', unresolved: true};
+        assert.equal(element._computeSaveDisabled('', comment, false), true);
+        assert.equal(element._computeSaveDisabled('test', comment, false), false);
+        assert.equal(element._computeSaveDisabled('', msgComment, false), true);
+        assert.equal(
+            element._computeSaveDisabled('test', msgComment, false), false);
+        assert.equal(
+            element._computeSaveDisabled('test2', msgComment, false), false);
+        assert.equal(element._computeSaveDisabled('test', comment, true), false);
+        assert.equal(element._computeSaveDisabled('', comment, true), true);
+        assert.equal(element._computeSaveDisabled('', comment, false), true);
+      });
+
+      suite('confirm discard', () => {
+        let discardStub;
+        let overlayStub;
+        let mockEvent;
+
+        setup(() => {
+          discardStub = sandbox.stub(element, '_discardDraft');
+          overlayStub = sandbox.stub(element, '_openOverlay')
+              .returns(Promise.resolve());
+          mockEvent = {preventDefault: sinon.stub()};
+        });
+
+        test('confirms discard of comments with message text', () => {
+          element._messageText = 'test';
+          element._handleDiscard(mockEvent);
+          assert.isTrue(overlayStub.calledWith(element.confirmDiscardOverlay));
+          assert.isFalse(discardStub.called);
+        });
+
+        test('no confirmation for comments without message text', () => {
+          element._messageText = '';
+          element._handleDiscard(mockEvent);
+          assert.isFalse(overlayStub.called);
+          assert.isTrue(discardStub.calledOnce);
+        });
+      });
+
+      test('ctrl+s saves comment', done => {
+        const stub = sinon.stub(element, 'save', () => {
+          assert.isTrue(stub.called);
+          stub.restore();
+          done();
+          return Promise.resolve();
+        });
+        element._messageText = 'is that the horse from horsing around??';
+        element.editing = true;
+        flushAsynchronousOperations();
+        MockInteractions.pressAndReleaseKeyOn(
+            element.textarea.$.textarea.textarea,
+            83, 'ctrl'); // 'ctrl + s'
+      });
+
+      test('draft saving/editing', done => {
+        const fireStub = sinon.stub(element, 'fire');
+        const cancelDebounce = sandbox.stub(element, 'cancelDebouncer');
+
+        element.draft = true;
+        MockInteractions.tap(element.$$('.edit'));
+        element._messageText = 'good news, everyone!';
+        element.flushDebouncer('fire-update');
+        element.flushDebouncer('store');
+        assert(fireStub.calledWith('comment-update'),
+            'comment-update should be sent');
+        assert.isTrue(fireStub.calledOnce);
+
+        element._messageText = 'good news, everyone!';
+        element.flushDebouncer('fire-update');
+        element.flushDebouncer('store');
+        assert.isTrue(fireStub.calledOnce,
+            'No events should fire for text editing');
+
         MockInteractions.tap(element.$$('.save'));
+
         assert.isTrue(element.disabled,
-            'Element should be disabled when updating draft.');
+            'Element should be disabled when creating draft.');
 
         element._xhrPromise.then(draft => {
+          assert(fireStub.calledWith('comment-save'),
+              'comment-save should be sent');
+          assert(cancelDebounce.calledWith('store'));
+
+          assert.deepEqual(fireStub.lastCall.args[1], {
+            comment: {
+              __commentSide: 'right',
+              __draft: true,
+              __draftID: 'temp_draft_id',
+              id: 'baf0414d_40572e03',
+              line: 5,
+              message: 'saved!',
+              path: '/path/to/file',
+              updated: '2015-12-08 21:52:36.177000000',
+            },
+            patchNum: 1,
+          });
           assert.isFalse(element.disabled,
-              'Element should be enabled when done updating draft.');
+              'Element should be enabled when done creating draft.');
           assert.equal(draft.message, 'saved!');
           assert.isFalse(element.editing);
-          fireStub.restore();
-          done();
+        }).then(() => {
+          MockInteractions.tap(element.$$('.edit'));
+          element._messageText = 'You’ll be delivering a package to Chapek 9, ' +
+              'a world where humans are killed on sight.';
+          MockInteractions.tap(element.$$('.save'));
+          assert.isTrue(element.disabled,
+              'Element should be disabled when updating draft.');
+
+          element._xhrPromise.then(draft => {
+            assert.isFalse(element.disabled,
+                'Element should be enabled when done updating draft.');
+            assert.equal(draft.message, 'saved!');
+            assert.isFalse(element.editing);
+            fireStub.restore();
+            done();
+          });
         });
       });
-    });
 
-    test('draft prevent save when disabled', () => {
-      const saveStub = sandbox.stub(element, 'save').returns(Promise.resolve());
-      element.showActions = true;
-      element.draft = true;
-      MockInteractions.tap(element.$.header);
-      MockInteractions.tap(element.$$('.edit'));
-      element._messageText = 'good news, everyone!';
-      element.flushDebouncer('fire-update');
-      element.flushDebouncer('store');
+      test('draft prevent save when disabled', () => {
+        const saveStub = sandbox.stub(element, 'save').returns(Promise.resolve());
+        element.showActions = true;
+        element.draft = true;
+        MockInteractions.tap(element.$.header);
+        MockInteractions.tap(element.$$('.edit'));
+        element._messageText = 'good news, everyone!';
+        element.flushDebouncer('fire-update');
+        element.flushDebouncer('store');
 
-      element.disabled = true;
-      MockInteractions.tap(element.$$('.save'));
-      assert.isFalse(saveStub.called);
+        element.disabled = true;
+        MockInteractions.tap(element.$$('.save'));
+        assert.isFalse(saveStub.called);
 
-      element.disabled = false;
-      MockInteractions.tap(element.$$('.save'));
-      assert.isTrue(saveStub.calledOnce);
-    });
+        element.disabled = false;
+        MockInteractions.tap(element.$$('.save'));
+        assert.isTrue(saveStub.calledOnce);
+      });
 
-    test('proper event fires on resolve, comment is not saved', done => {
-      const save = sandbox.stub(element, 'save');
-      element.addEventListener('comment-update', e => {
-        assert.isTrue(e.detail.comment.unresolved);
+      test('proper event fires on resolve, comment is not saved', done => {
+        const save = sandbox.stub(element, 'save');
+        element.addEventListener('comment-update', e => {
+          assert.isTrue(e.detail.comment.unresolved);
+          assert.isFalse(save.called);
+          done();
+        });
+        MockInteractions.tap(element.$$('.resolve input'));
+      });
+
+      test('resolved comment state indicated by checkbox', () => {
+        sandbox.stub(element, 'save');
+        element.comment = {unresolved: false};
+        assert.isTrue(element.$$('.resolve input').checked);
+        element.comment = {unresolved: true};
+        assert.isFalse(element.$$('.resolve input').checked);
+      });
+
+      test('resolved checkbox saves with tap when !editing', () => {
+        element.editing = false;
+        const save = sandbox.stub(element, 'save');
+
+        element.comment = {unresolved: false};
+        assert.isTrue(element.$$('.resolve input').checked);
+        element.comment = {unresolved: true};
+        assert.isFalse(element.$$('.resolve input').checked);
         assert.isFalse(save.called);
-        done();
-      });
-      MockInteractions.tap(element.$$('.resolve input'));
-    });
-
-    test('resolved comment state indicated by checkbox', () => {
-      sandbox.stub(element, 'save');
-      element.comment = {unresolved: false};
-      assert.isTrue(element.$$('.resolve input').checked);
-      element.comment = {unresolved: true};
-      assert.isFalse(element.$$('.resolve input').checked);
-    });
-
-    test('resolved checkbox saves with tap when !editing', () => {
-      element.editing = false;
-      const save = sandbox.stub(element, 'save');
-
-      element.comment = {unresolved: false};
-      assert.isTrue(element.$$('.resolve input').checked);
-      element.comment = {unresolved: true};
-      assert.isFalse(element.$$('.resolve input').checked);
-      assert.isFalse(save.called);
-      MockInteractions.tap(element.$.resolvedCheckbox);
-      assert.isTrue(element.$$('.resolve input').checked);
-      assert.isTrue(save.called);
-    });
-
-    suite('draft saving messages', () => {
-      test('_getSavingMessage', () => {
-        assert.equal(element._getSavingMessage(0), 'All changes saved');
-        assert.equal(element._getSavingMessage(1), 'Saving 1 draft...');
-        assert.equal(element._getSavingMessage(2), 'Saving 2 drafts...');
-        assert.equal(element._getSavingMessage(3), 'Saving 3 drafts...');
+        MockInteractions.tap(element.$.resolvedCheckbox);
+        assert.isTrue(element.$$('.resolve input').checked);
+        assert.isTrue(save.called);
       });
 
-      test('_show{Start,End}Request', () => {
-        const updateStub = sandbox.stub(element, '_updateRequestToast');
-        element._numPendingDraftRequests.number = 1;
+      suite('draft saving messages', () => {
+        test('_getSavingMessage', () => {
+          assert.equal(element._getSavingMessage(0), 'All changes saved');
+          assert.equal(element._getSavingMessage(1), 'Saving 1 draft...');
+          assert.equal(element._getSavingMessage(2), 'Saving 2 drafts...');
+          assert.equal(element._getSavingMessage(3), 'Saving 3 drafts...');
+        });
 
-        element._showStartRequest();
-        assert.isTrue(updateStub.calledOnce);
-        assert.equal(updateStub.lastCall.args[0], 2);
-        assert.equal(element._numPendingDraftRequests.number, 2);
+        test('_show{Start,End}Request', () => {
+          const updateStub = sandbox.stub(element, '_updateRequestToast');
+          element._numPendingDraftRequests.number = 1;
 
-        element._showEndRequest();
-        assert.isTrue(updateStub.calledTwice);
-        assert.equal(updateStub.lastCall.args[0], 1);
-        assert.equal(element._numPendingDraftRequests.number, 1);
+          element._showStartRequest();
+          assert.isTrue(updateStub.calledOnce);
+          assert.equal(updateStub.lastCall.args[0], 2);
+          assert.equal(element._numPendingDraftRequests.number, 2);
 
-        element._showEndRequest();
-        assert.isTrue(updateStub.calledThrice);
-        assert.equal(updateStub.lastCall.args[0], 0);
-        assert.equal(element._numPendingDraftRequests.number, 0);
+          element._showEndRequest();
+          assert.isTrue(updateStub.calledTwice);
+          assert.equal(updateStub.lastCall.args[0], 1);
+          assert.equal(element._numPendingDraftRequests.number, 1);
+
+          element._showEndRequest();
+          assert.isTrue(updateStub.calledThrice);
+          assert.equal(updateStub.lastCall.args[0], 0);
+          assert.equal(element._numPendingDraftRequests.number, 0);
+        });
       });
-    });
 
-    test('cancelling an unsaved draft discards, persists in storage', () => {
-      const discardSpy = sandbox.spy(element, '_fireDiscard');
-      const storeStub = sandbox.stub(element.$.storage, 'setDraftComment');
-      const eraseStub = sandbox.stub(element.$.storage, 'eraseDraftComment');
-      element._messageText = 'test text';
-      flushAsynchronousOperations();
-      element.flushDebouncer('store');
+      test('cancelling an unsaved draft discards, persists in storage', () => {
+        const discardSpy = sandbox.spy(element, '_fireDiscard');
+        const storeStub = sandbox.stub(element.$.storage, 'setDraftComment');
+        const eraseStub = sandbox.stub(element.$.storage, 'eraseDraftComment');
+        element._messageText = 'test text';
+        flushAsynchronousOperations();
+        element.flushDebouncer('store');
 
-      assert.isTrue(storeStub.called);
-      assert.equal(storeStub.lastCall.args[1], 'test text');
-      element._handleCancel({preventDefault: () => {}});
-      assert.isTrue(discardSpy.called);
-      assert.isFalse(eraseStub.called);
-    });
-
-    test('cancelling edit on a saved draft does not store', () => {
-      element.comment.id = 'foo';
-      const discardSpy = sandbox.spy(element, '_fireDiscard');
-      const storeStub = sandbox.stub(element.$.storage, 'setDraftComment');
-      element._messageText = 'test text';
-      flushAsynchronousOperations();
-      element.flushDebouncer('store');
-
-      assert.isFalse(storeStub.called);
-      element._handleCancel({preventDefault: () => {}});
-      assert.isTrue(discardSpy.called);
-    });
-
-    test('deleting text from saved draft and saving deletes the draft', () => {
-      element.comment = {id: 'foo', message: 'test'};
-      element._messageText = '';
-      const discardStub = sandbox.stub(element, '_discardDraft');
-
-      element.save();
-      assert.isTrue(discardStub.called);
-    });
-
-    test('_handleFix fires create-fix event', done => {
-      element.addEventListener('create-fix-comment', e => {
-        assert.deepEqual(e.detail, element._getEventPayload());
-        done();
+        assert.isTrue(storeStub.called);
+        assert.equal(storeStub.lastCall.args[1], 'test text');
+        element._handleCancel({preventDefault: () => {}});
+        assert.isTrue(discardSpy.called);
+        assert.isFalse(eraseStub.called);
       });
-      element.isRobotComment = true;
-      element.comments = [element.comment];
-      flushAsynchronousOperations();
 
-      MockInteractions.tap(element.$$('.fix'));
-    });
+      test('cancelling edit on a saved draft does not store', () => {
+        element.comment.id = 'foo';
+        const discardSpy = sandbox.spy(element, '_fireDiscard');
+        const storeStub = sandbox.stub(element.$.storage, 'setDraftComment');
+        element._messageText = 'test text';
+        flushAsynchronousOperations();
+        element.flushDebouncer('store');
 
-    test('do not show Please Fix button if human reply exists', () => {
-      element.comments = [
-        {
-          robot_id: 'happy_robot_id',
-          robot_run_id: '5838406743490560',
-          fix_suggestions: [
-            {
-              fix_id: '478ff847_3bf47aaf',
-              description: 'Make the smiley happier by giving it a nose.',
-              replacements: [
-                {
-                  path: 'Documentation/config-gerrit.txt',
-                  range: {
-                    start_line: 10,
-                    start_character: 7,
-                    end_line: 10,
-                    end_character: 9,
+        assert.isFalse(storeStub.called);
+        element._handleCancel({preventDefault: () => {}});
+        assert.isTrue(discardSpy.called);
+      });
+
+      test('deleting text from saved draft and saving deletes the draft', () => {
+        element.comment = {id: 'foo', message: 'test'};
+        element._messageText = '';
+        const discardStub = sandbox.stub(element, '_discardDraft');
+
+        element.save();
+        assert.isTrue(discardStub.called);
+      });
+
+      test('_handleFix fires create-fix event', done => {
+        element.addEventListener('create-fix-comment', e => {
+          assert.deepEqual(e.detail, element._getEventPayload());
+          done();
+        });
+        element.isRobotComment = true;
+        element.comments = [element.comment];
+        flushAsynchronousOperations();
+
+        MockInteractions.tap(element.$$('.fix'));
+      });
+
+      test('do not show Please Fix button if human reply exists', () => {
+        element.comments = [
+          {
+            robot_id: 'happy_robot_id',
+            robot_run_id: '5838406743490560',
+            fix_suggestions: [
+              {
+                fix_id: '478ff847_3bf47aaf',
+                description: 'Make the smiley happier by giving it a nose.',
+                replacements: [
+                  {
+                    path: 'Documentation/config-gerrit.txt',
+                    range: {
+                      start_line: 10,
+                      start_character: 7,
+                      end_line: 10,
+                      end_character: 9,
+                    },
+                    replacement: ':-)',
                   },
-                  replacement: ':-)',
+                ],
+              },
+            ],
+            author: {
+              _account_id: 1030912,
+              name: 'Alice Kober-Sotzek',
+              email: 'aliceks@google.com',
+              avatars: [
+                {
+                  url: '/s32-p/photo.jpg',
+                  height: 32,
+                },
+                {
+                  url: '/AaAdOFzPlFI/s56-p/photo.jpg',
+                  height: 56,
+                },
+                {
+                  url: '/AaAdOFzPlFI/s100-p/photo.jpg',
+                  height: 100,
+                },
+                {
+                  url: '/AaAdOFzPlFI/s120-p/photo.jpg',
+                  height: 120,
                 },
               ],
             },
-          ],
-          author: {
-            _account_id: 1030912,
-            name: 'Alice Kober-Sotzek',
-            email: 'aliceks@google.com',
-            avatars: [
+            patch_set: 1,
+            id: 'eb0d03fd_5e95904f',
+            line: 10,
+            updated: '2017-04-04 15:36:17.000000000',
+            message: 'This is a robot comment with a fix.',
+            unresolved: false,
+            __commentSide: 'right',
+            collapsed: false,
+          },
+          {
+            __draft: true,
+            __draftID: '0.wbrfbwj89sa',
+            __date: '2019-12-04T13:41:03.689Z',
+            path: 'Documentation/config-gerrit.txt',
+            patchNum: 1,
+            side: 'REVISION',
+            __commentSide: 'right',
+            line: 10,
+            in_reply_to: 'eb0d03fd_5e95904f',
+            message: '> This is a robot comment with a fix.\n\nPlease fix.',
+            unresolved: true,
+          },
+        ];
+        element.comment = element.comments[0];
+        flushAsynchronousOperations();
+        assert.isNull(element.$$('robotActions gr-button'));
+      });
+
+      test('show Please Fix if no human reply', () => {
+        element.comments = [
+          {
+            robot_id: 'happy_robot_id',
+            robot_run_id: '5838406743490560',
+            fix_suggestions: [
               {
-                url: '/s32-p/photo.jpg',
-                height: 32,
-              },
-              {
-                url: '/AaAdOFzPlFI/s56-p/photo.jpg',
-                height: 56,
-              },
-              {
-                url: '/AaAdOFzPlFI/s100-p/photo.jpg',
-                height: 100,
-              },
-              {
-                url: '/AaAdOFzPlFI/s120-p/photo.jpg',
-                height: 120,
+                fix_id: '478ff847_3bf47aaf',
+                description: 'Make the smiley happier by giving it a nose.',
+                replacements: [
+                  {
+                    path: 'Documentation/config-gerrit.txt',
+                    range: {
+                      start_line: 10,
+                      start_character: 7,
+                      end_line: 10,
+                      end_character: 9,
+                    },
+                    replacement: ':-)',
+                  },
+                ],
               },
             ],
-          },
-          patch_set: 1,
-          id: 'eb0d03fd_5e95904f',
-          line: 10,
-          updated: '2017-04-04 15:36:17.000000000',
-          message: 'This is a robot comment with a fix.',
-          unresolved: false,
-          __commentSide: 'right',
-          collapsed: false,
-        },
-        {
-          __draft: true,
-          __draftID: '0.wbrfbwj89sa',
-          __date: '2019-12-04T13:41:03.689Z',
-          path: 'Documentation/config-gerrit.txt',
-          patchNum: 1,
-          side: 'REVISION',
-          __commentSide: 'right',
-          line: 10,
-          in_reply_to: 'eb0d03fd_5e95904f',
-          message: '> This is a robot comment with a fix.\n\nPlease fix.',
-          unresolved: true,
-        },
-      ];
-      element.comment = element.comments[0];
-      flushAsynchronousOperations();
-      assert.isNull(element.$$('robotActions gr-button'));
-    });
-
-    test('show Please Fix if no human reply', () => {
-      element.comments = [
-        {
-          robot_id: 'happy_robot_id',
-          robot_run_id: '5838406743490560',
-          fix_suggestions: [
-            {
-              fix_id: '478ff847_3bf47aaf',
-              description: 'Make the smiley happier by giving it a nose.',
-              replacements: [
+            author: {
+              _account_id: 1030912,
+              name: 'Alice Kober-Sotzek',
+              email: 'aliceks@google.com',
+              avatars: [
                 {
-                  path: 'Documentation/config-gerrit.txt',
-                  range: {
-                    start_line: 10,
-                    start_character: 7,
-                    end_line: 10,
-                    end_character: 9,
-                  },
-                  replacement: ':-)',
+                  url: '/s32-p/photo.jpg',
+                  height: 32,
+                },
+                {
+                  url: '/AaAdOFzPlFI/s56-p/photo.jpg',
+                  height: 56,
+                },
+                {
+                  url: '/AaAdOFzPlFI/s100-p/photo.jpg',
+                  height: 100,
+                },
+                {
+                  url: '/AaAdOFzPlFI/s120-p/photo.jpg',
+                  height: 120,
                 },
               ],
             },
-          ],
-          author: {
-            _account_id: 1030912,
-            name: 'Alice Kober-Sotzek',
-            email: 'aliceks@google.com',
-            avatars: [
-              {
-                url: '/s32-p/photo.jpg',
-                height: 32,
-              },
-              {
-                url: '/AaAdOFzPlFI/s56-p/photo.jpg',
-                height: 56,
-              },
-              {
-                url: '/AaAdOFzPlFI/s100-p/photo.jpg',
-                height: 100,
-              },
-              {
-                url: '/AaAdOFzPlFI/s120-p/photo.jpg',
-                height: 120,
-              },
-            ],
+            patch_set: 1,
+            id: 'eb0d03fd_5e95904f',
+            line: 10,
+            updated: '2017-04-04 15:36:17.000000000',
+            message: 'This is a robot comment with a fix.',
+            unresolved: false,
+            __commentSide: 'right',
+            collapsed: false,
           },
-          patch_set: 1,
-          id: 'eb0d03fd_5e95904f',
-          line: 10,
-          updated: '2017-04-04 15:36:17.000000000',
-          message: 'This is a robot comment with a fix.',
-          unresolved: false,
-          __commentSide: 'right',
-          collapsed: false,
-        },
-      ];
-      element.comment = element.comments[0];
-      flushAsynchronousOperations();
-      assert.isNotNull(element.$$('.robotActions gr-button'));
-    });
-
-    test('_handleShowFix fires open-fix-preview event', done => {
-      element.addEventListener('open-fix-preview', e => {
-        assert.deepEqual(e.detail, element._getEventPayload());
-        done();
+        ];
+        element.comment = element.comments[0];
+        flushAsynchronousOperations();
+        assert.isNotNull(element.$$('.robotActions gr-button'));
       });
-      element.comment = {fix_suggestions: [{}]};
-      element.isRobotComment = true;
-      flushAsynchronousOperations();
 
-      MockInteractions.tap(element.$$('.show-fix'));
+      test('_handleShowFix fires open-fix-preview event', done => {
+        element.addEventListener('open-fix-preview', e => {
+          assert.deepEqual(e.detail, element._getEventPayload());
+          done();
+        });
+        element.comment = {fix_suggestions: [{}]};
+        element.isRobotComment = true;
+        flushAsynchronousOperations();
+
+        MockInteractions.tap(element.$$('.show-fix'));
+      });
     });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_test.html b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_test.html
index 14490f0..677a952 100644
--- a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-copy-clipboard.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-copy-clipboard tests', () => {
+  suite('gr-copy-clipboard tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/shared/gr-count-string-formatter/gr-count-string-formatter_test.html b/polygerrit-ui/app/elements/shared/gr-count-string-formatter/gr-count-string-formatter_test.html
index 5022766..64dff6a 100644
--- a/polygerrit-ui/app/elements/shared/gr-count-string-formatter/gr-count-string-formatter_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-count-string-formatter/gr-count-string-formatter_test.html
@@ -23,11 +23,13 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-count-string-formatter.html"/>
 
 <script>
-  suite('gr-count-string-formatter tests', () => {
+  suite('gr-count-string-formatter tests', async () => {
+    await readyToTest();
     test('computeString', () => {
       const noun = 'unresolved';
       assert.equal(GrCountStringFormatter.computeString(0, noun), '');
diff --git a/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager_test.html b/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager_test.html
index 103b41a..e7d5d74 100644
--- a/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-cursor-manager.html">
 
@@ -41,7 +42,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-cursor-manager tests', () => {
+  suite('gr-cursor-manager tests', async () => {
+    await readyToTest();
     let sandbox;
     let element;
     let list;
diff --git a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.html b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.html
index d2f7489..93e693c 100644
--- a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="../../../scripts/util.js"></script>
 
@@ -37,7 +38,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-date-formatter tests', () => {
+  suite('gr-date-formatter tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog_test.html b/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog_test.html
index ced925e..13553ba 100644
--- a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-dialog.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-dialog tests', () => {
+  suite('gr-dialog tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences_test.html b/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences_test.html
index fa1ade5..3c2a7d1 100644
--- a/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-diff-preferences.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-diff-preferences tests', () => {
+  suite('gr-diff-preferences tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
     let diffPreferences;
diff --git a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_test.html b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_test.html
index 4d2bda7..a298680 100644
--- a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-download-commands.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-download-commands', () => {
+  suite('gr-download-commands', async () => {
+    await readyToTest();
     let element;
     let sandbox;
     const SCHEMES = ['http', 'repo', 'ssh'];
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list_test.html b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list_test.html
index 8d098df..0a14127 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-dropdown-list.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-dropdown-list tests', () => {
+  suite('gr-dropdown-list tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.html b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.html
index 4b5ccb4..5c6d06f 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-dropdown.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-dropdown tests', () => {
+  suite('gr-dropdown tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.js b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.js
index 7d3308e..5145f50 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.js
+++ b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.js
@@ -90,13 +90,34 @@
         if (newContent.length) {
           this.$.storage.setEditableContentItem(this.storageKey, newContent);
         } else {
+          // This does not really happen, because we don't clear newContent
+          // after saving (see below). So this only occurs when the user clears
+          // all the content in the editable textarea. But <gr-storage> cleans
+          // up itself after one day, so we are not so concerned about leaving
+          // some garbage behind.
           this.$.storage.eraseEditableContentItem(this.storageKey);
         }
       }, STORAGE_DEBOUNCE_INTERVAL_MS);
     }
 
     _editingChanged(editing) {
-      if (!editing) { return; }
+      // This method is for initializing _newContent when you start editing.
+      // Restoring content from local storage is not perfect and has
+      // some issues:
+      //
+      // 1. When you start editing in multiple tabs, then we are vulnerable to
+      // race conditions between the tabs.
+      // 2. The stored content is keyed by revision, so when you upload a new
+      // patchset and click "reload" and then click "cancel" on the content-
+      // editable, then you won't be able to recover the content anymore.
+      //
+      // Because of these issues we believe that it is better to only recover
+      // content from local storage when you enter editing mode for the first
+      // time. Otherwise it is better to just keep the last editing state from
+      // the same session.
+      if (!editing || this._newContent) {
+        return;
+      }
 
       let content;
       if (this.storageKey) {
@@ -122,21 +143,15 @@
     }
 
     _computeSaveDisabled(disabled, content, newContent) {
-      // Polymer 2: check for undefined
-      if ([
-        disabled,
-        content,
-        newContent,
-      ].some(arg => arg === undefined)) {
-        return true;
-      }
-
-      return disabled || (content === newContent);
+      return disabled || !newContent || content === newContent;
     }
 
     _handleSave(e) {
       e.preventDefault();
       this.fire('editable-content-save', {content: this._newContent});
+      // It would be nice, if we would set this._newContent = undefined here,
+      // but we can only do that when we are sure that the save operation has
+      // succeeded.
     }
 
     _handleCancel(e) {
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_test.html b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_test.html
index 69c9a00..671cb06 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="/bower_components/iron-test-helpers/mock-interactions.js"></script>
 
@@ -37,7 +38,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-editable-content tests', () => {
+  suite('gr-editable-content tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
@@ -65,11 +67,11 @@
       MockInteractions.tap(element.$$('gr-button:not([primary])'));
     });
 
-    test('enabling editing updates edit field contents', () => {
+    test('enabling editing keeps old content', () => {
       element.content = 'current content';
-      element._newContent = 'stale content';
+      element._newContent = 'old content';
       element.editing = true;
-      assert.equal(element._newContent, 'current content');
+      assert.equal(element._newContent, 'old content');
     });
 
     test('disabling editing does not update edit field contents', () => {
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.html b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.html
index 917e4b6..8d0d1c37 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.html
+++ b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.html
@@ -17,6 +17,7 @@
 <link rel="import" href="/bower_components/polymer/polymer.html">
 
 <link rel="import" href="../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html">
+<link rel="import" href="/bower_components/iron-overlay-behavior/iron-overlay-behavior.html">
 <link rel="import" href="/bower_components/iron-dropdown/iron-dropdown.html">
 <link rel="import" href="/bower_components/paper-input/paper-input.html">
 <link rel="import" href="../../../behaviors/fire-behavior/fire-behavior.html">
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.html b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.html
index 1690c3a..304b6c4 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="/bower_components/iron-test-helpers/mock-interactions.js"></script>
 
@@ -54,7 +55,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-editable-label tests', () => {
+  suite('gr-editable-label tests', async () => {
+    await readyToTest();
     let element;
     let elementNoPlaceholder;
     let input;
@@ -217,30 +219,30 @@
       // Press escape:
       MockInteractions.tap(element.$.cancelBtn);
     });
-  });
 
-  suite('gr-editable-label read-only tests', () => {
-    let element;
-    let label;
+    suite('gr-editable-label read-only tests', () => {
+      let element;
+      let label;
 
-    setup(() => {
-      element = fixture('read-only');
-      label = element.$$('label');
-    });
+      setup(() => {
+        element = fixture('read-only');
+        label = element.$$('label');
+      });
 
-    test('disallows edit when read-only', () => {
-      // The dropdown is closed.
-      assert.isFalse(element.$.dropdown.opened);
-      MockInteractions.tap(label);
+      test('disallows edit when read-only', () => {
+        // The dropdown is closed.
+        assert.isFalse(element.$.dropdown.opened);
+        MockInteractions.tap(label);
 
-      Polymer.dom.flush();
+        Polymer.dom.flush();
 
-      // The dropdown is still closed.
-      assert.isFalse(element.$.dropdown.opened);
-    });
+        // The dropdown is still closed.
+        assert.isFalse(element.$.dropdown.opened);
+      });
 
-    test('label is not marked as editable', () => {
-      assert.isFalse(label.classList.contains('editable'));
+      test('label is not marked as editable', () => {
+        assert.isFalse(label.classList.contains('editable'));
+      });
     });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/shared/gr-event-interface/gr-event-interface_test.html b/polygerrit-ui/app/elements/shared/gr-event-interface/gr-event-interface_test.html
index 4509dfe..6e62b15 100644
--- a/polygerrit-ui/app/elements/shared/gr-event-interface/gr-event-interface_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-event-interface/gr-event-interface_test.html
@@ -21,6 +21,7 @@
 
 <script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
 <script src="../../../bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="../gr-js-api-interface/gr-js-api-interface.html">
 
@@ -33,7 +34,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-event-interface tests', () => {
+  suite('gr-event-interface tests', async () => {
+    await readyToTest();
     let sandbox;
 
     setup(() => {
diff --git a/polygerrit-ui/app/elements/shared/gr-fixed-panel/gr-fixed-panel_test.html b/polygerrit-ui/app/elements/shared/gr-fixed-panel/gr-fixed-panel_test.html
index 419b3e7..7ae0265 100644
--- a/polygerrit-ui/app/elements/shared/gr-fixed-panel/gr-fixed-panel_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-fixed-panel/gr-fixed-panel_test.html
@@ -23,8 +23,17 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-fixed-panel.html">
+<style>
+  /* Prevent horizontal scrolling on page.
+   New version of web-component-tester creates body with margins */
+  body {
+    margin: 0px;
+    padding: 0px;
+  }
+</style>
 
 <script>void(0);</script>
 
@@ -37,7 +46,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-fixed-panel', () => {
+  suite('gr-fixed-panel', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.html b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.html
index 92fbc74..1f0d26d 100644
--- a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-formatted-text.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-formatted-text tests', () => {
+  suite('gr-formatted-text tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard_test.html b/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard_test.html
index 35d736c..3c04853 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="/bower_components/iron-test-helpers/mock-interactions.js"></script>
 
@@ -38,7 +39,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-hovercard tests', () => {
+  suite('gr-hovercard tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
     // For css animations
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context_test.html
index 66e7a74..719cf3c 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context_test.html
@@ -25,6 +25,7 @@
 <script src="/bower_components/web-component-tester/browser.js"></script>
 <script src="../../diff/gr-diff-highlight/gr-annotation.js"></script>
 
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-js-api-interface.html"/>
 
@@ -37,7 +38,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-annotation-actions-context tests', () => {
+  suite('gr-annotation-actions-context tests', async () => {
+    await readyToTest();
     let instance;
     let sandbox;
     let el;
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api_test.html
index 98ff954..0486965 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="../../change/gr-change-actions/gr-change-actions.html">
 
@@ -38,7 +39,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-annotation-actions-js-api tests', () => {
+  suite('gr-annotation-actions-js-api tests', async () => {
+    await readyToTest();
     let annotationActions;
     let sandbox;
     let plugin;
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-api-utils_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-api-utils_test.html
index b43796f..d70a8d2 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-api-utils_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-api-utils_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-js-api-interface.html">
 
@@ -31,7 +32,8 @@
 <script>
   const PRELOADED_PROTOCOL = 'preloaded:';
 
-  suite('gr-api-utils tests', () => {
+  suite('gr-api-utils tests', async () => {
+    await readyToTest();
     suite('test getPluginNameFromUrl', () => {
       const {getPluginNameFromUrl} = window._apiUtils;
 
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.html
index cbe2d37..fa39cb0 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <!--
 This must refer to the element this interface is wrapping around. Otherwise
@@ -39,7 +40,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-js-api-interface tests', () => {
+  suite('gr-js-api-interface tests', async () => {
+    await readyToTest();
     let element;
     let changeActions;
     let plugin;
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api_test.html
index 7955aa4..3147746 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <!--
 This must refer to the element this interface is wrapping around. Otherwise
@@ -39,7 +40,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-change-reply-js-api tests', () => {
+  suite('gr-change-reply-js-api tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
     let changeReply;
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit_test.html
index a316fd5..ee95a5e 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-js-api-interface.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-gerrit tests', () => {
+  suite('gr-gerrit tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
     let sendStub;
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html
index 323a730..3a03c72 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-js-api-interface.html">
 
@@ -35,8 +36,9 @@
 </test-fixture>
 
 <script>
-  const {PLUGIN_LOADING_TIMEOUT_MS} = window._apiUtils;
-  suite('gr-js-api-interface tests', () => {
+  suite('gr-js-api-interface tests', async () => {
+    await readyToTest();
+    const {PLUGIN_LOADING_TIMEOUT_MS} = window._apiUtils;
     let element;
     let plugin;
     let errorStub;
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context_test.html
index ca43fc0..c8fb9b1 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-js-api-interface.html"/>
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-plugin-action-context tests', () => {
+  suite('gr-plugin-action-context tests', async () => {
+    await readyToTest();
     let instance;
     let sandbox;
     let plugin;
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.html
index b39ed6d..5c0d69a 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.html
@@ -23,13 +23,15 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-js-api-interface.html"/>
 
 <script>void(0);</script>
 
 <script>
-  suite('gr-plugin-endpoints tests', () => {
+  suite('gr-plugin-endpoints tests', async () => {
+    await readyToTest();
     let sandbox;
     let instance;
     let pluginFoo;
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader_test.html
index 85c23dd..1a9174f 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-js-api-interface.html">
 
@@ -35,8 +36,9 @@
 </test-fixture>
 
 <script>
-  const {PRELOADED_PROTOCOL, PLUGIN_LOADING_TIMEOUT_MS} = window._apiUtils;
-  suite('gr-plugin-loader tests', () => {
+  suite('gr-plugin-loader tests', async () => {
+    await readyToTest();
+    const {PRELOADED_PROTOCOL, PLUGIN_LOADING_TIMEOUT_MS} = window._apiUtils;
     let plugin;
     let sandbox;
     let url;
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-rest-api_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-rest-api_test.html
index 6fb0b19..049e8d5 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-rest-api_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-rest-api_test.html
@@ -23,11 +23,13 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-js-api-interface.html"/>
 
 <script>
-  suite('gr-plugin-rest-api tests', () => {
+  suite('gr-plugin-rest-api tests', async () => {
+    await readyToTest();
     let instance;
     let sandbox;
     let getResponseObjectStub;
diff --git a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_test.html b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_test.html
index adf88d9..c234b13 100644
--- a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_test.html
@@ -22,6 +22,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-label-info.html">
 
@@ -34,7 +35,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-account-link tests', () => {
+  suite('gr-account-link tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/shared/gr-labeled-autocomplete/gr-labeled-autocomplete_test.html b/polygerrit-ui/app/elements/shared/gr-labeled-autocomplete/gr-labeled-autocomplete_test.html
index 7e8f73f..e79e741 100644
--- a/polygerrit-ui/app/elements/shared/gr-labeled-autocomplete/gr-labeled-autocomplete_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-labeled-autocomplete/gr-labeled-autocomplete_test.html
@@ -22,6 +22,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-labeled-autocomplete.html">
 
@@ -34,7 +35,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-labeled-autocomplete tests', () => {
+  suite('gr-labeled-autocomplete tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader_test.html b/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader_test.html
index 832a558..a1d9c0f 100644
--- a/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-lib-loader.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-lib-loader tests', () => {
+  suite('gr-lib-loader tests', async () => {
+    await readyToTest();
     let sandbox;
     let element;
     let resolveLoad;
diff --git a/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text_test.html b/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text_test.html
index 3ba30d1..c34a348 100644
--- a/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 
 <link rel="import" href="gr-limited-text.html">
@@ -36,7 +37,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-limited-text tests', () => {
+  suite('gr-limited-text tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip_test.html b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip_test.html
index 733e897..6eb93b4 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="/bower_components/iron-test-helpers/mock-interactions.js"></script>
 
@@ -37,7 +38,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-linked-chip tests', () => {
+  suite('gr-linked-chip tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text_test.html b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text_test.html
index b0186f0..2b2fcfc 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="../../../scripts/util.js"></script>
 
@@ -39,7 +40,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-linked-text tests', () => {
+  suite('gr-linked-text tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view_test.html b/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view_test.html
index b8f12ad..14350c8 100644
--- a/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view_test.html
@@ -24,6 +24,7 @@
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
 
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-list-view.html">
 
@@ -36,7 +37,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-list-view tests', () => {
+  suite('gr-list-view tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay_test.html b/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay_test.html
index 659823f..e1218af3 100644
--- a/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay_test.html
@@ -25,6 +25,7 @@
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
 
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 
 <link rel="import" href="gr-overlay.html">
@@ -40,7 +41,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-overlay tests', () => {
+  suite('gr-overlay tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav_test.html b/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav_test.html
index 663d3bd..fdfe46c 100644
--- a/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav_test.html
@@ -25,6 +25,7 @@
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
 
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 
 <link rel="import" href="gr-page-nav.html">
@@ -42,7 +43,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-page-nav tests', () => {
+  suite('gr-page-nav tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker_test.html b/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker_test.html
index 3bad2a9..b068b25 100644
--- a/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker_test.html
@@ -22,6 +22,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-repo-branch-picker.html">
 
@@ -34,7 +35,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-repo-branch-picker tests', () => {
+  suite('gr-repo-branch-picker tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-auth.js b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-auth.js
index 7648b7d..4f68e4b 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-auth.js
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-auth.js
@@ -16,6 +16,7 @@
  */
 (function(window) {
   'use strict';
+  window.Gerrit = window.Gerrit || {};
 
   // Prevent redefinition.
   if (window.Gerrit.Auth) { return; }
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-auth_test.html b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-auth_test.html
index cbaf49d..091c88e 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-auth_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-auth_test.html
@@ -23,13 +23,15 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="../../../behaviors/base-url-behavior/base-url-behavior.html">
 
 <script src="gr-auth.js"></script>
 
 <script>
-  suite('gr-auth', () => {
+  suite('gr-auth', async () => {
+    await readyToTest();
     let auth;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-etag-decorator_test.html b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-etag-decorator_test.html
index 623ea18..93b6a21 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-etag-decorator_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-etag-decorator_test.html
@@ -23,12 +23,14 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 
 <script src="gr-etag-decorator.js"></script>
 
 <script>
-  suite('gr-etag-decorator', () => {
+  suite('gr-etag-decorator', async () => {
+    await readyToTest();
     let etag;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
index f021bf0..2eb727c 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
@@ -1866,6 +1866,15 @@
       });
     }
 
+    deleteChangeCommitMessage(changeNum, messageId) {
+      return this._getChangeURLAndSend({
+        changeNum,
+        method: 'DELETE',
+        endpoint: '/messages/' + messageId,
+        reportEndpointAsIs: true,
+      });
+    }
+
     saveChangeStarred(changeNum, starred) {
       // Some servers may require the project name to be provided
       // alongside the change number, so resolve the project name
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html
index ed7d29f..1088f7e 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="../../../scripts/util.js"></script>
 
@@ -37,7 +38,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-rest-api-interface tests', () => {
+  suite('gr-rest-api-interface tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
     let ctr = 0;
@@ -714,6 +716,25 @@
       });
     });
 
+    test('deleteChangeCommitMessage', () => {
+      element._projectLookup = {1: 'test'};
+      const change_num = '1';
+      const messageId = 'abc';
+      sandbox.stub(element._restApiHelper, 'send').returns(
+          Promise.resolve([change_num, messageId]));
+      sandbox.stub(element, 'getResponseObject')
+          .returns(Promise.resolve([change_num, messageId]));
+      return element.deleteChangeCommitMessage(change_num, messageId).then(() => {
+        assert.isTrue(element._restApiHelper.send.calledOnce);
+        assert.equal(
+            element._restApiHelper.send.lastCall.args[0].method,
+            'DELETE'
+        );
+        assert.equal(element._restApiHelper.send.lastCall.args[0].url,
+            '/changes/test~1/messages/abc');
+      });
+    });
+
     test('startWorkInProgress', () => {
       const sendStub = sandbox.stub(element, '_getChangeURLAndSend')
           .returns(Promise.resolve('ok'));
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper_test.html b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper_test.html
index 6458104..310063c 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../../test/common-test-setup.html"/>
 <script src="../../../../scripts/util.js"></script>
 <script src="../gr-auth.js"></script>
@@ -31,7 +32,8 @@
 <script>void(0);</script>
 
 <script>
-  suite('gr-rest-api-helper tests', () => {
+  suite('gr-rest-api-helper tests', async () => {
+    await readyToTest();
     let helper;
     let sandbox;
     let cache;
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser_test.html b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser_test.html
index 593fcec..678e02a 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser_test.html
@@ -23,12 +23,14 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <script src="../../../scripts/util.js"></script>
 <script src="gr-reviewer-updates-parser.js"></script>
 
 <script>
-  suite('gr-reviewer-updates-parser tests', () => {
+  suite('gr-reviewer-updates-parser tests', async () => {
+    await readyToTest();
     let sandbox;
     let instance;
 
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/mock-diff-response_test.html b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/mock-diff-response_test.html
index 015d71e..df3b9a5 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/mock-diff-response_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/mock-diff-response_test.html
@@ -16,6 +16,7 @@
 -->
 
 <link rel="import" href="/bower_components/polymer/polymer.html">
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <dom-module id="mock-diff-response">
   <template></template>
diff --git a/polygerrit-ui/app/elements/shared/gr-select/gr-select_test.html b/polygerrit-ui/app/elements/shared/gr-select/gr-select_test.html
index cae61056..536f4f8 100644
--- a/polygerrit-ui/app/elements/shared/gr-select/gr-select_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-select/gr-select_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-select.html">
 
@@ -50,7 +51,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-select tests', () => {
+  suite('gr-select tests', async () => {
+    await readyToTest();
     let element;
 
     setup(() => {
@@ -102,17 +104,17 @@
       assert.equal(element.bindValue, '3');
       assert.isTrue(changeStub.called);
     });
-  });
 
-  suite('gr-select no options tests', () => {
-    let element;
+    suite('gr-select no options tests', () => {
+      let element;
 
-    setup(() => {
-      element = fixture('noOptions');
-    });
+      setup(() => {
+        element = fixture('noOptions');
+      });
 
-    test('bindValue must not be changed', () => {
-      assert.isUndefined(element.bindValue);
+      test('bindValue must not be changed', () => {
+        assert.isUndefined(element.bindValue);
+      });
     });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command_test.html b/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command_test.html
index a4bdf58..5fbbdf8 100644
--- a/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-shell-command.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-shell-command tests', () => {
+  suite('gr-shell-command tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/shared/gr-storage/gr-storage_test.html b/polygerrit-ui/app/elements/shared/gr-storage/gr-storage_test.html
index 5cd4d3e..66e7f98 100644
--- a/polygerrit-ui/app/elements/shared/gr-storage/gr-storage_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-storage/gr-storage_test.html
@@ -22,6 +22,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-storage.html">
 
@@ -34,7 +35,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-storage tests', () => {
+  suite('gr-storage tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
diff --git a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.html b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.html
index 699deab..674089d 100644
--- a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-textarea.html">
 
@@ -46,7 +47,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-textarea tests', () => {
+  suite('gr-textarea tests', async () => {
+    await readyToTest();
     let element;
     let sandbox;
 
@@ -323,53 +325,53 @@
         assert.isFalse(enterSpy.called);
       });
     });
-  });
 
-  suite('gr-textarea monospace', () => {
+    suite('gr-textarea monospace', () => {
     // gr-textarea set monospace class in the ready() method.
     // In Polymer2, ready() is called from the fixture(...) method,
     // If ready() is called again later, some nested elements doesn't
     // handle it correctly. A separate test-fixture is used to set
     // properties before ready() is called.
 
-    let element;
-    let sandbox;
+      let element;
+      let sandbox;
 
-    setup(() => {
-      sandbox = sinon.sandbox.create();
-      element = fixture('monospace');
+      setup(() => {
+        sandbox = sinon.sandbox.create();
+        element = fixture('monospace');
+      });
+
+      teardown(() => {
+        sandbox.restore();
+      });
+
+      test('monospace is set properly', () => {
+        assert.isTrue(element.classList.contains('monospace'));
+      });
     });
 
-    teardown(() => {
-      sandbox.restore();
-    });
-
-    test('monospace is set properly', () => {
-      assert.isTrue(element.classList.contains('monospace'));
-    });
-  });
-
-  suite('gr-textarea hideBorder', () => {
+    suite('gr-textarea hideBorder', () => {
     // gr-textarea set noBorder class in the ready() method.
     // In Polymer2, ready() is called from the fixture(...) method,
     // If ready() is called again later, some nested elements doesn't
     // handle it correctly. A separate test-fixture is used to set
     // properties before ready() is called.
 
-    let element;
-    let sandbox;
+      let element;
+      let sandbox;
 
-    setup(() => {
-      sandbox = sinon.sandbox.create();
-      element = fixture('hideBorder');
-    });
+      setup(() => {
+        sandbox = sinon.sandbox.create();
+        element = fixture('hideBorder');
+      });
 
-    teardown(() => {
-      sandbox.restore();
-    });
+      teardown(() => {
+        sandbox.restore();
+      });
 
-    test('hideBorder is set properly', () => {
-      assert.isTrue(element.$.textarea.classList.contains('noBorder'));
+      test('hideBorder is set properly', () => {
+        assert.isTrue(element.$.textarea.classList.contains('noBorder'));
+      });
     });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content_test.html b/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content_test.html
index 7098d7c..8237552 100644
--- a/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content_test.html
@@ -22,6 +22,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-tooltip-content.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-tooltip-content tests', () => {
+  suite('gr-tooltip-content tests', async () => {
+    await readyToTest();
     let element;
     setup(() => {
       element = fixture('basic');
diff --git a/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip_test.html b/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip_test.html
index 95f3922..07dc57f 100644
--- a/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip_test.html
@@ -22,6 +22,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="gr-tooltip.html">
 
@@ -35,7 +36,8 @@
 </test-fixture>
 
 <script>
-  suite('gr-tooltip tests', () => {
+  suite('gr-tooltip tests', async () => {
+    await readyToTest();
     let element;
     setup(() => {
       element = fixture('basic');
diff --git a/polygerrit-ui/app/elements/shared/revision-info/revision-info_test.html b/polygerrit-ui/app/elements/shared/revision-info/revision-info_test.html
index 187ce35..fb7a011 100644
--- a/polygerrit-ui/app/elements/shared/revision-info/revision-info_test.html
+++ b/polygerrit-ui/app/elements/shared/revision-info/revision-info_test.html
@@ -23,11 +23,13 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="revision-info.html">
 
 <script>
-  suite('revision-info tests', () => {
+  suite('revision-info tests', async () => {
+    await readyToTest();
     let mockChange;
 
     setup(() => {
diff --git a/polygerrit-ui/app/lint_test.sh b/polygerrit-ui/app/lint_test.sh
index 4e7d8c9..637ea93 100755
--- a/polygerrit-ui/app/lint_test.sh
+++ b/polygerrit-ui/app/lint_test.sh
@@ -37,4 +37,4 @@
 # eslint installation.
 npm link eslint eslint-config-google eslint-plugin-html eslint-plugin-jsdoc
 
-${eslint_bin} -c ${UI_PATH}/.eslintrc.json --ignore-pattern 'node_modules/' --ignore-pattern 'bower_components/' --ignore-pattern 'scripts/vendor' --ext .html,.js ${UI_PATH}
+${eslint_bin} -c ${UI_PATH}/.eslintrc.json --ignore-pattern 'rollup.config.js' --ignore-pattern 'elements/font-roboto-local-loader.js' --ignore-pattern 'node_modules/' --ignore-pattern 'bower_components/' --ignore-pattern 'scripts/vendor' --ext .html,.js ${UI_PATH}
diff --git a/polygerrit-ui/app/node_modules_licenses/.gitignore b/polygerrit-ui/app/node_modules_licenses/.gitignore
new file mode 100644
index 0000000..6a3417b
--- /dev/null
+++ b/polygerrit-ui/app/node_modules_licenses/.gitignore
@@ -0,0 +1 @@
+/out/
diff --git a/polygerrit-ui/app/node_modules_licenses/BUILD b/polygerrit-ui/app/node_modules_licenses/BUILD
new file mode 100644
index 0000000..d2f24b9
--- /dev/null
+++ b/polygerrit-ui/app/node_modules_licenses/BUILD
@@ -0,0 +1,61 @@
+load("@npm_bazel_typescript//:index.bzl", "ts_config", "ts_library")
+load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary", "npm_package_bin")
+load("//tools/node_tools/node_modules_licenses:node_modules_licenses.bzl", "node_modules_licenses")
+
+filegroup(
+    name = "licenses-texts",
+    srcs = glob(["licenses/*.txt"]),
+)
+
+ts_library(
+    name = "licenses-config",
+    srcs = [
+        "licenses.ts",
+    ],
+    compiler = "//tools/node_tools:tsc_wrapped-bin",
+    node_modules = "@tools_npm//:node_modules",
+    tsconfig = "tsconfig.json",
+    deps = [
+        "//tools/node_tools/node_modules_licenses:licenses-map",
+        "@tools_npm//@types/node",
+    ],
+)
+
+# (TODO)dmfilippov Find a better way to fix it (another workaround or submit a bug to
+# plugin's authors or to a ts_config rule author).
+# The following genrule is a workaround for a bazel intellij plugin's bug.
+# According to the documentation, the ts_config_rules section should be added
+# to a .bazelproject file if a project uses typescript
+# (https://ij.bazel.build/docs/dynamic-languages-typescript.html)
+# Unfortunately, this doesn't work. It seems, that the plugin expects some output from
+# the ts_config rule, but the rule doesn't produce any output.
+# To workaround the issue, the tsconfig_editor genrule was added. The genrule only copies
+# input file to the output file, but this is enough to make bazel plugins works.
+# So, if you have any problem a typescript editor (import errors, types not found, etc...) -
+# try to build this rule from the command line
+# (bazel build tools/node_tools/node_modules/licenses:tsconfig_editor) and then sync bazel project
+# in intellij.
+genrule(
+    name = "tsconfig_editor",
+    srcs = [":tsconfig.json"],
+    outs = ["tsconfig_editor.json"],
+    cmd = "cp $< $@",
+)
+
+# filegroup is enough (instead of rollup-bundle), because we are not going to run licenses.ts file
+filegroup(
+    name = "licenses-config-js",
+    srcs = [":licenses-config"],
+    output_group = "es5_sources",
+)
+
+# Generate polygerrit-licenses.json for files in @ui_npm workspace.
+# For details - see comments for node_modules_licenses rule and
+# tools/node_tools/node_modules_licenses/license-map-generator.ts file
+node_modules_licenses(
+    name = "polygerrit-licenses",
+    licenses_config = "licenses-config-js",
+    licenses_texts = [":licenses-texts"],
+    node_modules = "@ui_npm//:node_modules",
+    visibility = ["//visibility:public"],
+)
diff --git a/polygerrit-ui/app/node_modules_licenses/licenses.ts b/polygerrit-ui/app/node_modules_licenses/licenses.ts
new file mode 100644
index 0000000..fe07569
--- /dev/null
+++ b/polygerrit-ui/app/node_modules_licenses/licenses.ts
@@ -0,0 +1,313 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Ugly import path due to the following bugs:
+// https://github.com/bazelbuild/rules_nodejs/issues/1522
+// https://github.com/bazelbuild/rules_nodejs/issues/1380
+import {PackageInfo, LicenseType, LicenseInfo} from "../../../tools/node_tools/node_modules_licenses/package-license-info";
+import * as path from "path";
+
+class LicenseTypes {
+  public static Mit: LicenseType = {
+    name: "MIT",
+    allowed: true
+  };
+  public static Apache2_0: LicenseType = {
+    name: "Apache 2.0",
+    allowed: true
+  };
+
+  public static Bsd3: LicenseType = {
+    name: "BSD-3-Clause",
+    allowed: true
+  };
+}
+
+/** List of licenses texts. Add the licenses here if there is no text file with license
+ * in package. For details - see comments for {@link LicenseInfo} and {@link PackageInfo} */
+class SharedLicenses {
+  public static Polymer2014: LicenseInfo = {
+    name: "Polymer-2014",
+    type: LicenseTypes.Bsd3,
+    sharedLicenseFile: "polymer-2014.txt",
+  };
+
+  public static Polymer2015: LicenseInfo = {
+    name: "Polymer-2015",
+    type: LicenseTypes.Bsd3,
+    sharedLicenseFile: "polymer-2015.txt",
+  };
+
+  public static Polymer2017: LicenseInfo = {
+    name: "Polymer-2017",
+    type: LicenseTypes.Bsd3,
+    sharedLicenseFile: "polymer-2017.txt",
+  };
+
+  public static Polymer2018: LicenseInfo = {
+    name: "Polymer-2018",
+    type: LicenseTypes.Bsd3,
+    sharedLicenseFile: "polymer-2018.txt",
+  };
+
+  public static IsArray: LicenseInfo = {
+    name: "isarray",
+    type: LicenseTypes.Mit,
+    sharedLicenseFile: "isarray.txt"
+  };
+
+  public static Page: LicenseInfo = {
+    name: "page",
+    type: LicenseTypes.Mit,
+    sharedLicenseFile: "page.txt"
+  }
+}
+
+const fontsRobotoFilter = (fileName: string) =>
+    fileName.startsWith("fonts/roboto/") && path.basename(fileName) !== "DESCRIPTION.en_us.html";
+
+const fontsRobotomonoFilter = (fileName: string) =>
+    fileName.startsWith("fonts/robotomono/") && path.basename(fileName) !== "DESCRIPTION.en_us.html";
+
+
+const packages: PackageInfo[] = [
+  {
+    name: "@polymer/font-roboto",
+    license: SharedLicenses.Polymer2015,
+  },
+  {
+    name: "@polymer/font-roboto-local",
+    license: SharedLicenses.Polymer2015,
+    filesFilter: fileName => !fontsRobotoFilter(fileName) && !fontsRobotomonoFilter(fileName)
+  },
+  {
+    name: "@polymer/font-roboto-local",
+    license: {
+      name: "font-roboto-local-fonts-roboto",
+      type: LicenseTypes.Apache2_0,
+      packageLicenseFile: "fonts/roboto/LICENSE.txt"
+    },
+    filesFilter: fontsRobotoFilter
+  },
+  {
+    name: "@polymer/font-roboto-local",
+    license: {
+      name: "font-roboto-local-fonts-robotomono",
+      type: LicenseTypes.Apache2_0,
+      packageLicenseFile: "fonts/robotomono/LICENSE.txt"
+    },
+    filesFilter: fontsRobotomonoFilter
+  },
+  {
+    name: "@polymer/iron-a11y-announcer",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/iron-a11y-keys-behavior",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/iron-autogrow-textarea",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/iron-behaviors",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/iron-checked-element-behavior",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/iron-dropdown",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/iron-fit-behavior",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/iron-flex-layout",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/iron-form-element-behavior",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/iron-icon",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/iron-iconset-svg",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/iron-input",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/iron-menu-behavior",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/iron-meta",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/iron-overlay-behavior",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/iron-resizable-behavior",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/iron-selector",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/iron-validatable-behavior",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/neon-animation",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/paper-behaviors",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/paper-button",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/paper-dialog",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/paper-dialog-behavior",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/paper-dialog-scrollable",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/paper-icon-button",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/paper-input",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/paper-item",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/paper-listbox",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/paper-ripple",
+    license: SharedLicenses.Polymer2014
+  },
+  {
+    name: "@polymer/paper-styles",
+    license: SharedLicenses.Polymer2014
+  },
+  {
+    name: "@polymer/paper-tabs",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/paper-toggle-button",
+    license: SharedLicenses.Polymer2015
+  },
+  {
+    name: "@polymer/polymer",
+    license: SharedLicenses.Polymer2017
+  },
+  {
+    name: "@webcomponents/shadycss",
+    license: SharedLicenses.Polymer2017
+  },
+  {
+    name: "@webcomponents/webcomponentsjs",
+    license: SharedLicenses.Polymer2018
+  },
+  {
+    name: "ba-linkify",
+    license: {
+      name: "ba-linkify",
+      type: LicenseTypes.Mit,
+      packageLicenseFile: "LICENSE-MIT",
+    }
+  },
+  {
+    name: "es6-promise",
+    license: {
+      name: "es6-promise",
+      type: LicenseTypes.Mit,
+      packageLicenseFile: "LICENSE"
+    }
+  },
+  {
+    name: "isarray",
+    license: SharedLicenses.IsArray
+  },
+  {
+    name: "moment",
+    license: {
+      name: "moment",
+      type: LicenseTypes.Mit,
+      packageLicenseFile: "LICENSE"
+    }
+  },
+  {
+    name: "page",
+    license: SharedLicenses.Page
+  },
+  {
+    name: "path-to-regexp",
+    license: {
+      name: "path-to-regexp",
+      type: LicenseTypes.Mit,
+      packageLicenseFile: "LICENSE"
+    }
+  },
+  {
+    name: "polymer-resin",
+    license: SharedLicenses.Polymer2018
+  },
+  {
+    name: "polymer-bridges",
+    license: SharedLicenses.Polymer2018
+  },
+  {
+    name: "whatwg-fetch",
+    license: {
+      name: "whatwg-fetch",
+      type: LicenseTypes.Mit,
+      packageLicenseFile: "LICENSE"
+    }
+  }
+];
+
+export default packages;
diff --git a/polygerrit-ui/app/node_modules_licenses/licenses/isarray.txt b/polygerrit-ui/app/node_modules_licenses/licenses/isarray.txt
new file mode 100644
index 0000000..f42263e
--- /dev/null
+++ b/polygerrit-ui/app/node_modules_licenses/licenses/isarray.txt
@@ -0,0 +1,21 @@
+(MIT)
+
+Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>;
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/polygerrit-ui/app/node_modules_licenses/licenses/page.txt b/polygerrit-ui/app/node_modules_licenses/licenses/page.txt
new file mode 100644
index 0000000..f527394
--- /dev/null
+++ b/polygerrit-ui/app/node_modules_licenses/licenses/page.txt
@@ -0,0 +1,22 @@
+(The MIT License)
+
+Copyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/polygerrit-ui/app/node_modules_licenses/licenses/polymer-2014.txt b/polygerrit-ui/app/node_modules_licenses/licenses/polymer-2014.txt
new file mode 100644
index 0000000..9a35430
--- /dev/null
+++ b/polygerrit-ui/app/node_modules_licenses/licenses/polymer-2014.txt
@@ -0,0 +1,34 @@
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+
+This code may only be used under the BSD style license found at
+http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
+http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
+found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
+part of the polymer project is also subject to an additional IP rights grant
+found at http://polymer.github.io/PATENTS.txt
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/polygerrit-ui/app/node_modules_licenses/licenses/polymer-2015.txt b/polygerrit-ui/app/node_modules_licenses/licenses/polymer-2015.txt
new file mode 100644
index 0000000..d19f02f
--- /dev/null
+++ b/polygerrit-ui/app/node_modules_licenses/licenses/polymer-2015.txt
@@ -0,0 +1,34 @@
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+
+This code may only be used under the BSD style license found at
+http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
+http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
+found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
+part of the polymer project is also subject to an additional IP rights grant
+found at http://polymer.github.io/PATENTS.txt
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/polygerrit-ui/app/node_modules_licenses/licenses/polymer-2017.txt b/polygerrit-ui/app/node_modules_licenses/licenses/polymer-2017.txt
new file mode 100644
index 0000000..440f70f
--- /dev/null
+++ b/polygerrit-ui/app/node_modules_licenses/licenses/polymer-2017.txt
@@ -0,0 +1,34 @@
+Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
+
+This code may only be used under the BSD style license found at
+http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
+http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
+found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
+part of the polymer project is also subject to an additional IP rights grant
+found at http://polymer.github.io/PATENTS.txt
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/polygerrit-ui/app/node_modules_licenses/licenses/polymer-2018.txt b/polygerrit-ui/app/node_modules_licenses/licenses/polymer-2018.txt
new file mode 100644
index 0000000..9381974
--- /dev/null
+++ b/polygerrit-ui/app/node_modules_licenses/licenses/polymer-2018.txt
@@ -0,0 +1,34 @@
+Copyright (c) 2018 The Polymer Project Authors. All rights reserved.
+
+This code may only be used under the BSD style license found at
+http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
+http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
+found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
+part of the polymer project is also subject to an additional IP rights grant
+found at http://polymer.github.io/PATENTS.txt
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/polygerrit-ui/app/node_modules_licenses/tsconfig.json b/polygerrit-ui/app/node_modules_licenses/tsconfig.json
new file mode 100644
index 0000000..6f4254f
--- /dev/null
+++ b/polygerrit-ui/app/node_modules_licenses/tsconfig.json
@@ -0,0 +1,13 @@
+{
+  "compilerOptions": {
+    "target": "es6",
+    "module": "commonjs",
+    "allowSyntheticDefaultImports": true,
+    "esModuleInterop": true,
+    "strict": true,
+    "moduleResolution": "node",
+    "outDir": "out",
+    "types": ["node"]
+  },
+  "include": ["**/*.ts"]
+}
diff --git a/polygerrit-ui/app/package.json b/polygerrit-ui/app/package.json
new file mode 100644
index 0000000..491920d
--- /dev/null
+++ b/polygerrit-ui/app/package.json
@@ -0,0 +1,38 @@
+{
+  "name": "polygerrit-ui-dependencies",
+  "description": "Gerrit Code Review - Polygerrit dependencies",
+  "browser": true,
+  "dependencies": {
+    "@polymer/font-roboto-local": "^3.0.2",
+    "@polymer/iron-a11y-keys-behavior": "^3.0.1",
+    "@polymer/iron-autogrow-textarea": "^3.0.1",
+    "@polymer/iron-dropdown": "^3.0.1",
+    "@polymer/iron-fit-behavior": "^3.0.1",
+    "@polymer/iron-icon": "^3.0.1",
+    "@polymer/iron-iconset-svg": "^3.0.1",
+    "@polymer/iron-input": "^3.0.1",
+    "@polymer/iron-overlay-behavior": "^3.0.2",
+    "@polymer/iron-selector": "^3.0.1",
+    "@polymer/paper-button": "^3.0.1",
+    "@polymer/paper-dialog": "^3.0.1",
+    "@polymer/paper-dialog-behavior": "^3.0.1",
+    "@polymer/paper-dialog-scrollable": "^3.0.1",
+    "@polymer/paper-input": "^3.0.2",
+    "@polymer/paper-item": "^3.0.1",
+    "@polymer/paper-listbox": "^3.0.1",
+    "@polymer/paper-tabs": "^3.1.0",
+    "@polymer/paper-toggle-button": "^3.0.1",
+    "@polymer/polymer": "^3.3.0",
+    "@webcomponents/shadycss": "^1.9.2",
+    "@webcomponents/webcomponentsjs": "^1.3.3",
+    "es6-promise": "^4.2.8",
+    "moment": "^2.24.0",
+    "page": "^1.11.5",
+    "polymer-bridges": "file:../../polymer-bridges/",
+    "ba-linkify": "file:../../lib/ba-linkify/src/",
+    "polymer-resin": "^2.0.1",
+    "whatwg-fetch": "^3.0.0"
+  },
+  "license": "Apache-2.0",
+  "private": true
+}
diff --git a/polygerrit-ui/app/polylint_test.sh b/polygerrit-ui/app/polylint_test.sh
index 98cf06f..79c5972 100755
--- a/polygerrit-ui/app/polylint_test.sh
+++ b/polygerrit-ui/app/polylint_test.sh
@@ -2,30 +2,12 @@
 
 set -ex
 
-npm_bin=$(which npm)
-if [[ -z "$npm_bin" ]]; then
-    echo "NPM must be on the path."
-    exit 1
-fi
-
-node_bin=$(which node)
-if [[ -z "$node_bin" ]]; then
-    echo "node must be on the path."
-    exit 1
-fi
-
-polymer_bin=$(which polymer)
-if [[ -z "$polymer_bin" ]]; then
-  polymer_bin=$(abs_path ./node_modules/polymer-cli/bin/polymer.js);
-fi
-if [[ -z "$polymer_bin" ]]; then
-    echo "polymer must be set or polymer-cli locally installed (npm install polymer-cli)."
-    exit 1
-fi
-
-unzip -o polygerrit-ui/polygerrit_components.bower_components.zip -d polygerrit-ui/app
+DIR=$(pwd)
+ln -s $RUNFILES_DIR/ui_npm/node_modules $TEST_TMPDIR/node_modules
+cp $2 $TEST_TMPDIR/polymer.json
+cp -R -L polygerrit-ui/app/polylint-updated-links/polygerrit-ui/app/* $TEST_TMPDIR
 
 #Can't use --root with polymer.json - see https://github.com/Polymer/tools/issues/2616
 #Change current directory to the root folder
-cd polygerrit-ui/app
-$polymer_bin lint --component-dir 'bower_components' --verbose
+cd $TEST_TMPDIR/
+$DIR/$1 lint --verbose
diff --git a/polygerrit-ui/app/redirects.json b/polygerrit-ui/app/redirects.json
new file mode 100644
index 0000000..a51d361
--- /dev/null
+++ b/polygerrit-ui/app/redirects.json
@@ -0,0 +1,50 @@
+{
+  "description": "See tools/node_tools/polygerrit_app_preprocessor/redirects.ts",
+  "redirects": [
+    {
+      "from": "/bower_components/ba-linkify",
+      "to": {
+        "npm_module": "ba-linkify"
+      }
+    },
+    {
+      "from": "/bower_components/es6-promise",
+      "to": {
+        "npm_module": "es6-promise"
+      }
+    },
+    {
+      "from": "/bower_components/fetch",
+      "to": {
+        "npm_module": "whatwg-fetch",
+        "files": {
+          "fetch.js": "dist/fetch.umd.js"
+        }
+      }
+    },
+    {
+      "from": "/bower_components/moment",
+      "to": {
+        "npm_module": "moment"
+      }
+    },
+    {
+      "from": "/bower_components/webcomponentsjs",
+      "to": {
+        "npm_module": "@webcomponents/webcomponentsjs"
+      }
+    },
+    {
+      "from": "/bower_components/page",
+      "to": {
+        "npm_module": "page"
+      }
+    },
+    {
+      "from": "/bower_components",
+      "to": {
+        "npm_module": "polymer-bridges"
+      }
+    }
+  ]
+}
diff --git a/polygerrit-ui/app/rollup.config.js b/polygerrit-ui/app/rollup.config.js
new file mode 100644
index 0000000..eb489ce
--- /dev/null
+++ b/polygerrit-ui/app/rollup.config.js
@@ -0,0 +1,87 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+const path = require('path');
+
+// In this file word "plugin" refers to rollup plugin, not Gerrit plugin.
+// By default, require(plugin_name) tries to find module plugin_name starting
+// from the folder where this file (rollup.config.js) is located
+// (see https://www.typescriptlang.org/docs/handbook/module-resolution.html#node
+// and https://nodejs.org/api/modules.html#modules_all_together).
+// So, rollup.config.js can't be in polygerrit-ui/app dir and it should be in
+// tools/node_tools directory (where all plugins are installed).
+// But rollup_bundle rule copy this .config.js file to another directory,
+// so require(plugin_name) can't find a plugin.
+// To fix it, requirePlugin tries:
+// 1. resolve module id using default behavior, i.e. it starts from __dirname
+// 2. if module not found - it tries to resolve module starting from rollupBin
+//    location.
+// This workaround also gives us additional power - we can place .config.js
+// file anywhere in a source tree and add all plugins in the same package.json
+// file as rollup node module.
+function requirePlugin(id) {
+  const rollupBinDir = path.dirname(process.argv[1]);
+  const pluginPath = require.resolve(id, {paths: [__dirname, rollupBinDir] });
+  return require(pluginPath);
+}
+
+const resolve = requirePlugin('rollup-plugin-node-resolve');
+const {terser} = requirePlugin('rollup-plugin-terser');
+
+// @polymer/font-roboto-local uses import.meta.url value
+// as a base path to fonts. We should substitute a correct javascript
+// code to get a base path for font-roboto-local fonts.
+const importLocalFontMetaUrlResolver = function() {
+  return {
+    name: 'import-meta-url-resolver',
+    resolveImportMeta: function (property, data) {
+      if(property === 'url' && data.moduleId.endsWith('/@polymer/font-roboto-local/roboto.js')) {
+        return 'new URL("..", document.baseURI).href';
+      }
+      return null;
+    }
+  }
+};
+
+export default {
+  treeshake: false,
+  onwarn: warning => {
+    if(warning.code === 'CIRCULAR_DEPENDENCY') {
+      // Temporary allow CIRCULAR_DEPENDENCY.
+      // See https://bugs.chromium.org/p/gerrit/issues/detail?id=12090
+      // Delete this code after bug is fixed.
+      return;
+    }
+    // No warnings from rollupjs are allowed.
+    // Most of the warnings are real error in our code (for example,
+    // if some import couldn't be resolved we can't continue, but rollup
+    // reports it as a warning)
+    throw new Error(warning.message);
+  },
+  output: {
+    format: 'iife',
+    compact: true,
+    plugins: [terser()]
+  },
+  //Context must be set to window to correctly processing global variables
+  context: 'window',
+  plugins: [resolve({
+    customResolveOptions: {
+      moduleDirectory: 'node_modules'
+    }
+  }), importLocalFontMetaUrlResolver()],
+};
diff --git a/polygerrit-ui/app/rules.bzl b/polygerrit-ui/app/rules.bzl
index 7ef0ee3..12b6911 100644
--- a/polygerrit-ui/app/rules.bzl
+++ b/polygerrit-ui/app/rules.bzl
@@ -1,55 +1,118 @@
-load("@io_bazel_rules_closure//closure:defs.bzl", "closure_js_binary", "closure_js_library")
 load("//tools/bzl:genrule2.bzl", "genrule2")
-load(
-    "//tools/bzl:js.bzl",
-    "bundle_assets",
-)
+load("//tools/node_tools/polygerrit_app_preprocessor:index.bzl", "prepare_for_bundling", "update_links")
+load("//tools/node_tools/legacy:index.bzl", "polymer_bundler_tool")
+load("@npm_bazel_rollup//:index.bzl", "rollup_bundle")
 
-def polygerrit_bundle(name, srcs, outs, app):
-    appName = app.split(".html")[0].split("/").pop()  # eg: gr-app
+def polygerrit_bundle(name, srcs, outs, entry_point, redirects):
+    """Build .zip bundle from source code
 
-    closure_js_binary(
-        name = name + "_closure_bin",
-        # Known issue: Closure compilation not compatible with Polymer behaviors.
-        # See: https://github.com/google/closure-compiler/issues/2042
-        compilation_level = "WHITESPACE_ONLY",
-        defs = [
-            "--polymer_version=2",
-            "--jscomp_off=duplicate",
-        ],
-        language = "ECMASCRIPT_2017",
-        deps = [name + "_closure_lib"],
-        dependency_mode = "PRUNE_LEGACY",
-    )
+    Args:
+        name: rule name
+        srcs: source files
+        outs: array with a single item - the output file name
+        entry_point: application entry-point
+        redirects: .json file with redirects
+    """
 
-    closure_js_library(
-        name = name + "_closure_lib",
-        srcs = [appName + ".js"],
-        convention = "GOOGLE",
-        # TODO(davido): Clean up these issues: http://paste.openstack.org/show/608548
-        # and remove this supression
-        suppress = [
-            "JSC_JSDOC_MISSING_TYPE_WARNING",
-            "JSC_UNNECESSARY_ESCAPE",
-        ],
-        deps = [
-            "//lib/polymer_externs:polymer_closure",
-            "@io_bazel_rules_closure//closure/library",
-        ],
-    )
+    app_name = entry_point.split(".html")[0].split("/").pop()  # eg: gr-app
 
-    bundle_assets(
-        name = appName,
+    # Update links in all .html files according to rules in redirects.json file. All other files
+    # remain unchanged. After the update, all references to bower_components have been replaced with
+    # correct references to node_modules.
+    # The output of this rule is a directory, which mirrors the directory layout of srcs files.
+    update_links(
+        name = app_name + "-updated-links",
         srcs = srcs,
-        app = app,
-        deps = ["//polygerrit-ui:polygerrit_components.bower_components"],
+        redirects = redirects,
+    )
+    # Note: prepare_for_bundling and polymer_bundler_tool will be removed after switch to
+    #   ES6 modules.
+    # Polymer 3 uses ES modules; gerrit still use HTML imports and polymer-bridges. In such
+    # conditions, polymer-bundler/crisper and polymer-cli tools crash without an error or complains
+    # about non-existing syntax error in .js code. But even if they works with some config, the
+    # output result is not correct. At the same time, polymer-bundler/crisper work well if input
+    # files are HTML and js without javascript modules.
+    #
+    # Polygerrit's code follows simple rules, so it is quite easy to preprocess code in a way, that
+    # it can be consumed by polymer-bundler/crisper tool. Rules do the following:
+    # 1) prepare_for_bundling - update srcs by moving all scripts out of HTML files.
+    #    For each HTML file it creates file.html_gen.js file in the same directory and put all
+    #    scripts there in the same order, as script tags appear in HTML file.
+    #    - Inline javascript is copied as is;
+    #    - <script src = "path/to/file.js" > adds to .js file as
+    #      import 'path/to/file.js'
+    #      statement. Such import statement run all side-effects in file.js (i.e. it run all global
+    #      code).
+    #    - <link rel="import" href = "path/to/file.html"> adds to .js file as
+    #     import 'path/to/file.html.js' - i.e. instead of html, the .js script imports another
+    #     generated js file ('path/to/file.html_gen.js').
+    #    Because output JS keeps the order of imports, all global variables are initialized in a
+    #    correct order (this is important for gerrit; it is impossible to use AMD modules here).
+    #    Then, all scripts are removed from HTML file.
+
+    #    Output of this rule - directory with updated HTML and JS files; all other files are copied
+    #    to the output directory without changes.
+    # 2) rollup_bundle - combines all .js files from the previous step into one bundle.
+    # 3) polymer_bundler_tool -
+    #    a) run polymer-bundle tool on HTML files (i.e. on output from the first step). Because
+    #    these files don't contain scripts anymore, it just combine all HTML/CSS files in one file
+    #    (by following HTML imports).
+    #    b) run crisper to add script tag at the end of generated HTML
+    #
+    # Output of the rule is 2 file: HTML bundle and JS bundle and HTML file loads JS file with
+    # <script src="..."> tag.
+
+    prepare_for_bundling(
+        name = app_name + "-prebundling-srcs",
+        srcs = [
+            app_name + "-updated-links",
+        ],
+        additional_node_modules_to_preprocess = [
+            "@ui_npm//polymer-bridges",
+        ],
+        entry_point = entry_point,
+        node_modules = [
+            "@ui_npm//:node_modules",
+        ],
+        root_path = "polygerrit-ui/app/" + app_name + "-updated-links/polygerrit-ui/app",
+    )
+
+    native.filegroup(
+        name = app_name + "-prebundling-srcs-js",
+        srcs = [app_name + "-prebundling-srcs"],
+        output_group = "js",
+    )
+
+    native.filegroup(
+        name = app_name + "-prebundling-srcs-html",
+        srcs = [app_name + "-prebundling-srcs"],
+        output_group = "html",
+    )
+
+    rollup_bundle(
+        name = app_name + "-bundle-js",
+        srcs = [app_name + "-prebundling-srcs-js"],
+        config_file = ":rollup.config.js",
+        entry_point = app_name + "-prebundling-srcs/entry.js",
+        rollup_bin = "//tools/node_tools:rollup-bin",
+        sourcemap = "hidden",
+        deps = [
+            "@tools_npm//rollup-plugin-node-resolve",
+        ],
+    )
+
+    polymer_bundler_tool(
+        name = app_name + "-bundle-html",
+        srcs = [app_name + "-prebundling-srcs-html"],
+        entry_point = app_name + "-prebundling-srcs/entry.html",
+        script_src_value = app_name + ".js",
     )
 
     native.filegroup(
         name = name + "_app_sources",
         srcs = [
-            name + "_closure_bin.js",
-            appName + ".html",
+            app_name + "-bundle-js.js",
+            app_name + "-bundle-html.html",
         ],
     )
 
@@ -74,6 +137,8 @@
         ],
     )
 
+    # Preserve bower_components directory in the final directory layout to
+    # avoid plugins break
     genrule2(
         name = name,
         srcs = [
@@ -82,24 +147,24 @@
             name + "_theme_sources",
             name + "_top_sources",
             "//lib/fonts:robotofonts",
-            "//lib/js:highlightjs_files",
-            # we extract from the zip, but depend on the component for license checking.
-            "@webcomponentsjs//:zipfile",
-            "//lib/js:webcomponentsjs",
-            "@font-roboto-local//:zipfile",
-            "//lib/js:font-roboto-local",
+            "//lib/js:highlightjs__files",
+            "@ui_npm//:node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js",
+            "@ui_npm//@polymer/font-roboto-local",
+            "@ui_npm//:node_modules/@polymer/font-roboto-local/package.json",
         ],
         outs = outs,
         cmd = " && ".join([
-            "mkdir -p $$TMP/polygerrit_ui/{styles/themes,fonts,bower_components/{highlightjs,webcomponentsjs},elements}",
-            "for f in $(locations " + name + "_app_sources); do ext=$${f##*.}; cp -p $$f $$TMP/polygerrit_ui/elements/" + appName + ".$$ext; done",
+            "FONT_DIR=$$(dirname $(location @ui_npm//:node_modules/@polymer/font-roboto-local/package.json))/fonts",
+            "mkdir -p $$TMP/polygerrit_ui/{styles/themes,fonts/{roboto,robotomono},bower_components/{highlightjs,webcomponentsjs},elements}",
+            "for f in $(locations " + name + "_app_sources); do ext=$${f##*.}; cp -p $$f $$TMP/polygerrit_ui/elements/" + app_name + ".$$ext; done",
             "cp $(locations //lib/fonts:robotofonts) $$TMP/polygerrit_ui/fonts/",
             "for f in $(locations " + name + "_top_sources); do cp $$f $$TMP/polygerrit_ui/; done",
             "for f in $(locations " + name + "_css_sources); do cp $$f $$TMP/polygerrit_ui/styles; done",
             "for f in $(locations " + name + "_theme_sources); do cp $$f $$TMP/polygerrit_ui/styles/themes; done",
-            "for f in $(locations //lib/js:highlightjs_files); do cp $$f $$TMP/polygerrit_ui/bower_components/highlightjs/ ; done",
-            "unzip -qd $$TMP/polygerrit_ui/bower_components $(location @webcomponentsjs//:zipfile) webcomponentsjs/webcomponents-lite.js",
-            "unzip -qd $$TMP/polygerrit_ui/bower_components $(location @font-roboto-local//:zipfile) font-roboto-local/fonts/\\*/\\*.ttf",
+            "for f in $(locations //lib/js:highlightjs__files); do cp $$f $$TMP/polygerrit_ui/bower_components/highlightjs/ ; done",
+            "cp $(location @ui_npm//:node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js) $$TMP/polygerrit_ui/bower_components/webcomponentsjs/webcomponents-lite.js",
+            "cp $$FONT_DIR/roboto/*.ttf $$TMP/polygerrit_ui/fonts/roboto/",
+            "cp $$FONT_DIR/robotomono/*.ttf $$TMP/polygerrit_ui/fonts/robotomono/",
             "cd $$TMP",
             "find . -exec touch -t 198001010000 '{}' ';'",
             "zip -qr $$ROOT/$@ *",
diff --git a/polygerrit-ui/app/run_test.sh b/polygerrit-ui/app/run_test.sh
index 76a4fa1..5f61de7 100755
--- a/polygerrit-ui/app/run_test.sh
+++ b/polygerrit-ui/app/run_test.sh
@@ -1,37 +1,5 @@
 #!/usr/bin/env bash
 
-npm_bin=$(which npm)
-if [[ -z "$npm_bin" ]]; then
-    echo "NPM must be on the path. (https://www.npmjs.com/)"
-    exit 1
-fi
-
-# From https://www.linuxquestions.org/questions/programming-9/bash-script-return-full-path-and-filename-680368/page3.html
-function abs_path {
-  if [[ -d "$1" ]]
-  then
-      pushd "$1" >/dev/null
-      pwd
-      popd >/dev/null
-  elif [[ -e $1 ]]
-  then
-      pushd "$(dirname "$1")" >/dev/null
-      echo "$(pwd)/$(basename "$1")"
-      popd >/dev/null
-  else
-      echo "$1" does not exist! >&2
-      return 127
-  fi
-}
-wct_bin=$(which wct)
-if [[ -z "$wct_bin" ]]; then
-  wct_bin=$(abs_path ./node_modules/web-component-tester/bin/wct);
-fi
-if [[ -z "$wct_bin" ]]; then
-    echo "wct_bin must be set or WCT locally installed (npm install wct)."
-    exit 1
-fi
-
 bazel_bin=$(which bazelisk 2>/dev/null)
 if [[ -z "$bazel_bin" ]]; then
     echo "Warning: bazelisk is not installed; falling back to bazel."
@@ -42,9 +10,7 @@
 # TODO(hanwen): does $DISPLAY even work on OSX?
 ${bazel_bin} test \
       --test_env="HOME=$HOME" \
-      --test_env="WCT=${wct_bin}" \
       --test_env="WCT_ARGS=${WCT_ARGS}" \
-      --test_env="NPM=${npm_bin}" \
       --test_env="DISPLAY=${DISPLAY}" \
       --test_env="WCT_HEADLESS_MODE=${WCT_HEADLESS_MODE}" \
       "$@" \
diff --git a/polygerrit-ui/app/scripts/gr-display-name-utils/gr-display-name-utils_test.html b/polygerrit-ui/app/scripts/gr-display-name-utils/gr-display-name-utils_test.html
index a35e034..0ab41de 100644
--- a/polygerrit-ui/app/scripts/gr-display-name-utils/gr-display-name-utils_test.html
+++ b/polygerrit-ui/app/scripts/gr-display-name-utils/gr-display-name-utils_test.html
@@ -23,11 +23,13 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../test/common-test-setup.html"/>
 <script src="gr-display-name-utils.js"></script>
 
 <script>
-  suite('gr-display-name-utils tests', () => {
+  suite('gr-display-name-utils tests', async () => {
+    await readyToTest();
     // eslint-disable-next-line no-unused-vars
     const config = {
       user: {
diff --git a/polygerrit-ui/app/scripts/gr-email-suggestions-provider/gr-email-suggestions-provider_test.html b/polygerrit-ui/app/scripts/gr-email-suggestions-provider/gr-email-suggestions-provider_test.html
index ac32efa..5fad3f4 100644
--- a/polygerrit-ui/app/scripts/gr-email-suggestions-provider/gr-email-suggestions-provider_test.html
+++ b/polygerrit-ui/app/scripts/gr-email-suggestions-provider/gr-email-suggestions-provider_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="../../elements/shared/gr-rest-api-interface/gr-rest-api-interface.html"/>
 <script src="../gr-display-name-utils/gr-display-name-utils.js"></script>
@@ -38,7 +39,8 @@
 </test-fixture>
 
 <script>
-  suite('GrEmailSuggestionsProvider tests', () => {
+  suite('GrEmailSuggestionsProvider tests', async () => {
+    await readyToTest();
     let sandbox;
     let restAPI;
     let provider;
diff --git a/polygerrit-ui/app/scripts/gr-group-suggestions-provider/gr-group-suggestions-provider_test.html b/polygerrit-ui/app/scripts/gr-group-suggestions-provider/gr-group-suggestions-provider_test.html
index 6908256..7d89c2a 100644
--- a/polygerrit-ui/app/scripts/gr-group-suggestions-provider/gr-group-suggestions-provider_test.html
+++ b/polygerrit-ui/app/scripts/gr-group-suggestions-provider/gr-group-suggestions-provider_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="../../elements/shared/gr-rest-api-interface/gr-rest-api-interface.html"/>
 <script src="../gr-display-name-utils/gr-display-name-utils.js"></script>
@@ -37,7 +38,8 @@
 </test-fixture>
 
 <script>
-  suite('GrGroupSuggestionsProvider tests', () => {
+  suite('GrGroupSuggestionsProvider tests', async () => {
+    await readyToTest();
     let sandbox;
     let restAPI;
     let provider;
diff --git a/polygerrit-ui/app/scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider.js b/polygerrit-ui/app/scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider.js
index ffcdba9..fecf75aa 100644
--- a/polygerrit-ui/app/scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider.js
+++ b/polygerrit-ui/app/scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider.js
@@ -16,6 +16,7 @@
  */
 (function(window) {
   'use strict';
+  window.Gerrit = window.Gerrit || {};
 
   if (window.GrReviewerSuggestionsProvider) {
     return;
diff --git a/polygerrit-ui/app/scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider_test.html b/polygerrit-ui/app/scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider_test.html
index fc6fa1c..af7b4bd 100644
--- a/polygerrit-ui/app/scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider_test.html
+++ b/polygerrit-ui/app/scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider_test.html
@@ -23,6 +23,7 @@
 
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../test/test-pre-setup.js"></script>
 <link rel="import" href="../../../test/common-test-setup.html"/>
 <link rel="import" href="../../elements/shared/gr-rest-api-interface/gr-rest-api-interface.html"/>
 <script src="../gr-display-name-utils/gr-display-name-utils.js"></script>
@@ -37,7 +38,8 @@
 </test-fixture>
 
 <script>
-  suite('GrReviewerSuggestionsProvider tests', () => {
+  suite('GrReviewerSuggestionsProvider tests', async () => {
+    await readyToTest();
     let sandbox;
     let _nextAccountId = 0;
     const makeAccount = function(opt_status) {
diff --git a/polygerrit-ui/app/test/index.html b/polygerrit-ui/app/test/index.html
index 26078cd..7decb61 100644
--- a/polygerrit-ui/app/test/index.html
+++ b/polygerrit-ui/app/test/index.html
@@ -21,6 +21,13 @@
 <meta charset="utf-8">
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <script src="/bower_components/web-component-tester/browser.js"></script>
+<style>
+  /* Prevent horizontal scrolling on page.
+   New version of web-component-tester creates very narrow iframe */
+  #subsuites {
+    width: 1500px !important;
+  }
+</style>
 <script>
   const testFiles = [];
   const scriptsPath = '../scripts/';
diff --git a/polygerrit-ui/app/test/test-pre-setup.js b/polygerrit-ui/app/test/test-pre-setup.js
new file mode 100644
index 0000000..dd317cf
--- /dev/null
+++ b/polygerrit-ui/app/test/test-pre-setup.js
@@ -0,0 +1,28 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * After M80, htmlImports has been removed and the polyfill from
+ * webcomponents can only support async html imports unlike
+ * native htmlImports which loads htmls synchronously.
+ */
+window.readyToTest = () => Promise.race([
+  new Promise(resolve =>
+    window.addEventListener('HTMLImportsLoaded', resolve)),
+  // timeout after 5s, the test timeout is 10s
+  new Promise(resolve => setTimeout(resolve, 5000)),
+]);
diff --git a/polygerrit-ui/app/types/polymer-behaviors.js b/polygerrit-ui/app/types/polymer-behaviors.js
index 18e7ad9..30b5f5d 100644
--- a/polygerrit-ui/app/types/polymer-behaviors.js
+++ b/polygerrit-ui/app/types/polymer-behaviors.js
@@ -49,4 +49,9 @@
         };
       }
     };
+
+  /**
+   * @polymerBehavior
+   * */
+  Polymer.IronA11yKeysBehavior = [];
 }
diff --git a/polygerrit-ui/app/wct.conf.js b/polygerrit-ui/app/wct.conf.js
new file mode 100644
index 0000000..0e53adb
--- /dev/null
+++ b/polygerrit-ui/app/wct.conf.js
@@ -0,0 +1,63 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+For some reason wct tries to install selenium into its node_modules
+directory on first run. If you've installed into /usr/local and
+aren't running wct as root, you're screwed. Turning this option off
+through skipSeleniumInstall seems to still work, so there's that.
+
+Sauce tests are disabled by default in order to run local tests
+only.  Run it with (saucelabs.com account required; free for open
+source): ./polygerrit-ui/app/run_test.sh --test_arg=--plugin --test_arg=sauce
+*/
+
+const headless = 'WCT_HEADLESS_MODE' in process.env ?
+  process.env['WCT_HEADLESS_MODE'] !== '0' : false;
+
+const headlessBrowserOptions = {
+  chrome: ['start-maximized', 'headless', 'disable-gpu', 'no-sandbox'],
+  firefox: ['-headless'],
+};
+
+const defaultBrowserOptions = {
+  chrome: ['start-maximized'],
+  firefox: [],
+};
+
+module.exports = {
+  suites: ['test'],
+  npm: true,
+  moduleResolution: 'node',
+  wctPackageName: 'wct-browser-legacy',
+  plugins: {
+    local: {
+      skipSeleniumInstall: true,
+      browserOptions: headless ? headlessBrowserOptions : defaultBrowserOptions,
+    },
+    sauce: {
+      disabled: true,
+      browsers: [
+        'OS X 10.12/chrome',
+        'Windows 10/chrome',
+        'Linux/firefox',
+        'OS X 10.12/safari',
+        'Windows 10/microsoftedge',
+      ],
+    },
+  },
+};
diff --git a/polygerrit-ui/app/wct_test.sh b/polygerrit-ui/app/wct_test.sh
index f1b4666..0970098 100755
--- a/polygerrit-ui/app/wct_test.sh
+++ b/polygerrit-ui/app/wct_test.sh
@@ -1,67 +1,27 @@
 #!/bin/sh
 
 set -ex
+root_dir=$(pwd)
+t=$TEST_TMPDIR
 
-t=$(mktemp -d || mktemp -d -t wct-XXXXXXXXXX)
-components=$TEST_SRCDIR/gerrit/polygerrit-ui/app/test_components.zip
-code=$TEST_SRCDIR/gerrit/polygerrit-ui/app/pg_code.zip
+mkdir -p $t/node_modules
+# WCT doesn't implement node module resolution.
+# WCT uses only node_module/ directory from current directory when looking for a module
+# So, it is impossible to make hierarchical node_modules. Instead, we copy
+# all node_modules to one directory.
+cp -R -L ./external/ui_dev_npm/node_modules/* $t/node_modules
 
-echo $t
-unzip -qd $t $components
-unzip -qd $t $code
-mkdir -p $t/test
-cp $TEST_SRCDIR/gerrit/polygerrit-ui/app/test/index.html $t/test/
+# Copy ui_npm, so it will override ui_dev_npm modules (in case of conflicts)
+# Because browser always requests specific exact files (i.e. not a directory),
+# it always receives file from ui_npm. It can broke WCT itself but luckely it works.
+cp -R -L ./external/ui_npm/node_modules/* $t/node_modules
 
-if [ "${WCT_HEADLESS_MODE:-0}" != "0" ]; then
-    CHROME_OPTIONS=[\'start-maximized\',\'headless\',\'disable-gpu\',\'no-sandbox\']
-    FIREFOX_OPTIONS=[\'-headless\']
-else
-    CHROME_OPTIONS=[\'start-maximized\']
-    FIREFOX_OPTIONS=[\'\']
-fi
-
-# For some reason wct tries to install selenium into its node_modules
-# directory on first run. If you've installed into /usr/local and
-# aren't running wct as root, you're screwed. Turning this option off
-# through skipSeleniumInstall seems to still work, so there's that.
-
-# Sauce tests are disabled by default in order to run local tests
-# only.  Run it with (saucelabs.com account required; free for open
-# source): WCT_ARGS='--plugin sauce' ./polygerrit-ui/app/run_test.sh
-
-cat <<EOF > $t/wct.conf.js
-module.exports = {
-      'suites': ['test'],
-      'webserver': {
-        'pathMappings': [
-          {'/components/bower_components': 'bower_components'}
-        ]
-      },
-      'plugins': {
-        'local': {
-          'skipSeleniumInstall': true,
-          'browserOptions': {
-            'chrome': ${CHROME_OPTIONS},
-            'firefox': ${FIREFOX_OPTIONS}
-          }
-        },
-        'sauce': {
-          'disabled': true,
-          'browsers': [
-            'OS X 10.12/chrome',
-            'Windows 10/chrome',
-            'Linux/firefox',
-            'OS X 10.12/safari',
-            'Windows 10/microsoftedge'
-          ]
-        }
-      }
-    };
-EOF
+cp -R -L ./polygerrit-ui/app/test-srcs-updated-links/polygerrit-ui/app/* $t/
 
 export PATH="$(dirname $NPM):$PATH"
 
 cd $t
-test -n "${WCT}"
 
-${WCT} ${WCT_ARGS}
+# If wct doesn't receive any paramenters, it fails (can't find files)
+# Pass --config-file as a parameter to have some arguments in command line
+$root_dir/$1 --config-file wct.conf.js ${WCT_ARGS}
diff --git a/polygerrit-ui/app/yarn.lock b/polygerrit-ui/app/yarn.lock
new file mode 100644
index 0000000..06b0e96
--- /dev/null
+++ b/polygerrit-ui/app/yarn.lock
@@ -0,0 +1,374 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@polymer/font-roboto-local@^3.0.2":
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/@polymer/font-roboto-local/-/font-roboto-local-3.0.2.tgz#563cd6cabbcaef54999d654c0f3d476bcc49ce58"
+  integrity sha512-mCd9TcjwnCxU+7uVHCkbREGU+OmzStvYh3ru5DSaftOQDnMrLAzernEv/QCcfSPRgTMHij+pIUN4tcaGeDGcYg==
+
+"@polymer/font-roboto@^3.0.1":
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/@polymer/font-roboto/-/font-roboto-3.0.2.tgz#80cdaa7225db2359130dfb2c6d9a3be1820020c3"
+  integrity sha512-tx5TauYSmzsIvmSqepUPDYbs4/Ejz2XbZ1IkD7JEGqkdNUJlh+9KU85G56Tfdk/xjEZ8zorFfN09OSwiMrIQWA==
+
+"@polymer/iron-a11y-announcer@^3.0.0-pre.26":
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/@polymer/iron-a11y-announcer/-/iron-a11y-announcer-3.0.2.tgz#730dd36ccb2e042ecd5160ba439c2bf2f8a97412"
+  integrity sha512-LqnMF39mXyxSSRbTHRzGbcJS8nU0NVTo2raBOgOlpxw5yfGJUVcwaTJ/qy5NtWCZLRfa4suycf0oAkuUjHTXHQ==
+  dependencies:
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/iron-a11y-keys-behavior@^3.0.0-pre.26", "@polymer/iron-a11y-keys-behavior@^3.0.1":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@polymer/iron-a11y-keys-behavior/-/iron-a11y-keys-behavior-3.0.1.tgz#2868ea72912d2007ffab4734684a91f5aac49b84"
+  integrity sha512-lnrjKq3ysbBPT/74l0Fj0U9H9C35Tpw2C/tpJ8a+5g8Y3YJs1WSZYnEl1yOkw6sEyaxOq/1DkzH0+60gGu5/PQ==
+  dependencies:
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/iron-autogrow-textarea@^3.0.0-pre.26", "@polymer/iron-autogrow-textarea@^3.0.1":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@polymer/iron-autogrow-textarea/-/iron-autogrow-textarea-3.0.1.tgz#0205d9c5ca16f3afd505f41e9037989707d59dce"
+  integrity sha512-FgSL7APrOSL9Vu812sBCFlQ17hvnJsBAV2C2e1UAiaHhB+dyfLq8gGdGUpqVWuGJ50q4Y/49QwCNnLf85AdVYA==
+  dependencies:
+    "@polymer/iron-behaviors" "^3.0.0-pre.26"
+    "@polymer/iron-flex-layout" "^3.0.0-pre.26"
+    "@polymer/iron-validatable-behavior" "^3.0.0-pre.26"
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/iron-behaviors@^3.0.0-pre.26":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@polymer/iron-behaviors/-/iron-behaviors-3.0.1.tgz#a3b6f876779a7f0a91a15e4423890968b6525901"
+  integrity sha512-IMEwcv1lhf1HSQxuyWOUIL0lOBwmeaoSTpgCJeP9IBYnuB1SPQngmfRuHKgK6/m9LQ9F9miC7p3HeQQUdKAE0w==
+  dependencies:
+    "@polymer/iron-a11y-keys-behavior" "^3.0.0-pre.26"
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/iron-checked-element-behavior@^3.0.0-pre.26":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@polymer/iron-checked-element-behavior/-/iron-checked-element-behavior-3.0.1.tgz#7a4b49646603657ab2c5e5ca7bd97f34444fdaf5"
+  integrity sha512-aDr0cbCNVq49q+pOqa6CZutFh+wWpwPMLpEth9swx+GkAj+gCURhuQkaUYhIo5f2egDbEioR1aeHMnPlU9dQZA==
+  dependencies:
+    "@polymer/iron-form-element-behavior" "^3.0.0-pre.26"
+    "@polymer/iron-validatable-behavior" "^3.0.0-pre.26"
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/iron-dropdown@^3.0.1":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@polymer/iron-dropdown/-/iron-dropdown-3.0.1.tgz#c573faa1a08c179d201ae877c1c726018314bff3"
+  integrity sha512-22yLhepfcKjuQMfFmRHi/9MPKTqkzgRrmWWW0P5uqK++xle53k2QBO5VYUAYiCN3ZcxIi9lEhZ9YWGeQj2JBig==
+  dependencies:
+    "@polymer/iron-behaviors" "^3.0.0-pre.26"
+    "@polymer/iron-overlay-behavior" "^3.0.0-pre.27"
+    "@polymer/neon-animation" "^3.0.0-pre.26"
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/iron-fit-behavior@^3.0.0-pre.26", "@polymer/iron-fit-behavior@^3.0.1":
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/@polymer/iron-fit-behavior/-/iron-fit-behavior-3.0.2.tgz#2ec460d8a6b0151394b55631a72a68b92e14e2e0"
+  integrity sha512-JndryJYbBR3gSN5IlST4rCHsd01+OyvYpRO6z5Zd3C6u5V/m07TwAtcf3aXwZ8WBNt2eLG28OcvdSO7XR2v2pg==
+  dependencies:
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/iron-flex-layout@^3.0.0-pre.26":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@polymer/iron-flex-layout/-/iron-flex-layout-3.0.1.tgz#36f9e1a8eb792d279b2bc75d362628721ad37f0c"
+  integrity sha512-7gB869czArF+HZcPTVSgvA7tXYFze9EKckvM95NB7SqYF+NnsQyhoXgKnpFwGyo95lUjUW9TFDLUwDXnCYFtkw==
+  dependencies:
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/iron-form-element-behavior@^3.0.0-pre.26":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@polymer/iron-form-element-behavior/-/iron-form-element-behavior-3.0.1.tgz#4c79e1981d7796ce659e997f3b8f5e14b4a075a4"
+  integrity sha512-G/e2KXyL5AY7mMjmomHkGpgS0uAf4ovNpKhkuUTRnMuMJuf589bKqE85KN4ovE1Tzhv2hJoh/igyD6ekHiYU1A==
+  dependencies:
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/iron-icon@^3.0.0-pre.26", "@polymer/iron-icon@^3.0.1":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@polymer/iron-icon/-/iron-icon-3.0.1.tgz#93211c39d8825fe4965a68419566036c1df291eb"
+  integrity sha512-QLPwirk+UPZNaLnMew9VludXA4CWUCenRewgEcGYwdzVgDPCDbXxy6vRJjmweZobMQv/oVLppT2JZtJFnPxX6g==
+  dependencies:
+    "@polymer/iron-flex-layout" "^3.0.0-pre.26"
+    "@polymer/iron-meta" "^3.0.0-pre.26"
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/iron-iconset-svg@^3.0.0-pre.26", "@polymer/iron-iconset-svg@^3.0.1":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@polymer/iron-iconset-svg/-/iron-iconset-svg-3.0.1.tgz#568d6e7dbc120299dae63be3600aeba0d30ddbea"
+  integrity sha512-XNwURbNHRw6u2fJe05O5fMYye6GSgDlDqCO+q6K1zAnKIrpgZwf2vTkBd5uCcZwsN0FyCB3mvNZx4jkh85dRDw==
+  dependencies:
+    "@polymer/iron-meta" "^3.0.0-pre.26"
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/iron-input@^3.0.0-pre.26", "@polymer/iron-input@^3.0.1":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@polymer/iron-input/-/iron-input-3.0.1.tgz#dc866a25107f9b38d9ca4512dd9a3e51b78b4915"
+  integrity sha512-WLx13kEcbH9GKbj9+pWR6pbJkA5kxn3796ynx6eQd2rueMyUfVTR3GzOvadBKsciUuIuzrxpBWZ2+3UcueVUQQ==
+  dependencies:
+    "@polymer/iron-a11y-announcer" "^3.0.0-pre.26"
+    "@polymer/iron-validatable-behavior" "^3.0.0-pre.26"
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/iron-menu-behavior@^3.0.0-pre.26":
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/@polymer/iron-menu-behavior/-/iron-menu-behavior-3.0.2.tgz#f8fa2d59af472a4cb4fb0359c704b808bc2c105d"
+  integrity sha512-8dpASkFNBIkxAJWsFLWIO1M7tKM0+wKs3PqdeF/dDdBciwoaaFgC2K1XCZFZnbe2t9/nJgemXxVugGZAWpYCGg==
+  dependencies:
+    "@polymer/iron-a11y-keys-behavior" "^3.0.0-pre.26"
+    "@polymer/iron-flex-layout" "^3.0.0-pre.26"
+    "@polymer/iron-selector" "^3.0.0-pre.26"
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/iron-meta@^3.0.0-pre.26":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@polymer/iron-meta/-/iron-meta-3.0.1.tgz#7f140628d127b0a284f882f1bb323a261bc125f5"
+  integrity sha512-pWguPugiLYmWFV9UWxLWzZ6gm4wBwQdDy4VULKwdHCqR7OP7u98h+XDdGZsSlDPv6qoryV/e3tGHlTIT0mbzJA==
+  dependencies:
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/iron-overlay-behavior@^3.0.0-pre.27", "@polymer/iron-overlay-behavior@^3.0.2":
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/@polymer/iron-overlay-behavior/-/iron-overlay-behavior-3.0.3.tgz#29c198e19e05bb2bcf7d86d3c11848cb93301d00"
+  integrity sha512-Q/Fp0+uOQQ145ebZ7T8Cxl4m1tUKYjyymkjcL2rXUm+aDQGb1wA1M1LYxUF5YBqd+9lipE0PTIiYwA2ZL/sznA==
+  dependencies:
+    "@polymer/iron-a11y-keys-behavior" "^3.0.0-pre.26"
+    "@polymer/iron-fit-behavior" "^3.0.0-pre.26"
+    "@polymer/iron-resizable-behavior" "^3.0.0-pre.26"
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/iron-resizable-behavior@^3.0.0-pre.26":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@polymer/iron-resizable-behavior/-/iron-resizable-behavior-3.0.1.tgz#e284348ed7c1c7e263f7039297532fa954025ea2"
+  integrity sha512-FyHxRxFspVoRaeZSWpT3y0C9awomb4tXXolIJcZ7RvXhMP632V5lez+ch5G5SwK0LpnAPkg35eB0LPMFv+YMMQ==
+  dependencies:
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/iron-selector@^3.0.0-pre.26", "@polymer/iron-selector@^3.0.1":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@polymer/iron-selector/-/iron-selector-3.0.1.tgz#e845bec58489c96b4e7609525532437869ad5a88"
+  integrity sha512-sBVk2uas6prW0glUe2xEJJYlvxmYzM40Au9OKbfDK2Qekou/fLKcBRyIYI39kuI8zWRaip8f3CI8qXcUHnKb1A==
+  dependencies:
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/iron-validatable-behavior@^3.0.0-pre.26":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@polymer/iron-validatable-behavior/-/iron-validatable-behavior-3.0.1.tgz#73538f005a07741c31b6fc1e981168c3d3e0d92b"
+  integrity sha512-wwpYh6wOa4fNI+jH5EYKC7TVPYQ2OfgQqocWat7GsNWcsblKYhLYbwsvEY5nO0n2xKqNfZzDLrUom5INJN7msQ==
+  dependencies:
+    "@polymer/iron-meta" "^3.0.0-pre.26"
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/neon-animation@^3.0.0-pre.26":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@polymer/neon-animation/-/neon-animation-3.0.1.tgz#6658e4b524abc057477772a7473292493d366c24"
+  integrity sha512-cDDc0llpVCe0ATbDS3clDthI54Bc8YwZIeTGGmBJleKOvbRTUC5+ssJmRL+VwVh+VM5FlnQlx760ppftY3uprg==
+  dependencies:
+    "@polymer/iron-resizable-behavior" "^3.0.0-pre.26"
+    "@polymer/iron-selector" "^3.0.0-pre.26"
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/paper-behaviors@^3.0.0-pre.27":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@polymer/paper-behaviors/-/paper-behaviors-3.0.1.tgz#83f1cd06489f484c1b108a2967fb01952df722ad"
+  integrity sha512-6knhj69fPJejv8qR0kCSUY+Q0XjaUf0OSnkjRjmTJPAwSrRYtgqE+l6P1FfA+py1X/cUjgne9EF5rMZAKJIg1g==
+  dependencies:
+    "@polymer/iron-behaviors" "^3.0.0-pre.26"
+    "@polymer/iron-checked-element-behavior" "^3.0.0-pre.26"
+    "@polymer/paper-ripple" "^3.0.0-pre.26"
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/paper-button@^3.0.1":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@polymer/paper-button/-/paper-button-3.0.1.tgz#f13b019137e3f6ccc4d04d0b1f27f4830ea5774d"
+  integrity sha512-JRNBc+Oj9EWnmyLr7FcCr8T1KAnEHPh6mosln9BUdkM+qYaYsudSICh3cjTIbnj6AuF5OJidoLkM1dlyj0j6Zg==
+  dependencies:
+    "@polymer/iron-flex-layout" "^3.0.0-pre.26"
+    "@polymer/paper-behaviors" "^3.0.0-pre.27"
+    "@polymer/paper-styles" "^3.0.0-pre.26"
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/paper-dialog-behavior@^3.0.0-pre.26", "@polymer/paper-dialog-behavior@^3.0.1":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@polymer/paper-dialog-behavior/-/paper-dialog-behavior-3.0.1.tgz#819b2fbb9444c1c318ddf55f02819bb29a85657b"
+  integrity sha512-wbI4kCK8le/9MHT+IXzvHjoatxf3kd3Yn0tgozAiAwfSZ7N4Ubpi5MHrK0m9S9PeIxKokAgBYdTUrezSE5378A==
+  dependencies:
+    "@polymer/iron-overlay-behavior" "^3.0.0-pre.27"
+    "@polymer/paper-styles" "^3.0.0-pre.26"
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/paper-dialog-scrollable@^3.0.1":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@polymer/paper-dialog-scrollable/-/paper-dialog-scrollable-3.0.1.tgz#42fd30380320e6dd6d4d68b2ac4e45ee9e5e024f"
+  integrity sha512-1E8B9kNdL58jUrJ/BwqJeOoNVcxNrB559z//d1V0rVHWT5bWCCZegwS3G06iFK5MjxWFbIKzleVTLrT0opiZkA==
+  dependencies:
+    "@polymer/iron-flex-layout" "^3.0.0-pre.26"
+    "@polymer/paper-dialog-behavior" "^3.0.0-pre.26"
+    "@polymer/paper-styles" "^3.0.0-pre.26"
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/paper-dialog@^3.0.1":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@polymer/paper-dialog/-/paper-dialog-3.0.1.tgz#728ebdbfc4d35ec1485e543434cef5dba476f15e"
+  integrity sha512-KvglYbEq7AWJvui2j6WKLnOvgVMeGjovAydGrPRj7kVzCiD49Eq/hpYFJTRV5iDcalWH+mORUpw+jrFnG9+Kgw==
+  dependencies:
+    "@polymer/iron-overlay-behavior" "^3.0.0-pre.27"
+    "@polymer/neon-animation" "^3.0.0-pre.26"
+    "@polymer/paper-dialog-behavior" "^3.0.0-pre.26"
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/paper-icon-button@^3.0.0-pre.26":
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/@polymer/paper-icon-button/-/paper-icon-button-3.0.2.tgz#a1254faadc2c8dd135ce1ae33bcc161a94c31f65"
+  integrity sha512-kOdxQgnKL097bggFF6PWvsBYuWg+MCcoHoTHX6bh/MuZoWFZNjrFntFqwuB4oEbpjCpfm4moA33muPJFj7CihQ==
+  dependencies:
+    "@polymer/iron-icon" "^3.0.0-pre.26"
+    "@polymer/paper-behaviors" "^3.0.0-pre.27"
+    "@polymer/paper-styles" "^3.0.0-pre.26"
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/paper-input@^3.0.2":
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/@polymer/paper-input/-/paper-input-3.2.0.tgz#a07dbc1b009bac97a5a86eccb57d99b17bd96285"
+  integrity sha512-vYEBxq6LDR+QGDrAO/il0JNhCd+31TwSnv58MVV+ijaGKz1qAuSJw4NSsgF3lrXCwomqnpME19vbp2ktrcluVA==
+  dependencies:
+    "@polymer/iron-a11y-keys-behavior" "^3.0.0-pre.26"
+    "@polymer/iron-autogrow-textarea" "^3.0.0-pre.26"
+    "@polymer/iron-behaviors" "^3.0.0-pre.26"
+    "@polymer/iron-form-element-behavior" "^3.0.0-pre.26"
+    "@polymer/iron-input" "^3.0.0-pre.26"
+    "@polymer/paper-styles" "^3.0.0-pre.26"
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/paper-item@^3.0.1":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@polymer/paper-item/-/paper-item-3.0.1.tgz#05b3543483e556cd5532431cd1751a84343989b5"
+  integrity sha512-KTk2N+GsYiI/HuubL3sxebZ6tteQbBOAp4QVLAnbjSPmwl+mJSDWk+omuadesU0bpkCwaWVs3fHuQsmXxy4pkw==
+  dependencies:
+    "@polymer/iron-behaviors" "^3.0.0-pre.26"
+    "@polymer/iron-flex-layout" "^3.0.0-pre.26"
+    "@polymer/paper-styles" "^3.0.0-pre.26"
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/paper-listbox@^3.0.1":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@polymer/paper-listbox/-/paper-listbox-3.0.1.tgz#fe05094781b359e4afbc5bec89a07758a303a957"
+  integrity sha512-vMLWFpYcggAPmEDBmK+96fFefacOG3GLB1EguTn8+ZkqI+328hNfw1MzHjH68rgCIIUtjmm+9qgB1Sy/MN0a/A==
+  dependencies:
+    "@polymer/iron-behaviors" "^3.0.0-pre.26"
+    "@polymer/iron-menu-behavior" "^3.0.0-pre.26"
+    "@polymer/paper-styles" "^3.0.0-pre.26"
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/paper-ripple@^3.0.0-pre.26":
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/@polymer/paper-ripple/-/paper-ripple-3.0.2.tgz#52566f5ee367942022ceaa991368105d21403de5"
+  integrity sha512-DnLNvYIMsiayeICroYxx6Q6Hg1cUU8HN2sbutXazlemAlGqdq80qz3TIaVdbpbt/pvjcFGX2HtntMlPstCge8Q==
+  dependencies:
+    "@polymer/iron-a11y-keys-behavior" "^3.0.0-pre.26"
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/paper-styles@^3.0.0-pre.26":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@polymer/paper-styles/-/paper-styles-3.0.1.tgz#bd4962b83ab8432cd1cf197bb5222d3a08f135e1"
+  integrity sha512-y6hmObLqlCx602TQiSBKHqjwkE7xmDiFkoxdYGaNjtv4xcysOTdVJsDR/R9UHwIaxJ7gHlthMSykir1nv78++g==
+  dependencies:
+    "@polymer/font-roboto" "^3.0.1"
+    "@polymer/iron-flex-layout" "^3.0.0-pre.26"
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/paper-tabs@^3.1.0":
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/@polymer/paper-tabs/-/paper-tabs-3.1.0.tgz#a173839d20703fdd5fca97a9d878f7b0e6257150"
+  integrity sha512-t8G+3CiyI0R+wA077UNQXR/oG9GlsqRRO1KMsFHHjBSsYqWXghNsqxUG827wEj+PafI5u9tZ3vVt1S++Lg4B2g==
+  dependencies:
+    "@polymer/iron-behaviors" "^3.0.0-pre.26"
+    "@polymer/iron-flex-layout" "^3.0.0-pre.26"
+    "@polymer/iron-icon" "^3.0.0-pre.26"
+    "@polymer/iron-iconset-svg" "^3.0.0-pre.26"
+    "@polymer/iron-menu-behavior" "^3.0.0-pre.26"
+    "@polymer/iron-resizable-behavior" "^3.0.0-pre.26"
+    "@polymer/paper-behaviors" "^3.0.0-pre.27"
+    "@polymer/paper-icon-button" "^3.0.0-pre.26"
+    "@polymer/paper-styles" "^3.0.0-pre.26"
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/paper-toggle-button@^3.0.1":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@polymer/paper-toggle-button/-/paper-toggle-button-3.0.1.tgz#7d855420f0df96e7f812a9f1bdcfbc5ab082e819"
+  integrity sha512-jadZB60fycT7YnSAH0H23LYo6/2HYmMZTtNr9LpdSIRFPLX6mqqxewex92cFz019bMKaRJgORn308hRlJo2u6A==
+  dependencies:
+    "@polymer/iron-checked-element-behavior" "^3.0.0-pre.26"
+    "@polymer/paper-behaviors" "^3.0.0-pre.27"
+    "@polymer/paper-styles" "^3.0.0-pre.26"
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/polymer@^3.0.0", "@polymer/polymer@^3.0.2", "@polymer/polymer@^3.3.0":
+  version "3.3.1"
+  resolved "https://registry.yarnpkg.com/@polymer/polymer/-/polymer-3.3.1.tgz#9ad48992d2a96775f80b0673f3a615d6df8a3dfc"
+  integrity sha512-8KaB48tzyMjdsHdxo5KvCAaqmTe7rYDzQAoj/pyEfq9Fp4YfUaS+/xqwYj0GbiDAUNzwkmEQ7dw9cgnRNdKO8A==
+  dependencies:
+    "@webcomponents/shadycss" "^1.9.1"
+
+"@webcomponents/shadycss@^1.9.1", "@webcomponents/shadycss@^1.9.2":
+  version "1.9.4"
+  resolved "https://registry.yarnpkg.com/@webcomponents/shadycss/-/shadycss-1.9.4.tgz#4f9d8ea1526bab084c60b53d4854dc39fdb2bb48"
+  integrity sha512-tgNcVEaKssyeZPbUBjVQf4aryO5Fi7fxRvOxV982ZJuRVDcefmIblBh0SXAbcvAAlQ2zpNEP4SuQUnr8uApIpw==
+
+"@webcomponents/webcomponentsjs@^1.3.3":
+  version "1.3.3"
+  resolved "https://registry.yarnpkg.com/@webcomponents/webcomponentsjs/-/webcomponentsjs-1.3.3.tgz#5bb82a0d3210c836bd4623e13a4a93145cb9dc27"
+  integrity sha512-eLH04VBMpuZGzBIhOnUjECcQPEPcmfhWEijW9u1B5I+2PPYdWf3vWUExdDxu4Y3GljRSTCOlWnGtS9tpzmXMyQ==
+
+"@webcomponents/webcomponentsjs@^2.0.3":
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/@webcomponents/webcomponentsjs/-/webcomponentsjs-2.4.1.tgz#7baadec56ed2fd79b94ddfd509132d8c0c295c5c"
+  integrity sha512-7jxBb+KoWncKb/JGFyTY40PjV4yRx2zd35ZLuvRP+6WndJDL7X32ZIZ7bN3sSQIl+NzJkCo7chfXJyzn+6WZaQ==
+
+"ba-linkify@file:../../lib/ba-linkify/src":
+  version "1.0.0"
+
+es6-promise@^4.2.8:
+  version "4.2.8"
+  resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
+  integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==
+
+isarray@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
+  integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
+
+moment@^2.24.0:
+  version "2.24.0"
+  resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
+  integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==
+
+page@^1.11.5:
+  version "1.11.5"
+  resolved "https://registry.yarnpkg.com/page/-/page-1.11.5.tgz#0cfc8608be337f26f4377f31df0787aef0ca1af7"
+  integrity sha512-0JXUHc7Y8p1cPJQbhZSwaKO3p+bU3Rgny+OM5gJMKHWHvJKan/fsE5RUzEjRQolv9DzPOSVWfSOHz0lLxK19eA==
+  dependencies:
+    path-to-regexp "~1.2.1"
+
+path-to-regexp@~1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.2.1.tgz#b33705c140234d873c8721c7b9fd8b541ed3aff9"
+  integrity sha1-szcFwUAjTYc8hyHHuf2LVB7Tr/k=
+  dependencies:
+    isarray "0.0.1"
+
+"polymer-bridges@file:../../polymer-bridges":
+  version "1.0.0"
+
+polymer-resin@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/polymer-resin/-/polymer-resin-2.0.1.tgz#08abcf0ea47bac746450cefa96caab1ebea199a8"
+  integrity sha512-Vak/4JiuToOKzvvjzcpISoFAlI7AwbOk79bZhqWNAZcqdzqEeFwos5hytjLV90d00TzVbff1LREaFpWR35zOjg==
+  dependencies:
+    "@polymer/polymer" "^3.0.2"
+    "@webcomponents/webcomponentsjs" "^2.0.3"
+
+whatwg-fetch@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb"
+  integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==
diff --git a/polygerrit-ui/package.json b/polygerrit-ui/package.json
new file mode 100644
index 0000000..3d35e3e
--- /dev/null
+++ b/polygerrit-ui/package.json
@@ -0,0 +1,15 @@
+{
+  "name": "polygerrit-ui-dev-dependencies",
+  "description": "Gerrit Code Review - Polygerrit dev dependencies",
+  "browser": true,
+  "dependencies": {},
+  "devDependencies": {
+    "@polymer/iron-test-helpers": "^3.0.1",
+    "chai": "^4.2.0",
+    "mocha": "^6.2.2",
+    "wct-browser-legacy": "^1.0.2",
+    "web-component-tester": "^6.9.2"
+  },
+  "license": "Apache-2.0",
+  "private": true
+}
diff --git a/polygerrit-ui/server.go b/polygerrit-ui/server.go
index ba52ce8..ad03e51 100644
--- a/polygerrit-ui/server.go
+++ b/polygerrit-ui/server.go
@@ -46,6 +46,36 @@
 	bundledPluginsPattern = regexp.MustCompile("https://cdn.googlesource.com/polygerrit_assets/[0-9.]*")
 )
 
+type redirectTarget struct {
+	NpmModule string            `json:"npm_module"`
+	Dir       string            `json:"dir"`
+	Files     map[string]string `json:"files"`
+}
+
+type redirects struct {
+	From string         `json:"from"`
+	To   redirectTarget `json:"to"`
+}
+
+type redirectsJson struct {
+	Redirects []redirects `json:"redirects"`
+}
+
+func readRedirects() []redirects {
+	redirectsFile, err := os.Open("app/redirects.json")
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer redirectsFile.Close()
+	redirectsFileContent, err := ioutil.ReadAll(redirectsFile)
+	if err != nil {
+		log.Fatal(err)
+	}
+	var result redirectsJson
+	json.Unmarshal([]byte(redirectsFileContent), &result)
+	return result.Redirects
+}
+
 func main() {
 	flag.Parse()
 
@@ -54,21 +84,22 @@
 		log.Fatal(err)
 	}
 
-	componentsArchive, err := openDataArchive("app/test_components.zip")
-	if err != nil {
-		log.Fatal(err)
-	}
-
 	workspace := os.Getenv("BUILD_WORKSPACE_DIRECTORY")
 	if err := os.Chdir(filepath.Join(workspace, "polygerrit-ui")); err != nil {
 		log.Fatal(err)
 	}
 
-	http.Handle("/", http.FileServer(http.Dir("app")))
-	http.Handle("/bower_components/",
-		http.FileServer(httpfs.New(zipfs.New(componentsArchive, "bower_components"))))
+	redirects := readRedirects()
+
+	dirListingMux := http.NewServeMux()
+	dirListingMux.Handle("/styles/", http.StripPrefix("/styles/", http.FileServer(http.Dir("app/styles"))))
+	dirListingMux.Handle("/elements/", http.StripPrefix("/elements/", http.FileServer(http.Dir("app/elements"))))
+	dirListingMux.Handle("/behaviors/", http.StripPrefix("/behaviors/", http.FileServer(http.Dir("app/behaviors"))))
+
+	http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { handleSrcRequest(redirects, dirListingMux, w, req) })
+
 	http.Handle("/fonts/",
-		http.FileServer(httpfs.New(zipfs.New(fontsArchive, "fonts"))))
+		addDevHeadersMiddleware(http.FileServer(httpfs.New(zipfs.New(fontsArchive, "fonts")))))
 
 	http.HandleFunc("/index.html", handleIndex)
 	http.HandleFunc("/changes/", handleProxy)
@@ -92,6 +123,120 @@
 	log.Fatal(http.ListenAndServe(*port, &server{}))
 }
 
+func addDevHeadersMiddleware(h http.Handler) http.Handler {
+	return http.HandlerFunc(func(writer http.ResponseWriter, req *http.Request) {
+		addDevHeaders(writer)
+		h.ServeHTTP(writer, req)
+	})
+}
+
+func addDevHeaders(writer http.ResponseWriter) {
+	writer.Header().Set("Access-Control-Allow-Origin", "*")
+	writer.Header().Set("Cache-Control", "public, max-age=10, must-revalidate")
+
+}
+
+func getFinalPath(redirects []redirects, originalPath string) string {
+	testComponentsPrefix := "/components/"
+	if strings.HasPrefix(originalPath, testComponentsPrefix) {
+		return "/../node_modules/" + originalPath[len(testComponentsPrefix):]
+	}
+
+	for _, redirect := range redirects {
+		fromDir := redirect.From
+		if !strings.HasSuffix(fromDir, "/") {
+			fromDir = fromDir + "/"
+		}
+		if strings.HasPrefix(originalPath, fromDir) {
+			targetDir := ""
+			if redirect.To.NpmModule != "" {
+				targetDir = "node_modules/" + redirect.To.NpmModule
+			} else {
+				targetDir = redirect.To.Dir
+			}
+			if !strings.HasSuffix(targetDir, "/") {
+				targetDir = targetDir + "/"
+			}
+			if !strings.HasPrefix(targetDir, "/") {
+				targetDir = "/" + targetDir
+			}
+			filename := originalPath[len(fromDir):]
+			if redirect.To.Files != nil {
+				newfilename, found := redirect.To.Files[filename]
+				if found {
+					filename = newfilename
+				}
+			}
+			return targetDir + filename
+		}
+	}
+	return originalPath
+}
+
+func handleSrcRequest(redirects []redirects, dirListingMux *http.ServeMux, writer http.ResponseWriter, originalRequest *http.Request) {
+	parsedUrl, err := url.Parse(originalRequest.RequestURI)
+	if err != nil {
+		writer.WriteHeader(500)
+		return
+	}
+	if parsedUrl.Path != "/" && strings.HasSuffix(parsedUrl.Path, "/") {
+		dirListingMux.ServeHTTP(writer, originalRequest)
+		return
+	}
+	if parsedUrl.Path == "/bower_components/web-component-tester/browser.js" {
+		http.Redirect(writer, originalRequest, "/bower_components/wct-browser-legacy/browser.js", 301)
+		return
+	}
+
+	requestPath := getFinalPath(redirects, parsedUrl.Path)
+
+	if !strings.HasPrefix(requestPath, "/") {
+		requestPath = "/" + requestPath
+	}
+
+	data, err := readFile(parsedUrl.Path, requestPath)
+	if err != nil {
+		writer.WriteHeader(404)
+		return
+	}
+	if strings.HasSuffix(requestPath, ".js") {
+		r := regexp.MustCompile("(?m)^(import.*)'([^/.].*)';$")
+		data = r.ReplaceAll(data, []byte("$1 '/node_modules/$2'"))
+		writer.Header().Set("Content-Type", "application/javascript")
+	} else if strings.HasSuffix(requestPath, ".css") {
+		writer.Header().Set("Content-Type", "text/css")
+	} else if strings.HasSuffix(requestPath, ".html") {
+		writer.Header().Set("Content-Type", "text/html")
+	}
+	writer.WriteHeader(200)
+	addDevHeaders(writer)
+	writer.Write(data)
+}
+
+func readFile(originalPath string, redirectedPath string) ([]byte, error) {
+	pathsToTry := []string{"app" + redirectedPath}
+	bowerComponentsSuffix := "/bower_components/"
+	nodeModulesPrefix := "/node_modules/"
+
+	if strings.HasPrefix(originalPath, bowerComponentsSuffix) {
+		pathsToTry = append(pathsToTry, "node_modules/wct-browser-legacy/node_modules/"+originalPath[len(bowerComponentsSuffix):])
+		pathsToTry = append(pathsToTry, "node_modules/"+originalPath[len(bowerComponentsSuffix):])
+	}
+
+	if strings.HasPrefix(originalPath, nodeModulesPrefix) {
+		pathsToTry = append(pathsToTry, "node_modules/"+originalPath[len(nodeModulesPrefix):])
+	}
+
+	for _, path := range pathsToTry {
+		data, err := ioutil.ReadFile(path)
+		if err == nil {
+			return data, nil
+		}
+	}
+
+	return nil, errors.New("File not found")
+}
+
 func openDataArchive(path string) (*zip.ReadCloser, error) {
 	absBinPath, err := resourceBasePath()
 	if err != nil {
@@ -318,6 +463,7 @@
 		return
 	}
 	w.Header().Set("Content-Encoding", "gzip")
+	addDevHeaders(w)
 	gzw := newGzipResponseWriter(w)
 	defer gzw.Close()
 	http.DefaultServeMux.ServeHTTP(gzw, r)
diff --git a/polygerrit-ui/wct.conf.js b/polygerrit-ui/wct.conf.js
index b6a6251..2096e60 100644
--- a/polygerrit-ui/wct.conf.js
+++ b/polygerrit-ui/wct.conf.js
@@ -1,3 +1,20 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 var path = require('path');
 
 var ret = {
diff --git a/polygerrit-ui/yarn.lock b/polygerrit-ui/yarn.lock
new file mode 100644
index 0000000..12d39aa
--- /dev/null
+++ b/polygerrit-ui/yarn.lock
@@ -0,0 +1,6828 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@babel/code-frame@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e"
+  integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==
+  dependencies:
+    "@babel/highlight" "^7.8.3"
+
+"@babel/core@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.3.tgz#30b0ebb4dd1585de6923a0b4d179e0b9f5d82941"
+  integrity sha512-4XFkf8AwyrEG7Ziu3L2L0Cv+WyY47Tcsp70JFmpftbAA1K7YL/sgE9jh9HyNj08Y/U50ItUchpN0w6HxAoX1rA==
+  dependencies:
+    "@babel/code-frame" "^7.8.3"
+    "@babel/generator" "^7.8.3"
+    "@babel/helpers" "^7.8.3"
+    "@babel/parser" "^7.8.3"
+    "@babel/template" "^7.8.3"
+    "@babel/traverse" "^7.8.3"
+    "@babel/types" "^7.8.3"
+    convert-source-map "^1.7.0"
+    debug "^4.1.0"
+    gensync "^1.0.0-beta.1"
+    json5 "^2.1.0"
+    lodash "^4.17.13"
+    resolve "^1.3.2"
+    semver "^5.4.1"
+    source-map "^0.5.0"
+
+"@babel/generator@^7.0.0-beta.42", "@babel/generator@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.3.tgz#0e22c005b0a94c1c74eafe19ef78ce53a4d45c03"
+  integrity sha512-WjoPk8hRpDRqqzRpvaR8/gDUPkrnOOeuT2m8cNICJtZH6mwaCo3v0OKMI7Y6SM1pBtyijnLtAL0HDi41pf41ug==
+  dependencies:
+    "@babel/types" "^7.8.3"
+    jsesc "^2.5.1"
+    lodash "^4.17.13"
+    source-map "^0.5.0"
+
+"@babel/helper-annotate-as-pure@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz#60bc0bc657f63a0924ff9a4b4a0b24a13cf4deee"
+  integrity sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw==
+  dependencies:
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-builder-binary-assignment-operator-visitor@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.8.3.tgz#c84097a427a061ac56a1c30ebf54b7b22d241503"
+  integrity sha512-5eFOm2SyFPK4Rh3XMMRDjN7lBH0orh3ss0g3rTYZnBQ+r6YPj7lgDyCvPphynHvUrobJmeMignBr6Acw9mAPlw==
+  dependencies:
+    "@babel/helper-explode-assignable-expression" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-call-delegate@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.8.3.tgz#de82619898aa605d409c42be6ffb8d7204579692"
+  integrity sha512-6Q05px0Eb+N4/GTyKPPvnkig7Lylw+QzihMpws9iiZQv7ZImf84ZsZpQH7QoWN4n4tm81SnSzPgHw2qtO0Zf3A==
+  dependencies:
+    "@babel/helper-hoist-variables" "^7.8.3"
+    "@babel/traverse" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-create-regexp-features-plugin@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.3.tgz#c774268c95ec07ee92476a3862b75cc2839beb79"
+  integrity sha512-Gcsm1OHCUr9o9TcJln57xhWHtdXbA2pgQ58S0Lxlks0WMGNXuki4+GLfX0p+L2ZkINUGZvfkz8rzoqJQSthI+Q==
+  dependencies:
+    "@babel/helper-regex" "^7.8.3"
+    regexpu-core "^4.6.0"
+
+"@babel/helper-define-map@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz#a0655cad5451c3760b726eba875f1cd8faa02c15"
+  integrity sha512-PoeBYtxoZGtct3md6xZOCWPcKuMuk3IHhgxsRRNtnNShebf4C8YonTSblsK4tvDbm+eJAw2HAPOfCr+Q/YRG/g==
+  dependencies:
+    "@babel/helper-function-name" "^7.8.3"
+    "@babel/types" "^7.8.3"
+    lodash "^4.17.13"
+
+"@babel/helper-explode-assignable-expression@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.8.3.tgz#a728dc5b4e89e30fc2dfc7d04fa28a930653f982"
+  integrity sha512-N+8eW86/Kj147bO9G2uclsg5pwfs/fqqY5rwgIL7eTBklgXjcOJ3btzS5iM6AitJcftnY7pm2lGsrJVYLGjzIw==
+  dependencies:
+    "@babel/traverse" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-function-name@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz#eeeb665a01b1f11068e9fb86ad56a1cb1a824cca"
+  integrity sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==
+  dependencies:
+    "@babel/helper-get-function-arity" "^7.8.3"
+    "@babel/template" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-get-function-arity@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5"
+  integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==
+  dependencies:
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-hoist-variables@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.8.3.tgz#1dbe9b6b55d78c9b4183fc8cdc6e30ceb83b7134"
+  integrity sha512-ky1JLOjcDUtSc+xkt0xhYff7Z6ILTAHKmZLHPxAhOP0Nd77O+3nCsd6uSVYur6nJnCI029CrNbYlc0LoPfAPQg==
+  dependencies:
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-member-expression-to-functions@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz#659b710498ea6c1d9907e0c73f206eee7dadc24c"
+  integrity sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA==
+  dependencies:
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-module-imports@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz#7fe39589b39c016331b6b8c3f441e8f0b1419498"
+  integrity sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg==
+  dependencies:
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-module-transforms@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.8.3.tgz#d305e35d02bee720fbc2c3c3623aa0c316c01590"
+  integrity sha512-C7NG6B7vfBa/pwCOshpMbOYUmrYQDfCpVL/JCRu0ek8B5p8kue1+BCXpg2vOYs7w5ACB9GTOBYQ5U6NwrMg+3Q==
+  dependencies:
+    "@babel/helper-module-imports" "^7.8.3"
+    "@babel/helper-simple-access" "^7.8.3"
+    "@babel/helper-split-export-declaration" "^7.8.3"
+    "@babel/template" "^7.8.3"
+    "@babel/types" "^7.8.3"
+    lodash "^4.17.13"
+
+"@babel/helper-optimise-call-expression@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9"
+  integrity sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ==
+  dependencies:
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz#9ea293be19babc0f52ff8ca88b34c3611b208670"
+  integrity sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==
+
+"@babel/helper-regex@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.8.3.tgz#139772607d51b93f23effe72105b319d2a4c6965"
+  integrity sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ==
+  dependencies:
+    lodash "^4.17.13"
+
+"@babel/helper-remap-async-to-generator@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.8.3.tgz#273c600d8b9bf5006142c1e35887d555c12edd86"
+  integrity sha512-kgwDmw4fCg7AVgS4DukQR/roGp+jP+XluJE5hsRZwxCYGg+Rv9wSGErDWhlI90FODdYfd4xG4AQRiMDjjN0GzA==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.8.3"
+    "@babel/helper-wrap-function" "^7.8.3"
+    "@babel/template" "^7.8.3"
+    "@babel/traverse" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-replace-supers@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.3.tgz#91192d25f6abbcd41da8a989d4492574fb1530bc"
+  integrity sha512-xOUssL6ho41U81etpLoT2RTdvdus4VfHamCuAm4AHxGr+0it5fnwoVdwUJ7GFEqCsQYzJUhcbsN9wB9apcYKFA==
+  dependencies:
+    "@babel/helper-member-expression-to-functions" "^7.8.3"
+    "@babel/helper-optimise-call-expression" "^7.8.3"
+    "@babel/traverse" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-simple-access@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz#7f8109928b4dab4654076986af575231deb639ae"
+  integrity sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw==
+  dependencies:
+    "@babel/template" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-split-export-declaration@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9"
+  integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==
+  dependencies:
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-wrap-function@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz#9dbdb2bb55ef14aaa01fe8c99b629bd5352d8610"
+  integrity sha512-LACJrbUET9cQDzb6kG7EeD7+7doC3JNvUgTEQOx2qaO1fKlzE/Bf05qs9w1oXQMmXlPO65lC3Tq9S6gZpTErEQ==
+  dependencies:
+    "@babel/helper-function-name" "^7.8.3"
+    "@babel/template" "^7.8.3"
+    "@babel/traverse" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/helpers@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.8.3.tgz#382fbb0382ce7c4ce905945ab9641d688336ce85"
+  integrity sha512-LmU3q9Pah/XyZU89QvBgGt+BCsTPoQa+73RxAQh8fb8qkDyIfeQnmgs+hvzhTCKTzqOyk7JTkS3MS1S8Mq5yrQ==
+  dependencies:
+    "@babel/template" "^7.8.3"
+    "@babel/traverse" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/highlight@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.8.3.tgz#28f173d04223eaaa59bc1d439a3836e6d1265797"
+  integrity sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==
+  dependencies:
+    chalk "^2.0.0"
+    esutils "^2.0.2"
+    js-tokens "^4.0.0"
+
+"@babel/parser@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.3.tgz#790874091d2001c9be6ec426c2eed47bc7679081"
+  integrity sha512-/V72F4Yp/qmHaTALizEm9Gf2eQHV3QyTL3K0cNfijwnMnb1L+LDlAubb/ZnSdGAVzVSWakujHYs1I26x66sMeQ==
+
+"@babel/plugin-external-helpers@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-external-helpers/-/plugin-external-helpers-7.8.3.tgz#5a94164d9af393b2820a3cdc407e28ebf237de4b"
+  integrity sha512-mx0WXDDiIl5DwzMtzWGRSPugXi9BxROS05GQrhLNbEamhBiicgn994ibwkyiBH+6png7bm/yA7AUsvHyCXi4Vw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-proposal-async-generator-functions@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz#bad329c670b382589721b27540c7d288601c6e6f"
+  integrity sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+    "@babel/helper-remap-async-to-generator" "^7.8.3"
+    "@babel/plugin-syntax-async-generators" "^7.8.0"
+
+"@babel/plugin-proposal-object-rest-spread@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.8.3.tgz#eb5ae366118ddca67bed583b53d7554cad9951bb"
+  integrity sha512-8qvuPwU/xxUCt78HocNlv0mXXo0wdh9VT1R04WU8HGOfaOob26pF+9P5/lYjN/q7DHOX1bvX60hnhOvuQUJdbA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+    "@babel/plugin-syntax-object-rest-spread" "^7.8.0"
+
+"@babel/plugin-syntax-async-generators@^7.0.0", "@babel/plugin-syntax-async-generators@^7.8.0":
+  version "7.8.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
+  integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-dynamic-import@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3"
+  integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-import-meta@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.8.3.tgz#230afff79d3ccc215b5944b438e4e266daf3d84d"
+  integrity sha512-vYiGd4wQ9gx0Lngb7+bPCwQXGK/PR6FeTIJ+TIOlq+OfOKG/kCAOO2+IBac3oMM9qV7/fU76hfcqxUaLKZf1hQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.8.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871"
+  integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-transform-arrow-functions@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz#82776c2ed0cd9e1a49956daeb896024c9473b8b6"
+  integrity sha512-0MRF+KC8EqH4dbuITCWwPSzsyO3HIWWlm30v8BbbpOrS1B++isGxPnnuq/IZvOX5J2D/p7DQalQm+/2PnlKGxg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-async-to-generator@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz#4308fad0d9409d71eafb9b1a6ee35f9d64b64086"
+  integrity sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ==
+  dependencies:
+    "@babel/helper-module-imports" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+    "@babel/helper-remap-async-to-generator" "^7.8.3"
+
+"@babel/plugin-transform-block-scoped-functions@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz#437eec5b799b5852072084b3ae5ef66e8349e8a3"
+  integrity sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-block-scoping@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz#97d35dab66857a437c166358b91d09050c868f3a"
+  integrity sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+    lodash "^4.17.13"
+
+"@babel/plugin-transform-classes@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.3.tgz#46fd7a9d2bb9ea89ce88720477979fe0d71b21b8"
+  integrity sha512-SjT0cwFJ+7Rbr1vQsvphAHwUHvSUPmMjMU/0P59G8U2HLFqSa082JO7zkbDNWs9kH/IUqpHI6xWNesGf8haF1w==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.8.3"
+    "@babel/helper-define-map" "^7.8.3"
+    "@babel/helper-function-name" "^7.8.3"
+    "@babel/helper-optimise-call-expression" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+    "@babel/helper-replace-supers" "^7.8.3"
+    "@babel/helper-split-export-declaration" "^7.8.3"
+    globals "^11.1.0"
+
+"@babel/plugin-transform-computed-properties@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz#96d0d28b7f7ce4eb5b120bb2e0e943343c86f81b"
+  integrity sha512-O5hiIpSyOGdrQZRQ2ccwtTVkgUDBBiCuK//4RJ6UfePllUTCENOzKxfh6ulckXKc0DixTFLCfb2HVkNA7aDpzA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-destructuring@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.3.tgz#20ddfbd9e4676906b1056ee60af88590cc7aaa0b"
+  integrity sha512-H4X646nCkiEcHZUZaRkhE2XVsoz0J/1x3VVujnn96pSoGCtKPA99ZZA+va+gK+92Zycd6OBKCD8tDb/731bhgQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-duplicate-keys@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.8.3.tgz#8d12df309aa537f272899c565ea1768e286e21f1"
+  integrity sha512-s8dHiBUbcbSgipS4SMFuWGqCvyge5V2ZeAWzR6INTVC3Ltjig/Vw1G2Gztv0vU/hRG9X8IvKvYdoksnUfgXOEQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-exponentiation-operator@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.8.3.tgz#581a6d7f56970e06bf51560cd64f5e947b70d7b7"
+  integrity sha512-zwIpuIymb3ACcInbksHaNcR12S++0MDLKkiqXHl3AzpgdKlFNhog+z/K0+TGW+b0w5pgTq4H6IwV/WhxbGYSjQ==
+  dependencies:
+    "@babel/helper-builder-binary-assignment-operator-visitor" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-for-of@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.3.tgz#15f17bce2fc95c7d59a24b299e83e81cedc22e18"
+  integrity sha512-ZjXznLNTxhpf4Q5q3x1NsngzGA38t9naWH8Gt+0qYZEJAcvPI9waSStSh56u19Ofjr7QmD0wUsQ8hw8s/p1VnA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-function-name@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz#279373cb27322aaad67c2683e776dfc47196ed8b"
+  integrity sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ==
+  dependencies:
+    "@babel/helper-function-name" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-instanceof@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-instanceof/-/plugin-transform-instanceof-7.8.3.tgz#a44d7d71590da36be7429573300618aefd784c3d"
+  integrity sha512-c/jB6Ebe2u17hxo+rce6PDgbkuHyfcJOleqgHYttnvMrCsxVwUnYsMq7GhxXekzUQsv9IImhv6YICKihpen+Ag==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-literals@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz#aef239823d91994ec7b68e55193525d76dbd5dc1"
+  integrity sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-modules-amd@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.8.3.tgz#65606d44616b50225e76f5578f33c568a0b876a5"
+  integrity sha512-MadJiU3rLKclzT5kBH4yxdry96odTUwuqrZM+GllFI/VhxfPz+k9MshJM+MwhfkCdxxclSbSBbUGciBngR+kEQ==
+  dependencies:
+    "@babel/helper-module-transforms" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+    babel-plugin-dynamic-import-node "^2.3.0"
+
+"@babel/plugin-transform-object-super@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz#ebb6a1e7a86ffa96858bd6ac0102d65944261725"
+  integrity sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+    "@babel/helper-replace-supers" "^7.8.3"
+
+"@babel/plugin-transform-parameters@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.3.tgz#7890576a13b17325d8b7d44cb37f21dc3bbdda59"
+  integrity sha512-/pqngtGb54JwMBZ6S/D3XYylQDFtGjWrnoCF4gXZOUpFV/ujbxnoNGNvDGu6doFWRPBveE72qTx/RRU44j5I/Q==
+  dependencies:
+    "@babel/helper-call-delegate" "^7.8.3"
+    "@babel/helper-get-function-arity" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-regenerator@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.3.tgz#b31031e8059c07495bf23614c97f3d9698bc6ec8"
+  integrity sha512-qt/kcur/FxrQrzFR432FGZznkVAjiyFtCOANjkAKwCbt465L6ZCiUQh2oMYGU3Wo8LRFJxNDFwWn106S5wVUNA==
+  dependencies:
+    regenerator-transform "^0.14.0"
+
+"@babel/plugin-transform-shorthand-properties@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz#28545216e023a832d4d3a1185ed492bcfeac08c8"
+  integrity sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-spread@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.8.3.tgz#9c8ffe8170fdfb88b114ecb920b82fb6e95fe5e8"
+  integrity sha512-CkuTU9mbmAoFOI1tklFWYYbzX5qCIZVXPVy0jpXgGwkplCndQAa58s2jr66fTeQnA64bDox0HL4U56CFYoyC7g==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-sticky-regex@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz#be7a1290f81dae767475452199e1f76d6175b100"
+  integrity sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+    "@babel/helper-regex" "^7.8.3"
+
+"@babel/plugin-transform-template-literals@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.8.3.tgz#7bfa4732b455ea6a43130adc0ba767ec0e402a80"
+  integrity sha512-820QBtykIQOLFT8NZOcTRJ1UNuztIELe4p9DCgvj4NK+PwluSJ49we7s9FB1HIGNIYT7wFUJ0ar2QpCDj0escQ==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-typeof-symbol@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.3.tgz#5cffb216fb25c8c64ba6bf5f76ce49d3ab079f4d"
+  integrity sha512-3TrkKd4LPqm4jHs6nPtSDI/SV9Cm5PRJkHLUgTcqRQQTMAZ44ZaAdDZJtvWFSaRcvT0a1rTmJ5ZA5tDKjleF3g==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-unicode-regex@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz#0cef36e3ba73e5c57273effb182f46b91a1ecaad"
+  integrity sha512-+ufgJjYdmWfSQ+6NS9VGUR2ns8cjJjYbrbi11mZBTaWm+Fui/ncTLFF28Ei1okavY+xkojGr1eJxNsWYeA5aZw==
+  dependencies:
+    "@babel/helper-create-regexp-features-plugin" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/template@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.3.tgz#e02ad04fe262a657809327f578056ca15fd4d1b8"
+  integrity sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==
+  dependencies:
+    "@babel/code-frame" "^7.8.3"
+    "@babel/parser" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/traverse@^7.0.0", "@babel/traverse@^7.0.0-beta.42", "@babel/traverse@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.3.tgz#a826215b011c9b4f73f3a893afbc05151358bf9a"
+  integrity sha512-we+a2lti+eEImHmEXp7bM9cTxGzxPmBiVJlLVD+FuuQMeeO7RaDbutbgeheDkw+Xe3mCfJHnGOWLswT74m2IPg==
+  dependencies:
+    "@babel/code-frame" "^7.8.3"
+    "@babel/generator" "^7.8.3"
+    "@babel/helper-function-name" "^7.8.3"
+    "@babel/helper-split-export-declaration" "^7.8.3"
+    "@babel/parser" "^7.8.3"
+    "@babel/types" "^7.8.3"
+    debug "^4.1.0"
+    globals "^11.1.0"
+    lodash "^4.17.13"
+
+"@babel/types@^7.0.0-beta.42", "@babel/types@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.3.tgz#5a383dffa5416db1b73dedffd311ffd0788fb31c"
+  integrity sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==
+  dependencies:
+    esutils "^2.0.2"
+    lodash "^4.17.13"
+    to-fast-properties "^2.0.0"
+
+"@polymer/esm-amd-loader@^1.0.0":
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/@polymer/esm-amd-loader/-/esm-amd-loader-1.0.4.tgz#4e77f2f59b29b01e0ad02aa83d33716cddc5f9f9"
+  integrity sha512-h+hqYkL+tQV/y2ESD5gFXMl5z4cC+XY1jTlBeGSBaTcj3VbB5OBEScbvRXm63NcEbBneQQYbHfBAXAkF9i9wIA==
+
+"@polymer/iron-test-helpers@^3.0.1":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@polymer/iron-test-helpers/-/iron-test-helpers-3.0.1.tgz#ec2b9c6567e2967a191b3d800a04b1167b2d1394"
+  integrity sha512-2R7dnGcW2eg95i7LhYWWUO4AlAk6qXsPnKoyeN2R1t0km0ECMx0jjwqeLwCo8/7LwuVPZSiarI4DK7jyU7fJLQ==
+  dependencies:
+    "@polymer/polymer" "^3.0.0"
+
+"@polymer/polymer@^3.0.0":
+  version "3.3.1"
+  resolved "https://registry.yarnpkg.com/@polymer/polymer/-/polymer-3.3.1.tgz#9ad48992d2a96775f80b0673f3a615d6df8a3dfc"
+  integrity sha512-8KaB48tzyMjdsHdxo5KvCAaqmTe7rYDzQAoj/pyEfq9Fp4YfUaS+/xqwYj0GbiDAUNzwkmEQ7dw9cgnRNdKO8A==
+  dependencies:
+    "@webcomponents/shadycss" "^1.9.1"
+
+"@polymer/sinonjs@^1.14.1":
+  version "1.17.1"
+  resolved "https://registry.yarnpkg.com/@polymer/sinonjs/-/sinonjs-1.17.1.tgz#e47d3785b7d0e8c29feb97f7e924b0fc597e2e9b"
+  integrity sha512-/U8F/cOTrbF2iVVYgINYmvKbtbexs+89Q3v8AaHADRYabTg7aOZGOb0RyWpOI+sUJt04kj63U4FwMhzW5r4wZA==
+
+"@polymer/test-fixture@^0.0.3":
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/@polymer/test-fixture/-/test-fixture-0.0.3.tgz#4443752697d4d9293bbc412ea0b5e4d341f149d9"
+  integrity sha1-REN1JpfU2Sk7vEEuoLXk00HxSdk=
+
+"@polymer/test-fixture@^3.0.0-pre.1":
+  version "3.0.0-pre.21"
+  resolved "https://registry.yarnpkg.com/@polymer/test-fixture/-/test-fixture-3.0.0-pre.21.tgz#85152207cb0bf57caebc191c80bb0fdb6952614e"
+  integrity sha512-IxzUe6YzaORzUksafHAXHprV29YncOJgr0+1zNAifl0/f+cb5iAd4IWUrnsnVFHG5UGTLjvis5RgV6vvIZPDrA==
+
+"@types/babel-generator@^6.25.1":
+  version "6.25.3"
+  resolved "https://registry.yarnpkg.com/@types/babel-generator/-/babel-generator-6.25.3.tgz#8f06caa12d0595a0538560abe771966d77d29286"
+  integrity sha512-pGgnuxVddKcYIc+VJkRDop7gxLhqclNKBdlsm/5Vp8d+37pQkkDK7fef8d9YYImRzw9xcojEPc18pUYnbxmjqA==
+  dependencies:
+    "@types/babel-types" "*"
+
+"@types/babel-traverse@^6.25.2", "@types/babel-traverse@^6.25.3":
+  version "6.25.5"
+  resolved "https://registry.yarnpkg.com/@types/babel-traverse/-/babel-traverse-6.25.5.tgz#6d293cf7523e48b524faa7b86dc3c488191484e5"
+  integrity sha512-WrMbwmu+MWf8FiUMbmVOGkc7bHPzndUafn1CivMaBHthBBoo0VNIcYk1KV71UovYguhsNOwf3UF5oRmkkGOU3w==
+  dependencies:
+    "@types/babel-types" "*"
+
+"@types/babel-types@*":
+  version "7.0.7"
+  resolved "https://registry.yarnpkg.com/@types/babel-types/-/babel-types-7.0.7.tgz#667eb1640e8039436028055737d2b9986ee336e3"
+  integrity sha512-dBtBbrc+qTHy1WdfHYjBwRln4+LWqASWakLHsWHR2NWHIFkv4W3O070IGoGLEBrJBvct3r0L1BUPuvURi7kYUQ==
+
+"@types/babel-types@^6.25.1":
+  version "6.25.2"
+  resolved "https://registry.yarnpkg.com/@types/babel-types/-/babel-types-6.25.2.tgz#5c57f45973e4f13742dbc5273dd84cffe7373a9e"
+  integrity sha512-+3bMuktcY4a70a0KZc8aPJlEOArPuAKQYHU5ErjkOqGJdx8xuEEVK6nWogqigBOJ8nKPxRpyCUDTCPmZ3bUxGA==
+
+"@types/babylon@^6.16.2":
+  version "6.16.5"
+  resolved "https://registry.yarnpkg.com/@types/babylon/-/babylon-6.16.5.tgz#1c5641db69eb8cdf378edd25b4be7754beeb48b4"
+  integrity sha512-xH2e58elpj1X4ynnKp9qSnWlsRTIs6n3tgLGNfwAGHwePw0mulHQllV34n0T25uYSu1k0hRKkWXF890B1yS47w==
+  dependencies:
+    "@types/babel-types" "*"
+
+"@types/bluebird@*":
+  version "3.5.29"
+  resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.29.tgz#7cd933c902c4fc83046517a1bef973886d00bdb6"
+  integrity sha512-kmVtnxTuUuhCET669irqQmPAez4KFnFVKvpleVRyfC3g+SHD1hIkFZcWLim9BVcwUBLO59o8VZE4yGCmTif8Yw==
+
+"@types/body-parser@*":
+  version "1.17.1"
+  resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.17.1.tgz#18fcf61768fb5c30ccc508c21d6fd2e8b3bf7897"
+  integrity sha512-RoX2EZjMiFMjZh9lmYrwgoP9RTpAjSHiJxdp4oidAQVO02T7HER3xj9UKue5534ULWeqVEkujhWcyvUce+d68w==
+  dependencies:
+    "@types/connect" "*"
+    "@types/node" "*"
+
+"@types/chai-subset@^1.3.0":
+  version "1.3.3"
+  resolved "https://registry.yarnpkg.com/@types/chai-subset/-/chai-subset-1.3.3.tgz#97893814e92abd2c534de422cb377e0e0bdaac94"
+  integrity sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==
+  dependencies:
+    "@types/chai" "*"
+
+"@types/chai@*":
+  version "4.2.7"
+  resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.7.tgz#1c8c25cbf6e59ffa7d6b9652c78e547d9a41692d"
+  integrity sha512-luq8meHGYwvky0O7u0eQZdA7B4Wd9owUCqvbw2m3XCrCU8mplYOujMBbvyS547AxJkC+pGnd0Cm15eNxEUNU8g==
+
+"@types/chalk@^0.4.30":
+  version "0.4.31"
+  resolved "https://registry.yarnpkg.com/@types/chalk/-/chalk-0.4.31.tgz#a31d74241a6b1edbb973cf36d97a2896834a51f9"
+  integrity sha1-ox10JBprHtu5c8822XooloNKUfk=
+
+"@types/clean-css@*":
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/@types/clean-css/-/clean-css-4.2.1.tgz#cb0134241ec5e6ede1b5344bc829668fd9871a8d"
+  integrity sha512-A1HQhQ0hkvqqByJMgg+Wiv9p9XdoYEzuwm11SVo1mX2/4PSdhjcrUlilJQoqLscIheC51t1D5g+EFWCXZ2VTQQ==
+  dependencies:
+    "@types/node" "*"
+
+"@types/clone@^0.1.30":
+  version "0.1.30"
+  resolved "https://registry.yarnpkg.com/@types/clone/-/clone-0.1.30.tgz#e7365648c1b42136a59c7d5040637b3b5c83b614"
+  integrity sha1-5zZWSMG0ITalnH1QQGN7O1yDthQ=
+
+"@types/compression@^0.0.33":
+  version "0.0.33"
+  resolved "https://registry.yarnpkg.com/@types/compression/-/compression-0.0.33.tgz#95dc733a2339aa846381d7f1377792d2553dc27d"
+  integrity sha1-ldxzOiM5qoRjgdfxN3eS0lU9wn0=
+  dependencies:
+    "@types/express" "*"
+
+"@types/connect@*":
+  version "3.4.33"
+  resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.33.tgz#31610c901eca573b8713c3330abc6e6b9f588546"
+  integrity sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==
+  dependencies:
+    "@types/node" "*"
+
+"@types/content-type@^1.1.0":
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/@types/content-type/-/content-type-1.1.3.tgz#3688bd77fc12f935548eef102a4e34c512b03a07"
+  integrity sha512-pv8VcFrZ3fN93L4rTNIbbUzdkzjEyVMp5mPVjsFfOYTDOZMZiZ8P1dhu+kEv3faYyKzZgLlSvnyQNFg+p/v5ug==
+
+"@types/cssbeautify@^0.3.1":
+  version "0.3.1"
+  resolved "https://registry.yarnpkg.com/@types/cssbeautify/-/cssbeautify-0.3.1.tgz#8e0bee8f7decb952250da0caebe05e30591c17ef"
+  integrity sha1-jgvuj33suVIlDaDK6+BeMFkcF+8=
+
+"@types/doctrine@^0.0.1":
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/@types/doctrine/-/doctrine-0.0.1.tgz#b999f2d9f7b43cabe0a1a2f39bc203bc7dcada9d"
+  integrity sha1-uZny2fe0PKvgoaLzm8IDvH3K2p0=
+
+"@types/escape-html@0.0.20":
+  version "0.0.20"
+  resolved "https://registry.yarnpkg.com/@types/escape-html/-/escape-html-0.0.20.tgz#cae698714dd61ebee5ab3f2aeb9a34ba1011735a"
+  integrity sha512-6dhZJLbA7aOwkYB2GDGdIqJ20wmHnkDzaxV9PJXe7O02I2dSFTERzRB6JrX6cWKaS+VqhhY7cQUMCbO5kloFUw==
+
+"@types/estree@*":
+  version "0.0.42"
+  resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.42.tgz#8d0c1f480339efedb3e46070e22dd63e0430dd11"
+  integrity sha512-K1DPVvnBCPxzD+G51/cxVIoc2X8uUVl1zpJeE6iKcgHMj4+tbat5Xu4TjV7v2QSDbIeAfLi2hIk+u2+s0MlpUQ==
+
+"@types/events@*":
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
+  integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==
+
+"@types/expect@^1.20.4":
+  version "1.20.4"
+  resolved "https://registry.yarnpkg.com/@types/expect/-/expect-1.20.4.tgz#8288e51737bf7e3ab5d7c77bfa695883745264e5"
+  integrity sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg==
+
+"@types/express-serve-static-core@*":
+  version "4.17.2"
+  resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.2.tgz#f6f41fa35d42e79dbf6610eccbb2637e6008a0cf"
+  integrity sha512-El9yMpctM6tORDAiBwZVLMcxoTMcqqRO9dVyYcn7ycLWbvR8klrDn8CAOwRfZujZtWD7yS/mshTdz43jMOejbg==
+  dependencies:
+    "@types/node" "*"
+    "@types/range-parser" "*"
+
+"@types/express@*", "@types/express@^4.0.30", "@types/express@^4.0.36":
+  version "4.17.2"
+  resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.2.tgz#a0fb7a23d8855bac31bc01d5a58cadd9b2173e6c"
+  integrity sha512-5mHFNyavtLoJmnusB8OKJ5bshSzw+qkMIBAobLrIM48HJvunFva9mOa6aBwh64lBFyNwBbs0xiEFuj4eU/NjCA==
+  dependencies:
+    "@types/body-parser" "*"
+    "@types/express-serve-static-core" "*"
+    "@types/serve-static" "*"
+
+"@types/freeport@^1.0.19":
+  version "1.0.21"
+  resolved "https://registry.yarnpkg.com/@types/freeport/-/freeport-1.0.21.tgz#73f6543ed67d3ca3fff97b985591598b7092066f"
+  integrity sha1-c/ZUPtZ9PKP/+XuYVZFZi3CSBm8=
+
+"@types/glob-stream@*":
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/@types/glob-stream/-/glob-stream-6.1.0.tgz#7ede8a33e59140534f8d8adfb8ac9edfb31897bc"
+  integrity sha512-RHv6ZQjcTncXo3thYZrsbAVwoy4vSKosSWhuhuQxLOTv74OJuFQxXkmUuZCr3q9uNBEVCvIzmZL/FeRNbHZGUg==
+  dependencies:
+    "@types/glob" "*"
+    "@types/node" "*"
+
+"@types/glob@*":
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575"
+  integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==
+  dependencies:
+    "@types/events" "*"
+    "@types/minimatch" "*"
+    "@types/node" "*"
+
+"@types/gulp-if@0.0.33":
+  version "0.0.33"
+  resolved "https://registry.yarnpkg.com/@types/gulp-if/-/gulp-if-0.0.33.tgz#edece22b7925d9a6db5f9c8c0d7882aa776fb678"
+  integrity sha512-J5lzff21X7r1x/4hSzn02GgIUEyjCqYIXZ9GgGBLhbsD3RiBdqwnkFWgF16/0jO5rcVZ52Zp+6MQMQdvIsWuKg==
+  dependencies:
+    "@types/node" "*"
+    "@types/vinyl" "*"
+
+"@types/html-minifier@^3.5.1":
+  version "3.5.3"
+  resolved "https://registry.yarnpkg.com/@types/html-minifier/-/html-minifier-3.5.3.tgz#5276845138db2cebc54c789e0aaf87621a21e84f"
+  integrity sha512-j1P/4PcWVVCPEy5lofcHnQ6BtXz9tHGiFPWzqm7TtGuWZEfCHEP446HlkSNc9fQgNJaJZ6ewPtp2aaFla/Uerg==
+  dependencies:
+    "@types/clean-css" "*"
+    "@types/relateurl" "*"
+    "@types/uglify-js" "*"
+
+"@types/is-windows@^0.2.0":
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/@types/is-windows/-/is-windows-0.2.0.tgz#6f24ee48731d31168ea510610d6dd15e5fc9c6ff"
+  integrity sha1-byTuSHMdMRaOpRBhDW3RXl/Jxv8=
+
+"@types/launchpad@^0.6.0":
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/@types/launchpad/-/launchpad-0.6.0.tgz#37296109b7f277f6e6c5fd7e0c0706bc918fbb51"
+  integrity sha1-NylhCbfyd/bmxf1+DAcGvJGPu1E=
+
+"@types/mime@*", "@types/mime@^2.0.0":
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d"
+  integrity sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==
+
+"@types/minimatch@*", "@types/minimatch@^3.0.1":
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
+  integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
+
+"@types/mz@0.0.29":
+  version "0.0.29"
+  resolved "https://registry.yarnpkg.com/@types/mz/-/mz-0.0.29.tgz#bc24728c649973f1c7851e9033f9ce525668c27b"
+  integrity sha1-vCRyjGSZc/HHhR6QM/nOUlZowns=
+  dependencies:
+    "@types/bluebird" "*"
+    "@types/node" "*"
+
+"@types/mz@0.0.31":
+  version "0.0.31"
+  resolved "https://registry.yarnpkg.com/@types/mz/-/mz-0.0.31.tgz#a4d80c082fefe71e40a7c0f07d1e6555bbbc7b52"
+  integrity sha1-pNgMCC/v5x5Ap8DwfR5lVbu8e1I=
+  dependencies:
+    "@types/node" "*"
+
+"@types/node@*":
+  version "13.1.8"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-13.1.8.tgz#1d590429fe8187a02707720ecf38a6fe46ce294b"
+  integrity sha512-6XzyyNM9EKQW4HKuzbo/CkOIjn/evtCmsU+MUM1xDfJ+3/rNjBttM1NgN7AOQvN6tP1Sl1D1PIKMreTArnxM9A==
+
+"@types/node@^4.0.30":
+  version "4.9.4"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-4.9.4.tgz#75ef91733afaa856b01e12da6ecf48aa9d5e221f"
+  integrity sha512-nKoiCZ87x6+fs26bNHjy07AQt6f46nFEitGH0P9JmWbY6tEyum6LLfLf7SIsKFh4DnBWsyUM2gYhaQAt+aA0Sw==
+
+"@types/opn@^3.0.28":
+  version "3.0.28"
+  resolved "https://registry.yarnpkg.com/@types/opn/-/opn-3.0.28.tgz#097d0d1c9b5749573a5d96df132387bb6d02118a"
+  integrity sha1-CX0NHJtXSVc6XZbfEyOHu20CEYo=
+  dependencies:
+    "@types/node" "*"
+
+"@types/parse5@^2.2.34":
+  version "2.2.34"
+  resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-2.2.34.tgz#e3870a10e82735a720f62d71dcd183ba78ef3a9d"
+  integrity sha1-44cKEOgnNacg9i1x3NGDunjvOp0=
+  dependencies:
+    "@types/node" "*"
+
+"@types/path-is-inside@^1.0.0":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@types/path-is-inside/-/path-is-inside-1.0.0.tgz#02d6ff38975d684bdec96204494baf9f29f0e17f"
+  integrity sha512-hfnXRGugz+McgX2jxyy5qz9sB21LRzlGn24zlwN2KEgoPtEvjzNRrLtUkOOebPDPZl3Rq7ywKxYvylVcEZDnEw==
+
+"@types/pem@^1.8.1":
+  version "1.9.5"
+  resolved "https://registry.yarnpkg.com/@types/pem/-/pem-1.9.5.tgz#cd5548b5e0acb4b41a9e21067e9fcd8c57089c99"
+  integrity sha512-C0txxEw8B7DCoD85Ko7SEvzUogNd5VDJ5/YBG8XUcacsOGqxr5Oo4g3OUAfdEDUbhXanwUoVh/ZkMFw77FGPQQ==
+  dependencies:
+    "@types/node" "*"
+
+"@types/range-parser@*":
+  version "1.2.3"
+  resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c"
+  integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==
+
+"@types/relateurl@*":
+  version "0.2.28"
+  resolved "https://registry.yarnpkg.com/@types/relateurl/-/relateurl-0.2.28.tgz#6bda7db8653fa62643f5ee69e9f69c11a392e3a6"
+  integrity sha1-a9p9uGU/piZD9e5p6facEaOS46Y=
+
+"@types/resolve@0.0.6":
+  version "0.0.6"
+  resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.6.tgz#0bd2f236c2e1cebb98b79885df57edd71a8d770e"
+  integrity sha512-g+Rg8uMWY76oYTyaL+m7ZcblqF/oj7pE6uEUyACluJx4zcop1Lk14qQiocdEkEVMDFm6DmKpxJhsER+ZuTwG3g==
+  dependencies:
+    "@types/node" "*"
+
+"@types/resolve@0.0.7":
+  version "0.0.7"
+  resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.7.tgz#b299c13be8d712b1b502fb14a084252acef84f4d"
+  integrity sha512-GPewdjkb0Q76o459qgp6pBLzJj/bD3oveS2kfLhIkZ9U3t3AFKtl5DlFB6lGTw0iZmcmxoGC8lpLW3NNJKrN9A==
+  dependencies:
+    "@types/node" "*"
+
+"@types/serve-static@*", "@types/serve-static@^1.7.31":
+  version "1.13.3"
+  resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.3.tgz#eb7e1c41c4468272557e897e9171ded5e2ded9d1"
+  integrity sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g==
+  dependencies:
+    "@types/express-serve-static-core" "*"
+    "@types/mime" "*"
+
+"@types/spdy@^3.4.1":
+  version "3.4.4"
+  resolved "https://registry.yarnpkg.com/@types/spdy/-/spdy-3.4.4.tgz#3282fd4ad8c4603aa49f7017dd520a08a345b2bc"
+  integrity sha512-N9LBlbVRRYq6HgYpPkqQc3a9HJ/iEtVZToW6xlTtJiMhmRJ7jJdV7TaZQJw/Ve/1ePUsQiCTDc4JMuzzag94GA==
+  dependencies:
+    "@types/node" "*"
+
+"@types/ua-parser-js@^0.7.31":
+  version "0.7.33"
+  resolved "https://registry.yarnpkg.com/@types/ua-parser-js/-/ua-parser-js-0.7.33.tgz#4a92089511574e12928a7cb6b99a01831acd1dd7"
+  integrity sha512-ngUKcHnytUodUCL7C6EZ+lVXUjTMQb+9p/e1JjV5tN9TVzS98lHozWEFRPY1QcCdwFeMsmVWfZ3DPPT/udCyIw==
+
+"@types/uglify-js@*":
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.0.4.tgz#96beae23df6f561862a830b4288a49e86baac082"
+  integrity sha512-SudIN9TRJ+v8g5pTG8RRCqfqTMNqgWCKKd3vtynhGzkIIjxaicNAMuY5TRadJ6tzDu3Dotf3ngaMILtmOdmWEQ==
+  dependencies:
+    source-map "^0.6.1"
+
+"@types/uuid@^3.4.3":
+  version "3.4.6"
+  resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-3.4.6.tgz#d2c4c48eb85a757bf2927f75f939942d521e3016"
+  integrity sha512-cCdlC/1kGEZdEglzOieLDYBxHsvEOIg7kp/2FYyVR9Pxakq+Qf/inL3RKQ+PA8gOlI/NnL+fXmQH12nwcGzsHw==
+  dependencies:
+    "@types/node" "*"
+
+"@types/vinyl-fs@^2.4.8":
+  version "2.4.11"
+  resolved "https://registry.yarnpkg.com/@types/vinyl-fs/-/vinyl-fs-2.4.11.tgz#b98119b8bb2494141eaf649b09fbfeb311161206"
+  integrity sha512-2OzQSfIr9CqqWMGqmcERE6Hnd2KY3eBVtFaulVo3sJghplUcaeMdL9ZjEiljcQQeHjheWY9RlNmumjIAvsBNaA==
+  dependencies:
+    "@types/glob-stream" "*"
+    "@types/node" "*"
+    "@types/vinyl" "*"
+
+"@types/vinyl@*", "@types/vinyl@^2.0.0":
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/@types/vinyl/-/vinyl-2.0.4.tgz#9a7a8071c8d14d3a95d41ebe7135babe4ad5995a"
+  integrity sha512-2o6a2ixaVI2EbwBPg1QYLGQoHK56p/8X/sGfKbFC8N6sY9lfjsMf/GprtkQkSya0D4uRiutRZ2BWj7k3JvLsAQ==
+  dependencies:
+    "@types/expect" "^1.20.4"
+    "@types/node" "*"
+
+"@types/whatwg-url@^6.4.0":
+  version "6.4.0"
+  resolved "https://registry.yarnpkg.com/@types/whatwg-url/-/whatwg-url-6.4.0.tgz#1e59b8c64bc0dbdf66d037cf8449d1c3d5270237"
+  integrity sha512-tonhlcbQ2eho09am6RHnHOgvtDfDYINd5rgxD+2YSkKENooVCFsWizJz139MQW/PV8FfClyKrNe9ZbdHrSCxGg==
+  dependencies:
+    "@types/node" "*"
+
+"@types/which@^1.3.1":
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/@types/which/-/which-1.3.2.tgz#9c246fc0c93ded311c8512df2891fb41f6227fdf"
+  integrity sha512-8oDqyLC7eD4HM307boe2QWKyuzdzWBj56xI/imSl2cpL+U3tCMaTAkMJ4ee5JBZ/FsOJlvRGeIShiZDAl1qERA==
+
+"@webcomponents/shadycss@^1.9.1":
+  version "1.9.4"
+  resolved "https://registry.yarnpkg.com/@webcomponents/shadycss/-/shadycss-1.9.4.tgz#4f9d8ea1526bab084c60b53d4854dc39fdb2bb48"
+  integrity sha512-tgNcVEaKssyeZPbUBjVQf4aryO5Fi7fxRvOxV982ZJuRVDcefmIblBh0SXAbcvAAlQ2zpNEP4SuQUnr8uApIpw==
+
+"@webcomponents/webcomponentsjs@^1.0.7":
+  version "1.3.3"
+  resolved "https://registry.yarnpkg.com/@webcomponents/webcomponentsjs/-/webcomponentsjs-1.3.3.tgz#5bb82a0d3210c836bd4623e13a4a93145cb9dc27"
+  integrity sha512-eLH04VBMpuZGzBIhOnUjECcQPEPcmfhWEijW9u1B5I+2PPYdWf3vWUExdDxu4Y3GljRSTCOlWnGtS9tpzmXMyQ==
+
+"@webcomponents/webcomponentsjs@^2.0.0":
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/@webcomponents/webcomponentsjs/-/webcomponentsjs-2.4.1.tgz#7baadec56ed2fd79b94ddfd509132d8c0c295c5c"
+  integrity sha512-7jxBb+KoWncKb/JGFyTY40PjV4yRx2zd35ZLuvRP+6WndJDL7X32ZIZ7bN3sSQIl+NzJkCo7chfXJyzn+6WZaQ==
+
+accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7:
+  version "1.3.7"
+  resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
+  integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
+  dependencies:
+    mime-types "~2.1.24"
+    negotiator "0.6.2"
+
+accessibility-developer-tools@^2.12.0:
+  version "2.12.0"
+  resolved "https://registry.yarnpkg.com/accessibility-developer-tools/-/accessibility-developer-tools-2.12.0.tgz#3da0cce9d6ec6373964b84f35db7cfc3df7ab514"
+  integrity sha1-PaDM6dbsY3OWS4TzXbfPw996tRQ=
+
+acorn-jsx@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b"
+  integrity sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=
+  dependencies:
+    acorn "^3.0.4"
+
+acorn@^3.0.4:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
+  integrity sha1-ReN/s56No/JbruP/U2niu18iAXo=
+
+acorn@^5.5.0:
+  version "5.7.3"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279"
+  integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==
+
+acorn@^7.1.0:
+  version "7.1.0"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.0.tgz#949d36f2c292535da602283586c2477c57eb2d6c"
+  integrity sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==
+
+adm-zip@~0.4.3:
+  version "0.4.13"
+  resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.13.tgz#597e2f8cc3672151e1307d3e95cddbc75672314a"
+  integrity sha512-fERNJX8sOXfel6qCBCMPvZLzENBEhZTzKqg6vrOW5pvoEaQuJhRU4ndTAh6lHOxn1I6jnz2NHra56ZODM751uw==
+
+after@0.8.2:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
+  integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=
+
+agent-base@^4.3.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee"
+  integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==
+  dependencies:
+    es6-promisify "^5.0.0"
+
+ajv@^6.5.5:
+  version "6.11.0"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.11.0.tgz#c3607cbc8ae392d8a5a536f25b21f8e5f3f87fe9"
+  integrity sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA==
+  dependencies:
+    fast-deep-equal "^3.1.1"
+    fast-json-stable-stringify "^2.0.0"
+    json-schema-traverse "^0.4.1"
+    uri-js "^4.2.2"
+
+ansi-align@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f"
+  integrity sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=
+  dependencies:
+    string-width "^2.0.0"
+
+ansi-colors@3.2.3:
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813"
+  integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==
+
+ansi-regex@^2.0.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+  integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
+
+ansi-regex@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
+  integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
+
+ansi-regex@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
+  integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
+
+ansi-styles@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
+  integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=
+
+ansi-styles@^3.2.0, ansi-styles@^3.2.1:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+  integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
+  dependencies:
+    color-convert "^1.9.0"
+
+ansi-styles@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178"
+  integrity sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=
+
+any-promise@^1.0.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
+  integrity sha1-q8av7tzqUugJzcA3au0845Y10X8=
+
+append-field@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56"
+  integrity sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=
+
+archiver-utils@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2"
+  integrity sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==
+  dependencies:
+    glob "^7.1.4"
+    graceful-fs "^4.2.0"
+    lazystream "^1.0.0"
+    lodash.defaults "^4.2.0"
+    lodash.difference "^4.5.0"
+    lodash.flatten "^4.4.0"
+    lodash.isplainobject "^4.0.6"
+    lodash.union "^4.6.0"
+    normalize-path "^3.0.0"
+    readable-stream "^2.0.0"
+
+archiver@^3.0.0:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/archiver/-/archiver-3.1.1.tgz#9db7819d4daf60aec10fe86b16cb9258ced66ea0"
+  integrity sha512-5Hxxcig7gw5Jod/8Gq0OneVgLYET+oNHcxgWItq4TbhOzRLKNAFUb9edAftiMKXvXfCB0vbGrJdZDNq0dWMsxg==
+  dependencies:
+    archiver-utils "^2.1.0"
+    async "^2.6.3"
+    buffer-crc32 "^0.2.1"
+    glob "^7.1.4"
+    readable-stream "^3.4.0"
+    tar-stream "^2.1.0"
+    zip-stream "^2.1.2"
+
+argparse@^1.0.7:
+  version "1.0.10"
+  resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
+  integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
+  dependencies:
+    sprintf-js "~1.0.2"
+
+arr-diff@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
+  integrity sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=
+  dependencies:
+    arr-flatten "^1.0.1"
+
+arr-diff@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
+  integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=
+
+arr-flatten@^1.0.1, arr-flatten@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1"
+  integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==
+
+arr-union@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
+  integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=
+
+array-back@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/array-back/-/array-back-2.0.0.tgz#6877471d51ecc9c9bfa6136fb6c7d5fe69748022"
+  integrity sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==
+  dependencies:
+    typical "^2.6.1"
+
+array-back@^3.0.1:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0"
+  integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==
+
+array-find-index@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
+  integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=
+
+array-flatten@1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
+  integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
+
+array-unique@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
+  integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=
+
+array-unique@^0.3.2:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
+  integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=
+
+arraybuffer.slice@~0.0.7:
+  version "0.0.7"
+  resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675"
+  integrity sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==
+
+asn1@~0.2.3:
+  version "0.2.4"
+  resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
+  integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
+  dependencies:
+    safer-buffer "~2.1.0"
+
+assert-plus@1.0.0, assert-plus@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
+  integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=
+
+assertion-error@^1.0.1, assertion-error@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b"
+  integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==
+
+assign-symbols@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
+  integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=
+
+async-limiter@~1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
+  integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
+
+async@^1.5.2:
+  version "1.5.2"
+  resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
+  integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=
+
+async@^2.0.0, async@^2.0.1, async@^2.1.2, async@^2.4.1, async@^2.6.1, async@^2.6.2, async@^2.6.3:
+  version "2.6.3"
+  resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
+  integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==
+  dependencies:
+    lodash "^4.17.14"
+
+async@~0.2.9:
+  version "0.2.10"
+  resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1"
+  integrity sha1-trvgsGdLnXGXCMo43owjfLUmw9E=
+
+asynckit@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+  integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
+
+atob@^2.1.2:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
+  integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
+
+aws-sign2@~0.7.0:
+  version "0.7.0"
+  resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
+  integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
+
+aws4@^1.8.0:
+  version "1.9.1"
+  resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e"
+  integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==
+
+babel-code-frame@^6.26.0:
+  version "6.26.0"
+  resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
+  integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=
+  dependencies:
+    chalk "^1.1.3"
+    esutils "^2.0.2"
+    js-tokens "^3.0.2"
+
+babel-generator@^6.26.1:
+  version "6.26.1"
+  resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90"
+  integrity sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==
+  dependencies:
+    babel-messages "^6.23.0"
+    babel-runtime "^6.26.0"
+    babel-types "^6.26.0"
+    detect-indent "^4.0.0"
+    jsesc "^1.3.0"
+    lodash "^4.17.4"
+    source-map "^0.5.7"
+    trim-right "^1.0.1"
+
+babel-helper-evaluate-path@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.5.0.tgz#a62fa9c4e64ff7ea5cea9353174ef023a900a67c"
+  integrity sha512-mUh0UhS607bGh5wUMAQfOpt2JX2ThXMtppHRdRU1kL7ZLRWIXxoV2UIV1r2cAeeNeU1M5SB5/RSUgUxrK8yOkA==
+
+babel-helper-flip-expressions@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.4.3.tgz#3696736a128ac18bc25254b5f40a22ceb3c1d3fd"
+  integrity sha1-NpZzahKKwYvCUlS19AoizrPB0/0=
+
+babel-helper-is-nodes-equiv@^0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz#34e9b300b1479ddd98ec77ea0bbe9342dfe39684"
+  integrity sha1-NOmzALFHnd2Y7HfqC76TQt/jloQ=
+
+babel-helper-is-void-0@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-helper-is-void-0/-/babel-helper-is-void-0-0.4.3.tgz#7d9c01b4561e7b95dbda0f6eee48f5b60e67313e"
+  integrity sha1-fZwBtFYee5Xb2g9u7kj1tg5nMT4=
+
+babel-helper-mark-eval-scopes@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.4.3.tgz#d244a3bef9844872603ffb46e22ce8acdf551562"
+  integrity sha1-0kSjvvmESHJgP/tG4izorN9VFWI=
+
+babel-helper-remove-or-void@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.4.3.tgz#a4f03b40077a0ffe88e45d07010dee241ff5ae60"
+  integrity sha1-pPA7QAd6D/6I5F0HAQ3uJB/1rmA=
+
+babel-helper-to-multiple-sequence-expressions@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.5.0.tgz#a3f924e3561882d42fcf48907aa98f7979a4588d"
+  integrity sha512-m2CvfDW4+1qfDdsrtf4dwOslQC3yhbgyBFptncp4wvtdrDHqueW7slsYv4gArie056phvQFhT2nRcGS4bnm6mA==
+
+babel-messages@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e"
+  integrity sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-dynamic-import-node@^2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f"
+  integrity sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==
+  dependencies:
+    object.assign "^4.1.0"
+
+babel-plugin-minify-builtins@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.5.0.tgz#31eb82ed1a0d0efdc31312f93b6e4741ce82c36b"
+  integrity sha512-wpqbN7Ov5hsNwGdzuzvFcjgRlzbIeVv1gMIlICbPj0xkexnfoIDe7q+AZHMkQmAE/F9R5jkrB6TLfTegImlXag==
+
+babel-plugin-minify-constant-folding@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.5.0.tgz#f84bc8dbf6a561e5e350ff95ae216b0ad5515b6e"
+  integrity sha512-Vj97CTn/lE9hR1D+jKUeHfNy+m1baNiJ1wJvoGyOBUx7F7kJqDZxr9nCHjO/Ad+irbR3HzR6jABpSSA29QsrXQ==
+  dependencies:
+    babel-helper-evaluate-path "^0.5.0"
+
+babel-plugin-minify-dead-code-elimination@^0.5.1:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.5.1.tgz#1a0c68e44be30de4976ca69ffc535e08be13683f"
+  integrity sha512-x8OJOZIrRmQBcSqxBcLbMIK8uPmTvNWPXH2bh5MDCW1latEqYiRMuUkPImKcfpo59pTUB2FT7HfcgtG8ZlR5Qg==
+  dependencies:
+    babel-helper-evaluate-path "^0.5.0"
+    babel-helper-mark-eval-scopes "^0.4.3"
+    babel-helper-remove-or-void "^0.4.3"
+    lodash "^4.17.11"
+
+babel-plugin-minify-flip-comparisons@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.4.3.tgz#00ca870cb8f13b45c038b3c1ebc0f227293c965a"
+  integrity sha1-AMqHDLjxO0XAOLPB68DyJyk8llo=
+  dependencies:
+    babel-helper-is-void-0 "^0.4.3"
+
+babel-plugin-minify-guarded-expressions@^0.4.3, babel-plugin-minify-guarded-expressions@^0.4.4:
+  version "0.4.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.4.4.tgz#818960f64cc08aee9d6c75bec6da974c4d621135"
+  integrity sha512-RMv0tM72YuPPfLT9QLr3ix9nwUIq+sHT6z8Iu3sLbqldzC1Dls8DPCywzUIzkTx9Zh1hWX4q/m9BPoPed9GOfA==
+  dependencies:
+    babel-helper-evaluate-path "^0.5.0"
+    babel-helper-flip-expressions "^0.4.3"
+
+babel-plugin-minify-infinity@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.4.3.tgz#dfb876a1b08a06576384ef3f92e653ba607b39ca"
+  integrity sha1-37h2obCKBldjhO8/kuZTumB7Oco=
+
+babel-plugin-minify-mangle-names@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.5.0.tgz#bcddb507c91d2c99e138bd6b17a19c3c271e3fd3"
+  integrity sha512-3jdNv6hCAw6fsX1p2wBGPfWuK69sfOjfd3zjUXkbq8McbohWy23tpXfy5RnToYWggvqzuMOwlId1PhyHOfgnGw==
+  dependencies:
+    babel-helper-mark-eval-scopes "^0.4.3"
+
+babel-plugin-minify-numeric-literals@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.4.3.tgz#8e4fd561c79f7801286ff60e8c5fd9deee93c0bc"
+  integrity sha1-jk/VYcefeAEob/YOjF/Z3u6TwLw=
+
+babel-plugin-minify-replace@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.5.0.tgz#d3e2c9946c9096c070efc96761ce288ec5c3f71c"
+  integrity sha512-aXZiaqWDNUbyNNNpWs/8NyST+oU7QTpK7J9zFEFSA0eOmtUNMU3fczlTTTlnCxHmq/jYNFEmkkSG3DDBtW3Y4Q==
+
+babel-plugin-minify-simplify@^0.5.1:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.5.1.tgz#f21613c8b95af3450a2ca71502fdbd91793c8d6a"
+  integrity sha512-OSYDSnoCxP2cYDMk9gxNAed6uJDiDz65zgL6h8d3tm8qXIagWGMLWhqysT6DY3Vs7Fgq7YUDcjOomhVUb+xX6A==
+  dependencies:
+    babel-helper-evaluate-path "^0.5.0"
+    babel-helper-flip-expressions "^0.4.3"
+    babel-helper-is-nodes-equiv "^0.0.1"
+    babel-helper-to-multiple-sequence-expressions "^0.5.0"
+
+babel-plugin-minify-type-constructors@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.4.3.tgz#1bc6f15b87f7ab1085d42b330b717657a2156500"
+  integrity sha1-G8bxW4f3qxCF1CszC3F2V6IVZQA=
+  dependencies:
+    babel-helper-is-void-0 "^0.4.3"
+
+babel-plugin-transform-inline-consecutive-adds@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.4.3.tgz#323d47a3ea63a83a7ac3c811ae8e6941faf2b0d1"
+  integrity sha1-Mj1Ho+pjqDp6w8gRro5pQfrysNE=
+
+babel-plugin-transform-member-expression-literals@^6.9.4:
+  version "6.9.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.9.4.tgz#37039c9a0c3313a39495faac2ff3a6b5b9d038bf"
+  integrity sha1-NwOcmgwzE6OUlfqsL/OmtbnQOL8=
+
+babel-plugin-transform-merge-sibling-variables@^6.9.4:
+  version "6.9.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.9.4.tgz#85b422fc3377b449c9d1cde44087203532401dae"
+  integrity sha1-hbQi/DN3tEnJ0c3kQIcgNTJAHa4=
+
+babel-plugin-transform-minify-booleans@^6.9.4:
+  version "6.9.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.4.tgz#acbb3e56a3555dd23928e4b582d285162dd2b198"
+  integrity sha1-rLs+VqNVXdI5KOS1gtKFFi3SsZg=
+
+babel-plugin-transform-property-literals@^6.9.4:
+  version "6.9.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.9.4.tgz#98c1d21e255736573f93ece54459f6ce24985d39"
+  integrity sha1-mMHSHiVXNlc/k+zlRFn2ziSYXTk=
+  dependencies:
+    esutils "^2.0.2"
+
+babel-plugin-transform-regexp-constructors@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.4.3.tgz#58b7775b63afcf33328fae9a5f88fbd4fb0b4965"
+  integrity sha1-WLd3W2OvzzMyj66aX4j71PsLSWU=
+
+babel-plugin-transform-remove-console@^6.9.4:
+  version "6.9.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.4.tgz#b980360c067384e24b357a588d807d3c83527780"
+  integrity sha1-uYA2DAZzhOJLNXpYjYB9PINSd4A=
+
+babel-plugin-transform-remove-debugger@^6.9.4:
+  version "6.9.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.9.4.tgz#42b727631c97978e1eb2d199a7aec84a18339ef2"
+  integrity sha1-QrcnYxyXl44estGZp67IShgznvI=
+
+babel-plugin-transform-remove-undefined@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.5.0.tgz#80208b31225766c630c97fa2d288952056ea22dd"
+  integrity sha512-+M7fJYFaEE/M9CXa0/IRkDbiV3wRELzA1kKQFCJ4ifhrzLKn/9VCCgj9OFmYWwBd8IB48YdgPkHYtbYq+4vtHQ==
+  dependencies:
+    babel-helper-evaluate-path "^0.5.0"
+
+babel-plugin-transform-simplify-comparison-operators@^6.9.4:
+  version "6.9.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.9.4.tgz#f62afe096cab0e1f68a2d753fdf283888471ceb9"
+  integrity sha1-9ir+CWyrDh9ootdT/fKDiIRxzrk=
+
+babel-plugin-transform-undefined-to-void@^6.9.4:
+  version "6.9.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.4.tgz#be241ca81404030678b748717322b89d0c8fe280"
+  integrity sha1-viQcqBQEAwZ4t0hxcyK4nQyP4oA=
+
+babel-preset-minify@^0.5.0:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/babel-preset-minify/-/babel-preset-minify-0.5.1.tgz#25f5d0bce36ec818be80338d0e594106e21eaa9f"
+  integrity sha512-1IajDumYOAPYImkHbrKeiN5AKKP9iOmRoO2IPbIuVp0j2iuCcj0n7P260z38siKMZZ+85d3mJZdtW8IgOv+Tzg==
+  dependencies:
+    babel-plugin-minify-builtins "^0.5.0"
+    babel-plugin-minify-constant-folding "^0.5.0"
+    babel-plugin-minify-dead-code-elimination "^0.5.1"
+    babel-plugin-minify-flip-comparisons "^0.4.3"
+    babel-plugin-minify-guarded-expressions "^0.4.4"
+    babel-plugin-minify-infinity "^0.4.3"
+    babel-plugin-minify-mangle-names "^0.5.0"
+    babel-plugin-minify-numeric-literals "^0.4.3"
+    babel-plugin-minify-replace "^0.5.0"
+    babel-plugin-minify-simplify "^0.5.1"
+    babel-plugin-minify-type-constructors "^0.4.3"
+    babel-plugin-transform-inline-consecutive-adds "^0.4.3"
+    babel-plugin-transform-member-expression-literals "^6.9.4"
+    babel-plugin-transform-merge-sibling-variables "^6.9.4"
+    babel-plugin-transform-minify-booleans "^6.9.4"
+    babel-plugin-transform-property-literals "^6.9.4"
+    babel-plugin-transform-regexp-constructors "^0.4.3"
+    babel-plugin-transform-remove-console "^6.9.4"
+    babel-plugin-transform-remove-debugger "^6.9.4"
+    babel-plugin-transform-remove-undefined "^0.5.0"
+    babel-plugin-transform-simplify-comparison-operators "^6.9.4"
+    babel-plugin-transform-undefined-to-void "^6.9.4"
+    lodash "^4.17.11"
+
+babel-runtime@^6.22.0, babel-runtime@^6.26.0:
+  version "6.26.0"
+  resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
+  integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4=
+  dependencies:
+    core-js "^2.4.0"
+    regenerator-runtime "^0.11.0"
+
+babel-traverse@^6.26.0:
+  version "6.26.0"
+  resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee"
+  integrity sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=
+  dependencies:
+    babel-code-frame "^6.26.0"
+    babel-messages "^6.23.0"
+    babel-runtime "^6.26.0"
+    babel-types "^6.26.0"
+    babylon "^6.18.0"
+    debug "^2.6.8"
+    globals "^9.18.0"
+    invariant "^2.2.2"
+    lodash "^4.17.4"
+
+babel-types@^6.26.0:
+  version "6.26.0"
+  resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497"
+  integrity sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=
+  dependencies:
+    babel-runtime "^6.26.0"
+    esutils "^2.0.2"
+    lodash "^4.17.4"
+    to-fast-properties "^1.0.3"
+
+babylon@^6.18.0:
+  version "6.18.0"
+  resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3"
+  integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==
+
+babylon@^7.0.0-beta.42:
+  version "7.0.0-beta.47"
+  resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.47.tgz#6d1fa44f0abec41ab7c780481e62fd9aafbdea80"
+  integrity sha512-+rq2cr4GDhtToEzKFD6KZZMDBXhjFAr9JjPw9pAppZACeEWqNM294j+NdBzkSHYXwzzBmVjZ3nEVJlOhbR2gOQ==
+
+backo2@1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
+  integrity sha1-MasayLEpNjRj41s+u2n038+6eUc=
+
+balanced-match@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
+  integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
+
+base64-arraybuffer@0.1.5:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8"
+  integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg=
+
+base64-js@1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
+  integrity sha1-o5mS1yNYSBGYK+XikLtqU9hnAPE=
+
+base64-js@^1.0.2:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1"
+  integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==
+
+base64id@2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6"
+  integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==
+
+base@^0.11.1:
+  version "0.11.2"
+  resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
+  integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==
+  dependencies:
+    cache-base "^1.0.1"
+    class-utils "^0.3.5"
+    component-emitter "^1.2.1"
+    define-property "^1.0.0"
+    isobject "^3.0.1"
+    mixin-deep "^1.2.0"
+    pascalcase "^0.1.1"
+
+bcrypt-pbkdf@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
+  integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=
+  dependencies:
+    tweetnacl "^0.14.3"
+
+better-assert@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522"
+  integrity sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=
+  dependencies:
+    callsite "1.0.0"
+
+bl@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/bl/-/bl-2.2.0.tgz#e1a574cdf528e4053019bb800b041c0ac88da493"
+  integrity sha512-wbgvOpqopSr7uq6fJrLH8EsvYMJf9gzfo2jCsL2eTy75qXPukA4pCgHamOQkZtY5vmfVtjB+P3LNlMHW5CEZXA==
+  dependencies:
+    readable-stream "^2.3.5"
+    safe-buffer "^5.1.1"
+
+bl@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/bl/-/bl-3.0.0.tgz#3611ec00579fd18561754360b21e9f784500ff88"
+  integrity sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A==
+  dependencies:
+    readable-stream "^3.0.1"
+
+blob@0.0.5:
+  version "0.0.5"
+  resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683"
+  integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==
+
+body-parser@1.19.0, body-parser@^1.17.2:
+  version "1.19.0"
+  resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
+  integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==
+  dependencies:
+    bytes "3.1.0"
+    content-type "~1.0.4"
+    debug "2.6.9"
+    depd "~1.1.2"
+    http-errors "1.7.2"
+    iconv-lite "0.4.24"
+    on-finished "~2.3.0"
+    qs "6.7.0"
+    raw-body "2.4.0"
+    type-is "~1.6.17"
+
+bower-config@^1.4.0, bower-config@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/bower-config/-/bower-config-1.4.1.tgz#85fd9df367c2b8dbbd0caa4c5f2bad40cd84c2cc"
+  integrity sha1-hf2d82fCuNu9DKpMXyutQM2Ewsw=
+  dependencies:
+    graceful-fs "^4.1.3"
+    mout "^1.0.0"
+    optimist "^0.6.1"
+    osenv "^0.1.3"
+    untildify "^2.1.0"
+
+boxen@^1.2.1:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b"
+  integrity sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==
+  dependencies:
+    ansi-align "^2.0.0"
+    camelcase "^4.0.0"
+    chalk "^2.0.1"
+    cli-boxes "^1.0.0"
+    string-width "^2.0.0"
+    term-size "^1.2.0"
+    widest-line "^2.0.0"
+
+brace-expansion@^1.1.7:
+  version "1.1.11"
+  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+  integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+  dependencies:
+    balanced-match "^1.0.0"
+    concat-map "0.0.1"
+
+braces@^1.8.2:
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
+  integrity sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=
+  dependencies:
+    expand-range "^1.8.1"
+    preserve "^0.2.0"
+    repeat-element "^1.1.2"
+
+braces@^2.3.1:
+  version "2.3.2"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
+  integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==
+  dependencies:
+    arr-flatten "^1.1.0"
+    array-unique "^0.3.2"
+    extend-shallow "^2.0.1"
+    fill-range "^4.0.0"
+    isobject "^3.0.1"
+    repeat-element "^1.1.2"
+    snapdragon "^0.8.1"
+    snapdragon-node "^2.0.1"
+    split-string "^3.0.2"
+    to-regex "^3.0.1"
+
+browser-capabilities@^1.0.0:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/browser-capabilities/-/browser-capabilities-1.1.4.tgz#a6bd657a07a134532ad66c722b8949904478b973"
+  integrity sha512-BezMQhbQklxjRQpZZQ8tnbzEo6AldUwMh8/PeWt5/CTBSwByQRXZEAK2fbnEahQ4poeeaI0suAYRq25A1YGOmw==
+  dependencies:
+    "@types/ua-parser-js" "^0.7.31"
+    ua-parser-js "^0.7.15"
+
+browser-stdout@1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f"
+  integrity sha1-81HTKWnTL6XXpVZxVCY9korjvR8=
+
+browser-stdout@1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60"
+  integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==
+
+browserstack@^1.2.0:
+  version "1.5.3"
+  resolved "https://registry.yarnpkg.com/browserstack/-/browserstack-1.5.3.tgz#93ab48799a12ef99dbd074dd595410ddb196a7ac"
+  integrity sha512-AO+mECXsW4QcqC9bxwM29O7qWa7bJT94uBFzeb5brylIQwawuEziwq20dPYbins95GlWzOawgyDNdjYAo32EKg==
+  dependencies:
+    https-proxy-agent "^2.2.1"
+
+buffer-crc32@^0.2.1, buffer-crc32@^0.2.13, buffer-crc32@~0.2.3:
+  version "0.2.13"
+  resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
+  integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=
+
+buffer-from@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
+  integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
+
+buffer@^5.1.0:
+  version "5.4.3"
+  resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.4.3.tgz#3fbc9c69eb713d323e3fc1a895eee0710c072115"
+  integrity sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==
+  dependencies:
+    base64-js "^1.0.2"
+    ieee754 "^1.1.4"
+
+busboy@^0.2.11:
+  version "0.2.14"
+  resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453"
+  integrity sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=
+  dependencies:
+    dicer "0.2.5"
+    readable-stream "1.1.x"
+
+bytes@3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
+  integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=
+
+bytes@3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
+  integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
+
+cache-base@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
+  integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==
+  dependencies:
+    collection-visit "^1.0.0"
+    component-emitter "^1.2.1"
+    get-value "^2.0.6"
+    has-value "^1.0.0"
+    isobject "^3.0.1"
+    set-value "^2.0.0"
+    to-object-path "^0.3.0"
+    union-value "^1.0.0"
+    unset-value "^1.0.0"
+
+callsite@1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20"
+  integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA=
+
+camel-case@3.0.x:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73"
+  integrity sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=
+  dependencies:
+    no-case "^2.2.0"
+    upper-case "^1.1.1"
+
+camelcase-keys@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7"
+  integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc=
+  dependencies:
+    camelcase "^2.0.0"
+    map-obj "^1.0.0"
+
+camelcase@^2.0.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
+  integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=
+
+camelcase@^4.0.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
+  integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=
+
+camelcase@^5.0.0:
+  version "5.3.1"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
+  integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
+
+cancel-token@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/cancel-token/-/cancel-token-0.1.1.tgz#c18197674bb1c84c1d6933ebf15d8d5a5ce79b4f"
+  integrity sha1-wYGXZ0uxyEwdaTPr8V2NWlznm08=
+  dependencies:
+    "@types/node" "^4.0.30"
+
+capture-stack-trace@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz#a6c0bbe1f38f3aa0b92238ecb6ff42c344d4135d"
+  integrity sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==
+
+caseless@~0.12.0:
+  version "0.12.0"
+  resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
+  integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
+
+chai@^3.5.0:
+  version "3.5.0"
+  resolved "https://registry.yarnpkg.com/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247"
+  integrity sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=
+  dependencies:
+    assertion-error "^1.0.1"
+    deep-eql "^0.1.3"
+    type-detect "^1.0.0"
+
+chai@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5"
+  integrity sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==
+  dependencies:
+    assertion-error "^1.1.0"
+    check-error "^1.0.2"
+    deep-eql "^3.0.1"
+    get-func-name "^2.0.0"
+    pathval "^1.1.0"
+    type-detect "^4.0.5"
+
+chalk@^1.1.1, chalk@^1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
+  integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=
+  dependencies:
+    ansi-styles "^2.2.1"
+    escape-string-regexp "^1.0.2"
+    has-ansi "^2.0.0"
+    strip-ansi "^3.0.0"
+    supports-color "^2.0.0"
+
+chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.1:
+  version "2.4.2"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
+  integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
+  dependencies:
+    ansi-styles "^3.2.1"
+    escape-string-regexp "^1.0.5"
+    supports-color "^5.3.0"
+
+chalk@~0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f"
+  integrity sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=
+  dependencies:
+    ansi-styles "~1.0.0"
+    has-color "~0.1.0"
+    strip-ansi "~0.1.0"
+
+charenc@~0.0.1:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
+  integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=
+
+check-error@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
+  integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=
+
+ci-info@^1.5.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497"
+  integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==
+
+class-utils@^0.3.5:
+  version "0.3.6"
+  resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
+  integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==
+  dependencies:
+    arr-union "^3.1.0"
+    define-property "^0.2.5"
+    isobject "^3.0.0"
+    static-extend "^0.1.1"
+
+clean-css@4.2.x:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.1.tgz#2d411ef76b8569b6d0c84068dabe85b0aa5e5c17"
+  integrity sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==
+  dependencies:
+    source-map "~0.6.0"
+
+cleankill@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/cleankill/-/cleankill-2.0.0.tgz#59830dfc8b411d53dc72ad09d45a78ea33161a91"
+  integrity sha1-WYMN/ItBHVPccq0J1Fp46jMWGpE=
+
+cli-boxes@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143"
+  integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM=
+
+cliui@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5"
+  integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==
+  dependencies:
+    string-width "^3.1.0"
+    strip-ansi "^5.2.0"
+    wrap-ansi "^5.1.0"
+
+clone-stats@^0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1"
+  integrity sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=
+
+clone@^1.0.0:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
+  integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
+
+clone@^2.0.0, clone@^2.1.0:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
+  integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=
+
+collection-visit@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
+  integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=
+  dependencies:
+    map-visit "^1.0.0"
+    object-visit "^1.0.0"
+
+color-convert@^1.9.0, color-convert@^1.9.1:
+  version "1.9.3"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
+  integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
+  dependencies:
+    color-name "1.1.3"
+
+color-name@1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+  integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
+
+color-name@^1.0.0:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
+  integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+
+color-string@^1.5.2:
+  version "1.5.3"
+  resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.3.tgz#c9bbc5f01b58b5492f3d6857459cb6590ce204cc"
+  integrity sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==
+  dependencies:
+    color-name "^1.0.0"
+    simple-swizzle "^0.2.2"
+
+color@3.0.x:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/color/-/color-3.0.0.tgz#d920b4328d534a3ac8295d68f7bd4ba6c427be9a"
+  integrity sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==
+  dependencies:
+    color-convert "^1.9.1"
+    color-string "^1.5.2"
+
+colornames@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/colornames/-/colornames-1.1.1.tgz#f8889030685c7c4ff9e2a559f5077eb76a816f96"
+  integrity sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=
+
+colors@^1.2.1:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
+  integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==
+
+colorspace@1.1.x:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.2.tgz#e0128950d082b86a2168580796a0aa5d6c68d8c5"
+  integrity sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==
+  dependencies:
+    color "3.0.x"
+    text-hex "1.0.x"
+
+combined-stream@^1.0.6, combined-stream@~1.0.6:
+  version "1.0.8"
+  resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
+  integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
+  dependencies:
+    delayed-stream "~1.0.0"
+
+command-line-args@^5.0.2:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.1.1.tgz#88e793e5bb3ceb30754a86863f0401ac92fd369a"
+  integrity sha512-hL/eG8lrll1Qy1ezvkant+trihbGnaKaeEjj6Scyr3DN+RC7iQ5Rz84IeLERfAWDGo0HBSNAakczwgCilDXnWg==
+  dependencies:
+    array-back "^3.0.1"
+    find-replace "^3.0.0"
+    lodash.camelcase "^4.3.0"
+    typical "^4.0.0"
+
+command-line-usage@^5.0.5:
+  version "5.0.5"
+  resolved "https://registry.yarnpkg.com/command-line-usage/-/command-line-usage-5.0.5.tgz#5f25933ffe6dedd983c635d38a21d7e623fda357"
+  integrity sha512-d8NrGylA5oCXSbGoKz05FkehDAzSmIm4K03S5VDh4d5lZAtTWfc3D1RuETtuQCn8129nYfJfDdF7P/lwcz1BlA==
+  dependencies:
+    array-back "^2.0.0"
+    chalk "^2.4.1"
+    table-layout "^0.4.3"
+    typical "^2.6.1"
+
+commander@2.17.x:
+  version "2.17.1"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
+  integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==
+
+commander@2.9.0:
+  version "2.9.0"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4"
+  integrity sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=
+  dependencies:
+    graceful-readlink ">= 1.0.0"
+
+commander@^2.19.0:
+  version "2.20.3"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
+  integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
+
+commander@~2.19.0:
+  version "2.19.0"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
+  integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==
+
+component-bind@1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1"
+  integrity sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=
+
+component-emitter@1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
+  integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=
+
+component-emitter@^1.2.1:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
+  integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
+
+component-inherit@0.0.3:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143"
+  integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=
+
+compress-commons@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-2.1.1.tgz#9410d9a534cf8435e3fbbb7c6ce48de2dc2f0610"
+  integrity sha512-eVw6n7CnEMFzc3duyFVrQEuY1BlHR3rYsSztyG32ibGMW722i3C6IizEGMFmfMU+A+fALvBIwxN3czffTcdA+Q==
+  dependencies:
+    buffer-crc32 "^0.2.13"
+    crc32-stream "^3.0.1"
+    normalize-path "^3.0.0"
+    readable-stream "^2.3.6"
+
+compressible@~2.0.16:
+  version "2.0.18"
+  resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba"
+  integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==
+  dependencies:
+    mime-db ">= 1.43.0 < 2"
+
+compression@^1.6.2:
+  version "1.7.4"
+  resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f"
+  integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==
+  dependencies:
+    accepts "~1.3.5"
+    bytes "3.0.0"
+    compressible "~2.0.16"
+    debug "2.6.9"
+    on-headers "~1.0.2"
+    safe-buffer "5.1.2"
+    vary "~1.1.2"
+
+concat-map@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+  integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
+
+concat-stream@^1.5.2:
+  version "1.6.2"
+  resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
+  integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
+  dependencies:
+    buffer-from "^1.0.0"
+    inherits "^2.0.3"
+    readable-stream "^2.2.2"
+    typedarray "^0.0.6"
+
+configstore@^3.0.0:
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.2.tgz#c6f25defaeef26df12dd33414b001fe81a543f8f"
+  integrity sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==
+  dependencies:
+    dot-prop "^4.1.0"
+    graceful-fs "^4.1.2"
+    make-dir "^1.0.0"
+    unique-string "^1.0.0"
+    write-file-atomic "^2.0.0"
+    xdg-basedir "^3.0.0"
+
+content-disposition@0.5.3:
+  version "0.5.3"
+  resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
+  integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==
+  dependencies:
+    safe-buffer "5.1.2"
+
+content-type@^1.0.2, content-type@~1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
+  integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
+
+convert-source-map@^1.1.1, convert-source-map@^1.7.0:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442"
+  integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==
+  dependencies:
+    safe-buffer "~5.1.1"
+
+cookie-signature@1.0.6:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
+  integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
+
+cookie@0.3.1:
+  version "0.3.1"
+  resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
+  integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=
+
+cookie@0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
+  integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
+
+copy-descriptor@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
+  integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
+
+core-js@^2.4.0:
+  version "2.6.11"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c"
+  integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==
+
+core-util-is@1.0.2, core-util-is@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
+  integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
+
+cors@^2.8.4:
+  version "2.8.5"
+  resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
+  integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
+  dependencies:
+    object-assign "^4"
+    vary "^1"
+
+crc32-stream@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-3.0.1.tgz#cae6eeed003b0e44d739d279de5ae63b171b4e85"
+  integrity sha512-mctvpXlbzsvK+6z8kJwSJ5crm7yBwrQMTybJzMw1O4lLGJqjlDCXY2Zw7KheiA6XBEcBmfLx1D88mjRGVJtY9w==
+  dependencies:
+    crc "^3.4.4"
+    readable-stream "^3.4.0"
+
+crc@^3.4.4:
+  version "3.8.0"
+  resolved "https://registry.yarnpkg.com/crc/-/crc-3.8.0.tgz#ad60269c2c856f8c299e2c4cc0de4556914056c6"
+  integrity sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==
+  dependencies:
+    buffer "^5.1.0"
+
+create-error-class@^3.0.0:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6"
+  integrity sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=
+  dependencies:
+    capture-stack-trace "^1.0.0"
+
+cross-spawn@^5.0.1:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
+  integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=
+  dependencies:
+    lru-cache "^4.0.1"
+    shebang-command "^1.2.0"
+    which "^1.2.9"
+
+cross-spawn@^6.0.5:
+  version "6.0.5"
+  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
+  integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
+  dependencies:
+    nice-try "^1.0.4"
+    path-key "^2.0.1"
+    semver "^5.5.0"
+    shebang-command "^1.2.0"
+    which "^1.2.9"
+
+crypt@~0.0.1:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
+  integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=
+
+crypto-random-string@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
+  integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=
+
+css-slam@^2.1.2:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/css-slam/-/css-slam-2.1.2.tgz#3d35b1922cb3e0002a45c89ab189492508c493e5"
+  integrity sha512-cObrY+mhFEmepWpua6EpMrgRNTQ0eeym+kvR0lukI6hDEzK7F8himEDS4cJ9+fPHCoArTzVrrR0d+oAUbTR1NA==
+  dependencies:
+    command-line-args "^5.0.2"
+    command-line-usage "^5.0.5"
+    dom5 "^3.0.0"
+    parse5 "^4.0.0"
+    shady-css-parser "^0.1.0"
+
+cssbeautify@^0.3.1:
+  version "0.3.1"
+  resolved "https://registry.yarnpkg.com/cssbeautify/-/cssbeautify-0.3.1.tgz#12dd1f734035c2e6faca67dcbdcef74e42811397"
+  integrity sha1-Et0fc0A1wub6ymfcvc73TkKBE5c=
+
+currently-unhandled@^0.4.1:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
+  integrity sha1-mI3zP+qxke95mmE2nddsF635V+o=
+  dependencies:
+    array-find-index "^1.0.1"
+
+dashdash@^1.12.0:
+  version "1.14.1"
+  resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
+  integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=
+  dependencies:
+    assert-plus "^1.0.0"
+
+debug@2.6.8:
+  version "2.6.8"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc"
+  integrity sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=
+  dependencies:
+    ms "2.0.0"
+
+debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8:
+  version "2.6.9"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
+  integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
+  dependencies:
+    ms "2.0.0"
+
+debug@3.2.6, debug@^3.0.0, debug@^3.1.0:
+  version "3.2.6"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
+  integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
+  dependencies:
+    ms "^2.1.1"
+
+debug@^4.1.0, debug@^4.1.1, debug@~4.1.0:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
+  integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
+  dependencies:
+    ms "^2.1.1"
+
+debug@~3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
+  integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
+  dependencies:
+    ms "2.0.0"
+
+decamelize@^1.1.2, decamelize@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+  integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
+
+decode-uri-component@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
+  integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
+
+deep-eql@^0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2"
+  integrity sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=
+  dependencies:
+    type-detect "0.1.1"
+
+deep-eql@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df"
+  integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==
+  dependencies:
+    type-detect "^4.0.0"
+
+deep-extend@^0.6.0, deep-extend@~0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
+  integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
+
+define-properties@^1.1.2, define-properties@^1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
+  integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
+  dependencies:
+    object-keys "^1.0.12"
+
+define-property@^0.2.5:
+  version "0.2.5"
+  resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116"
+  integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=
+  dependencies:
+    is-descriptor "^0.1.0"
+
+define-property@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6"
+  integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY=
+  dependencies:
+    is-descriptor "^1.0.0"
+
+define-property@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d"
+  integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==
+  dependencies:
+    is-descriptor "^1.0.2"
+    isobject "^3.0.1"
+
+delayed-stream@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+  integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
+
+depd@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
+  integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
+
+destroy@~1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
+  integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
+
+detect-file@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7"
+  integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=
+
+detect-indent@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208"
+  integrity sha1-920GQ1LN9Docts5hnE7jqUdd4gg=
+  dependencies:
+    repeating "^2.0.0"
+
+detect-node@^2.0.3:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
+  integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==
+
+diagnostics@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/diagnostics/-/diagnostics-1.1.1.tgz#cab6ac33df70c9d9a727490ae43ac995a769b22a"
+  integrity sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==
+  dependencies:
+    colorspace "1.1.x"
+    enabled "1.0.x"
+    kuler "1.0.x"
+
+dicer@0.2.5:
+  version "0.2.5"
+  resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.2.5.tgz#5996c086bb33218c812c090bddc09cd12facb70f"
+  integrity sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=
+  dependencies:
+    readable-stream "1.1.x"
+    streamsearch "0.1.2"
+
+diff@3.2.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9"
+  integrity sha1-yc45Okt8vQsFinJck98pkCeGj/k=
+
+diff@3.5.0, diff@^3.1.0:
+  version "3.5.0"
+  resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
+  integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
+
+doctrine@^2.0.2:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
+  integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==
+  dependencies:
+    esutils "^2.0.2"
+
+dom-urls@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/dom-urls/-/dom-urls-1.1.0.tgz#001ddf81628cd1e706125c7176f53ccec55d918e"
+  integrity sha1-AB3fgWKM0ecGElxxdvU8zsVdkY4=
+  dependencies:
+    urijs "^1.16.1"
+
+dom5@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/dom5/-/dom5-3.0.1.tgz#cdfc7331f376e284bf379e6ea054afc136702944"
+  integrity sha512-JPFiouQIr16VQ4dX6i0+Hpbg3H2bMKPmZ+WZgBOSSvOPx9QHwwY8sPzeM2baUtViESYto6wC2nuZOMC/6gulcA==
+  dependencies:
+    "@types/parse5" "^2.2.34"
+    clone "^2.1.0"
+    parse5 "^4.0.0"
+
+dot-prop@^4.1.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57"
+  integrity sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==
+  dependencies:
+    is-obj "^1.0.0"
+
+duplexer2@^0.1.2:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1"
+  integrity sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=
+  dependencies:
+    readable-stream "^2.0.2"
+
+duplexer3@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
+  integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=
+
+duplexify@^3.2.0, duplexify@^3.5.0:
+  version "3.7.1"
+  resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309"
+  integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==
+  dependencies:
+    end-of-stream "^1.0.0"
+    inherits "^2.0.1"
+    readable-stream "^2.0.0"
+    stream-shift "^1.0.0"
+
+ecc-jsbn@~0.1.1:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
+  integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=
+  dependencies:
+    jsbn "~0.1.0"
+    safer-buffer "^2.1.0"
+
+ee-first@1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
+  integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
+
+emitter-component@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/emitter-component/-/emitter-component-1.1.1.tgz#065e2dbed6959bf470679edabeaf7981d1003ab6"
+  integrity sha1-Bl4tvtaVm/RwZ57avq95gdEAOrY=
+
+emoji-regex@^7.0.1:
+  version "7.0.3"
+  resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
+  integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
+
+enabled@1.0.x:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/enabled/-/enabled-1.0.2.tgz#965f6513d2c2d1c5f4652b64a2e3396467fc2f93"
+  integrity sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=
+  dependencies:
+    env-variable "0.0.x"
+
+encodeurl@~1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
+  integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
+
+end-of-stream@^1.0.0, end-of-stream@^1.4.1:
+  version "1.4.4"
+  resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
+  integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
+  dependencies:
+    once "^1.4.0"
+
+engine.io-client@~3.4.0:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.4.0.tgz#82a642b42862a9b3f7a188f41776b2deab643700"
+  integrity sha512-a4J5QO2k99CM2a0b12IznnyQndoEvtA4UAldhGzKqnHf42I3Qs2W5SPnDvatZRcMaNZs4IevVicBPayxYt6FwA==
+  dependencies:
+    component-emitter "1.2.1"
+    component-inherit "0.0.3"
+    debug "~4.1.0"
+    engine.io-parser "~2.2.0"
+    has-cors "1.1.0"
+    indexof "0.0.1"
+    parseqs "0.0.5"
+    parseuri "0.0.5"
+    ws "~6.1.0"
+    xmlhttprequest-ssl "~1.5.4"
+    yeast "0.1.2"
+
+engine.io-parser@~2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.2.0.tgz#312c4894f57d52a02b420868da7b5c1c84af80ed"
+  integrity sha512-6I3qD9iUxotsC5HEMuuGsKA0cXerGz+4uGcXQEkfBidgKf0amsjrrtwcbwK/nzpZBxclXlV7gGl9dgWvu4LF6w==
+  dependencies:
+    after "0.8.2"
+    arraybuffer.slice "~0.0.7"
+    base64-arraybuffer "0.1.5"
+    blob "0.0.5"
+    has-binary2 "~1.0.2"
+
+engine.io@~3.4.0:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.4.0.tgz#3a962cc4535928c252759a00f98519cb46c53ff3"
+  integrity sha512-XCyYVWzcHnK5cMz7G4VTu2W7zJS7SM1QkcelghyIk/FmobWBtXE7fwhBusEKvCSqc3bMh8fNFMlUkCKTFRxH2w==
+  dependencies:
+    accepts "~1.3.4"
+    base64id "2.0.0"
+    cookie "0.3.1"
+    debug "~4.1.0"
+    engine.io-parser "~2.2.0"
+    ws "^7.1.2"
+
+env-variable@0.0.x:
+  version "0.0.5"
+  resolved "https://registry.yarnpkg.com/env-variable/-/env-variable-0.0.5.tgz#913dd830bef11e96a039c038d4130604eba37f88"
+  integrity sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==
+
+error-ex@^1.2.0:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
+  integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
+  dependencies:
+    is-arrayish "^0.2.1"
+
+es-abstract@^1.17.0-next.1:
+  version "1.17.4"
+  resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.4.tgz#e3aedf19706b20e7c2594c35fc0d57605a79e184"
+  integrity sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==
+  dependencies:
+    es-to-primitive "^1.2.1"
+    function-bind "^1.1.1"
+    has "^1.0.3"
+    has-symbols "^1.0.1"
+    is-callable "^1.1.5"
+    is-regex "^1.0.5"
+    object-inspect "^1.7.0"
+    object-keys "^1.1.1"
+    object.assign "^4.1.0"
+    string.prototype.trimleft "^2.1.1"
+    string.prototype.trimright "^2.1.1"
+
+es-to-primitive@^1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
+  integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==
+  dependencies:
+    is-callable "^1.1.4"
+    is-date-object "^1.0.1"
+    is-symbol "^1.0.2"
+
+es6-promise@^4.0.3, es6-promise@^4.0.5:
+  version "4.2.8"
+  resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
+  integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==
+
+es6-promisify@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
+  integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=
+  dependencies:
+    es6-promise "^4.0.3"
+
+es6-promisify@^6.0.0:
+  version "6.0.2"
+  resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-6.0.2.tgz#525c23725b8510f5f1f2feb5a1fbad93a93e29b4"
+  integrity sha512-eO6vFm0JvqGzjWIQA6QVKjxpmELfhWbDUWHm1rPfIbn55mhKPiAa5xpLmQWJrNa629ZIeQ8ZvMAi13kvrjK6Mg==
+
+escape-html@^1.0.3, escape-html@~1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
+  integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
+
+escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.4, escape-string-regexp@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+  integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
+
+espree@^3.5.2:
+  version "3.5.4"
+  resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7"
+  integrity sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==
+  dependencies:
+    acorn "^5.5.0"
+    acorn-jsx "^3.0.0"
+
+esprima@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
+  integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
+
+esutils@^2.0.2:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
+  integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
+
+etag@~1.8.1:
+  version "1.8.1"
+  resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
+  integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
+
+eventemitter3@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb"
+  integrity sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==
+
+execa@^0.7.0:
+  version "0.7.0"
+  resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
+  integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=
+  dependencies:
+    cross-spawn "^5.0.1"
+    get-stream "^3.0.0"
+    is-stream "^1.1.0"
+    npm-run-path "^2.0.0"
+    p-finally "^1.0.0"
+    signal-exit "^3.0.0"
+    strip-eof "^1.0.0"
+
+expand-brackets@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
+  integrity sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=
+  dependencies:
+    is-posix-bracket "^0.1.0"
+
+expand-brackets@^2.1.4:
+  version "2.1.4"
+  resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622"
+  integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI=
+  dependencies:
+    debug "^2.3.3"
+    define-property "^0.2.5"
+    extend-shallow "^2.0.1"
+    posix-character-classes "^0.1.0"
+    regex-not "^1.0.0"
+    snapdragon "^0.8.1"
+    to-regex "^3.0.1"
+
+expand-range@^1.8.1:
+  version "1.8.2"
+  resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337"
+  integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=
+  dependencies:
+    fill-range "^2.1.0"
+
+expand-tilde@^2.0.0, expand-tilde@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502"
+  integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=
+  dependencies:
+    homedir-polyfill "^1.0.1"
+
+express@^4.15.3, express@^4.8.5:
+  version "4.17.1"
+  resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
+  integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==
+  dependencies:
+    accepts "~1.3.7"
+    array-flatten "1.1.1"
+    body-parser "1.19.0"
+    content-disposition "0.5.3"
+    content-type "~1.0.4"
+    cookie "0.4.0"
+    cookie-signature "1.0.6"
+    debug "2.6.9"
+    depd "~1.1.2"
+    encodeurl "~1.0.2"
+    escape-html "~1.0.3"
+    etag "~1.8.1"
+    finalhandler "~1.1.2"
+    fresh "0.5.2"
+    merge-descriptors "1.0.1"
+    methods "~1.1.2"
+    on-finished "~2.3.0"
+    parseurl "~1.3.3"
+    path-to-regexp "0.1.7"
+    proxy-addr "~2.0.5"
+    qs "6.7.0"
+    range-parser "~1.2.1"
+    safe-buffer "5.1.2"
+    send "0.17.1"
+    serve-static "1.14.1"
+    setprototypeof "1.1.1"
+    statuses "~1.5.0"
+    type-is "~1.6.18"
+    utils-merge "1.0.1"
+    vary "~1.1.2"
+
+extend-shallow@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
+  integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=
+  dependencies:
+    is-extendable "^0.1.0"
+
+extend-shallow@^3.0.0, extend-shallow@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8"
+  integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=
+  dependencies:
+    assign-symbols "^1.0.0"
+    is-extendable "^1.0.1"
+
+extend@^3.0.0, extend@~3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
+  integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
+
+extglob@^0.3.1:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
+  integrity sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=
+  dependencies:
+    is-extglob "^1.0.0"
+
+extglob@^2.0.4:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543"
+  integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==
+  dependencies:
+    array-unique "^0.3.2"
+    define-property "^1.0.0"
+    expand-brackets "^2.1.4"
+    extend-shallow "^2.0.1"
+    fragment-cache "^0.2.1"
+    regex-not "^1.0.0"
+    snapdragon "^0.8.1"
+    to-regex "^3.0.1"
+
+extsprintf@1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
+  integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=
+
+extsprintf@^1.2.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
+  integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
+
+fast-deep-equal@^3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4"
+  integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==
+
+fast-json-stable-stringify@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
+  integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
+
+fast-safe-stringify@^2.0.4:
+  version "2.0.7"
+  resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743"
+  integrity sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==
+
+fd-slicer@~1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e"
+  integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=
+  dependencies:
+    pend "~1.2.0"
+
+fecha@^2.3.3:
+  version "2.3.3"
+  resolved "https://registry.yarnpkg.com/fecha/-/fecha-2.3.3.tgz#948e74157df1a32fd1b12c3a3c3cdcb6ec9d96cd"
+  integrity sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==
+
+filename-regex@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
+  integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=
+
+fill-range@^2.1.0:
+  version "2.2.4"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565"
+  integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==
+  dependencies:
+    is-number "^2.1.0"
+    isobject "^2.0.0"
+    randomatic "^3.0.0"
+    repeat-element "^1.1.2"
+    repeat-string "^1.5.2"
+
+fill-range@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"
+  integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=
+  dependencies:
+    extend-shallow "^2.0.1"
+    is-number "^3.0.0"
+    repeat-string "^1.6.1"
+    to-regex-range "^2.1.0"
+
+finalhandler@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
+  integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
+  dependencies:
+    debug "2.6.9"
+    encodeurl "~1.0.2"
+    escape-html "~1.0.3"
+    on-finished "~2.3.0"
+    parseurl "~1.3.3"
+    statuses "~1.5.0"
+    unpipe "~1.0.0"
+
+find-port@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/find-port/-/find-port-1.0.1.tgz#db084a6cbf99564d99869ae79fbdecf66e8a185c"
+  integrity sha1-2whKbL+ZVk2Zhprnn73s9m6KGFw=
+  dependencies:
+    async "~0.2.9"
+
+find-replace@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-3.0.0.tgz#3e7e23d3b05167a76f770c9fbd5258b0def68c38"
+  integrity sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==
+  dependencies:
+    array-back "^3.0.1"
+
+find-up@3.0.0, find-up@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
+  integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==
+  dependencies:
+    locate-path "^3.0.0"
+
+find-up@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
+  integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=
+  dependencies:
+    path-exists "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+findup-sync@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc"
+  integrity sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=
+  dependencies:
+    detect-file "^1.0.0"
+    is-glob "^3.1.0"
+    micromatch "^3.0.4"
+    resolve-dir "^1.0.1"
+
+first-chunk-stream@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz#59bfb50cd905f60d7c394cd3d9acaab4e6ad934e"
+  integrity sha1-Wb+1DNkF9g18OUzT2ayqtOatk04=
+
+flat@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2"
+  integrity sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==
+  dependencies:
+    is-buffer "~2.0.3"
+
+follow-redirects@^1.0.0:
+  version "1.9.0"
+  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.9.0.tgz#8d5bcdc65b7108fe1508649c79c12d732dcedb4f"
+  integrity sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A==
+  dependencies:
+    debug "^3.0.0"
+
+for-in@^1.0.1, for-in@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
+  integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=
+
+for-own@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce"
+  integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=
+  dependencies:
+    for-in "^1.0.1"
+
+forever-agent@~0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
+  integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
+
+fork-stream@^0.0.4:
+  version "0.0.4"
+  resolved "https://registry.yarnpkg.com/fork-stream/-/fork-stream-0.0.4.tgz#db849fce77f6708a5f8f386ae533a0907b54ae70"
+  integrity sha1-24Sfznf2cIpfjzhq5TOgkHtUrnA=
+
+form-data@~2.3.2:
+  version "2.3.3"
+  resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
+  integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==
+  dependencies:
+    asynckit "^0.4.0"
+    combined-stream "^1.0.6"
+    mime-types "^2.1.12"
+
+formatio@1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/formatio/-/formatio-1.1.1.tgz#5ed3ccd636551097383465d996199100e86161e9"
+  integrity sha1-XtPM1jZVEJc4NGXZlhmRAOhhYek=
+  dependencies:
+    samsam "~1.1"
+
+formatio@1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/formatio/-/formatio-1.2.0.tgz#f3b2167d9068c4698a8d51f4f760a39a54d818eb"
+  integrity sha1-87IWfZBoxGmKjVH092CjmlTYGOs=
+  dependencies:
+    samsam "1.x"
+
+forwarded@~0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
+  integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=
+
+fragment-cache@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
+  integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=
+  dependencies:
+    map-cache "^0.2.2"
+
+freeport@^1.0.4:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/freeport/-/freeport-1.0.5.tgz#255e8ab84170c33ba85d990e821ae5f4a1a9bc5d"
+  integrity sha1-JV6KuEFwwzuoXZkOghrl9KGpvF0=
+
+fresh@0.5.2:
+  version "0.5.2"
+  resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
+  integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
+
+fs-constants@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
+  integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
+
+fs.realpath@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+  integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
+
+function-bind@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
+  integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
+
+gensync@^1.0.0-beta.1:
+  version "1.0.0-beta.1"
+  resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269"
+  integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==
+
+get-caller-file@^2.0.1:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
+  integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
+
+get-func-name@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41"
+  integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=
+
+get-stdin@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
+  integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=
+
+get-stream@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
+  integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
+
+get-value@^2.0.3, get-value@^2.0.6:
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
+  integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=
+
+getpass@^0.1.1:
+  version "0.1.7"
+  resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
+  integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=
+  dependencies:
+    assert-plus "^1.0.0"
+
+glob-base@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
+  integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=
+  dependencies:
+    glob-parent "^2.0.0"
+    is-glob "^2.0.0"
+
+glob-parent@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28"
+  integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=
+  dependencies:
+    is-glob "^2.0.0"
+
+glob-parent@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
+  integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=
+  dependencies:
+    is-glob "^3.1.0"
+    path-dirname "^1.0.0"
+
+glob-stream@^5.3.2:
+  version "5.3.5"
+  resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-5.3.5.tgz#a55665a9a8ccdc41915a87c701e32d4e016fad22"
+  integrity sha1-pVZlqajM3EGRWofHAeMtTgFvrSI=
+  dependencies:
+    extend "^3.0.0"
+    glob "^5.0.3"
+    glob-parent "^3.0.0"
+    micromatch "^2.3.7"
+    ordered-read-streams "^0.3.0"
+    through2 "^0.6.0"
+    to-absolute-glob "^0.1.1"
+    unique-stream "^2.0.2"
+
+glob@7.1.1:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
+  integrity sha1-gFIR3wT6rxxjo2ADBs31reULLsg=
+  dependencies:
+    fs.realpath "^1.0.0"
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "^3.0.2"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+glob@7.1.3:
+  version "7.1.3"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
+  integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==
+  dependencies:
+    fs.realpath "^1.0.0"
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "^3.0.4"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+glob@^5.0.3:
+  version "5.0.15"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1"
+  integrity sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=
+  dependencies:
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "2 || 3"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4:
+  version "7.1.6"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
+  integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
+  dependencies:
+    fs.realpath "^1.0.0"
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "^3.0.4"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+global-dirs@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445"
+  integrity sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=
+  dependencies:
+    ini "^1.3.4"
+
+global-modules@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea"
+  integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==
+  dependencies:
+    global-prefix "^1.0.1"
+    is-windows "^1.0.1"
+    resolve-dir "^1.0.0"
+
+global-prefix@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe"
+  integrity sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=
+  dependencies:
+    expand-tilde "^2.0.2"
+    homedir-polyfill "^1.0.1"
+    ini "^1.3.4"
+    is-windows "^1.0.1"
+    which "^1.2.14"
+
+globals@^11.1.0:
+  version "11.12.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
+  integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
+
+globals@^9.18.0:
+  version "9.18.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a"
+  integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==
+
+got@^6.7.1:
+  version "6.7.1"
+  resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0"
+  integrity sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=
+  dependencies:
+    create-error-class "^3.0.0"
+    duplexer3 "^0.1.4"
+    get-stream "^3.0.0"
+    is-redirect "^1.0.0"
+    is-retry-allowed "^1.0.0"
+    is-stream "^1.0.0"
+    lowercase-keys "^1.0.0"
+    safe-buffer "^5.0.1"
+    timed-out "^4.0.0"
+    unzip-response "^2.0.1"
+    url-parse-lax "^1.0.0"
+
+graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.2.0:
+  version "4.2.3"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423"
+  integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==
+
+"graceful-readlink@>= 1.0.0":
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
+  integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=
+
+growl@1.10.5:
+  version "1.10.5"
+  resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e"
+  integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==
+
+growl@1.9.2:
+  version "1.9.2"
+  resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f"
+  integrity sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=
+
+gulp-if@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/gulp-if/-/gulp-if-2.0.2.tgz#a497b7e7573005041caa2bc8b7dda3c80444d629"
+  integrity sha1-pJe351cwBQQcqivIt92jyARE1ik=
+  dependencies:
+    gulp-match "^1.0.3"
+    ternary-stream "^2.0.1"
+    through2 "^2.0.1"
+
+gulp-match@^1.0.3:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/gulp-match/-/gulp-match-1.1.0.tgz#552b7080fc006ee752c90563f9fec9d61aafdf4f"
+  integrity sha512-DlyVxa1Gj24DitY2OjEsS+X6tDpretuxD6wTfhXE/Rw2hweqc1f6D/XtsJmoiCwLWfXgR87W9ozEityPCVzGtQ==
+  dependencies:
+    minimatch "^3.0.3"
+
+gulp-sourcemaps@1.6.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/gulp-sourcemaps/-/gulp-sourcemaps-1.6.0.tgz#b86ff349d801ceb56e1d9e7dc7bbcb4b7dee600c"
+  integrity sha1-uG/zSdgBzrVuHZ59x7vLS33uYAw=
+  dependencies:
+    convert-source-map "^1.1.1"
+    graceful-fs "^4.1.2"
+    strip-bom "^2.0.0"
+    through2 "^2.0.0"
+    vinyl "^1.0.0"
+
+handle-thing@^1.2.5:
+  version "1.2.5"
+  resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4"
+  integrity sha1-/Xqtcmvxpf0W38KbL3pmAdJxOcQ=
+
+har-schema@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
+  integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
+
+har-validator@~5.1.0:
+  version "5.1.3"
+  resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080"
+  integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==
+  dependencies:
+    ajv "^6.5.5"
+    har-schema "^2.0.0"
+
+has-ansi@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
+  integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=
+  dependencies:
+    ansi-regex "^2.0.0"
+
+has-binary2@~1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d"
+  integrity sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==
+  dependencies:
+    isarray "2.0.1"
+
+has-color@~0.1.0:
+  version "0.1.7"
+  resolved "https://registry.yarnpkg.com/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f"
+  integrity sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=
+
+has-cors@1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39"
+  integrity sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=
+
+has-flag@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
+  integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=
+
+has-flag@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+  integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
+
+has-symbols@^1.0.0, has-symbols@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
+  integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==
+
+has-value@^0.3.1:
+  version "0.3.1"
+  resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
+  integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=
+  dependencies:
+    get-value "^2.0.3"
+    has-values "^0.1.4"
+    isobject "^2.0.0"
+
+has-value@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177"
+  integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=
+  dependencies:
+    get-value "^2.0.6"
+    has-values "^1.0.0"
+    isobject "^3.0.0"
+
+has-values@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771"
+  integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E=
+
+has-values@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f"
+  integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=
+  dependencies:
+    is-number "^3.0.0"
+    kind-of "^4.0.0"
+
+has@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
+  integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
+  dependencies:
+    function-bind "^1.1.1"
+
+he@1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
+  integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0=
+
+he@1.2.0, he@1.2.x:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
+  integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
+
+homedir-polyfill@^1.0.1:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8"
+  integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==
+  dependencies:
+    parse-passwd "^1.0.0"
+
+hosted-git-info@^2.1.4:
+  version "2.8.5"
+  resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.5.tgz#759cfcf2c4d156ade59b0b2dfabddc42a6b9c70c"
+  integrity sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==
+
+hpack.js@^2.1.6:
+  version "2.1.6"
+  resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2"
+  integrity sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=
+  dependencies:
+    inherits "^2.0.1"
+    obuf "^1.0.0"
+    readable-stream "^2.0.1"
+    wbuf "^1.1.0"
+
+html-minifier@^3.5.10:
+  version "3.5.21"
+  resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.21.tgz#d0040e054730e354db008463593194015212d20c"
+  integrity sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==
+  dependencies:
+    camel-case "3.0.x"
+    clean-css "4.2.x"
+    commander "2.17.x"
+    he "1.2.x"
+    param-case "2.1.x"
+    relateurl "0.2.x"
+    uglify-js "3.4.x"
+
+http-deceiver@^1.2.7:
+  version "1.2.7"
+  resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87"
+  integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=
+
+http-errors@1.7.2:
+  version "1.7.2"
+  resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f"
+  integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==
+  dependencies:
+    depd "~1.1.2"
+    inherits "2.0.3"
+    setprototypeof "1.1.1"
+    statuses ">= 1.5.0 < 2"
+    toidentifier "1.0.0"
+
+http-errors@~1.6.2:
+  version "1.6.3"
+  resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
+  integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=
+  dependencies:
+    depd "~1.1.2"
+    inherits "2.0.3"
+    setprototypeof "1.1.0"
+    statuses ">= 1.4.0 < 2"
+
+http-errors@~1.7.2:
+  version "1.7.3"
+  resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06"
+  integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==
+  dependencies:
+    depd "~1.1.2"
+    inherits "2.0.4"
+    setprototypeof "1.1.1"
+    statuses ">= 1.5.0 < 2"
+    toidentifier "1.0.0"
+
+http-proxy-middleware@^0.17.2:
+  version "0.17.4"
+  resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.17.4.tgz#642e8848851d66f09d4f124912846dbaeb41b833"
+  integrity sha1-ZC6ISIUdZvCdTxJJEoRtuutBuDM=
+  dependencies:
+    http-proxy "^1.16.2"
+    is-glob "^3.1.0"
+    lodash "^4.17.2"
+    micromatch "^2.3.11"
+
+http-proxy@^1.16.2:
+  version "1.18.0"
+  resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.0.tgz#dbe55f63e75a347db7f3d99974f2692a314a6a3a"
+  integrity sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==
+  dependencies:
+    eventemitter3 "^4.0.0"
+    follow-redirects "^1.0.0"
+    requires-port "^1.0.0"
+
+http-signature@~1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
+  integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=
+  dependencies:
+    assert-plus "^1.0.0"
+    jsprim "^1.2.2"
+    sshpk "^1.7.0"
+
+https-proxy-agent@^2.2.1:
+  version "2.2.4"
+  resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b"
+  integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==
+  dependencies:
+    agent-base "^4.3.0"
+    debug "^3.1.0"
+
+https-proxy-agent@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz#b8c286433e87602311b01c8ea34413d856a4af81"
+  integrity sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==
+  dependencies:
+    agent-base "^4.3.0"
+    debug "^3.1.0"
+
+iconv-lite@0.4.24:
+  version "0.4.24"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
+  integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
+  dependencies:
+    safer-buffer ">= 2.1.2 < 3"
+
+ieee754@^1.1.4:
+  version "1.1.13"
+  resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84"
+  integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==
+
+import-lazy@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
+  integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=
+
+imurmurhash@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
+  integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
+
+indent-string@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80"
+  integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=
+  dependencies:
+    repeating "^2.0.0"
+
+indent@0.0.2:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/indent/-/indent-0.0.2.tgz#8c79f080190559b687034b84c7aefa97d5a911d9"
+  integrity sha1-jHnwgBkFWbaHA0uEx676l9WpEdk=
+
+indexof@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
+  integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=
+
+inflight@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+  integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
+  dependencies:
+    once "^1.3.0"
+    wrappy "1"
+
+inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+  integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+
+inherits@2.0.3:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+  integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
+
+ini@^1.3.4, ini@~1.3.0:
+  version "1.3.5"
+  resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
+  integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
+
+invariant@^2.2.2:
+  version "2.2.4"
+  resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
+  integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
+  dependencies:
+    loose-envify "^1.0.0"
+
+ipaddr.js@1.9.0:
+  version "1.9.0"
+  resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65"
+  integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==
+
+is-accessor-descriptor@^0.1.6:
+  version "0.1.6"
+  resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"
+  integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=
+  dependencies:
+    kind-of "^3.0.2"
+
+is-accessor-descriptor@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656"
+  integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==
+  dependencies:
+    kind-of "^6.0.0"
+
+is-arguments@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.0.4.tgz#3faf966c7cba0ff437fb31f6250082fcf0448cf3"
+  integrity sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==
+
+is-arrayish@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+  integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
+
+is-arrayish@^0.3.1:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
+  integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==
+
+is-buffer@^1.1.5, is-buffer@~1.1.1:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
+  integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
+
+is-buffer@~2.0.3:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.4.tgz#3e572f23c8411a5cfd9557c849e3665e0b290623"
+  integrity sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==
+
+is-callable@^1.1.4, is-callable@^1.1.5:
+  version "1.1.5"
+  resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab"
+  integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==
+
+is-ci@^1.0.10:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c"
+  integrity sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==
+  dependencies:
+    ci-info "^1.5.0"
+
+is-data-descriptor@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
+  integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=
+  dependencies:
+    kind-of "^3.0.2"
+
+is-data-descriptor@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7"
+  integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==
+  dependencies:
+    kind-of "^6.0.0"
+
+is-date-object@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e"
+  integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==
+
+is-descriptor@^0.1.0:
+  version "0.1.6"
+  resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca"
+  integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==
+  dependencies:
+    is-accessor-descriptor "^0.1.6"
+    is-data-descriptor "^0.1.4"
+    kind-of "^5.0.0"
+
+is-descriptor@^1.0.0, is-descriptor@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec"
+  integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==
+  dependencies:
+    is-accessor-descriptor "^1.0.0"
+    is-data-descriptor "^1.0.0"
+    kind-of "^6.0.2"
+
+is-dotfile@^1.0.0:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1"
+  integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=
+
+is-equal-shallow@^0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534"
+  integrity sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=
+  dependencies:
+    is-primitive "^2.0.0"
+
+is-extendable@^0.1.0, is-extendable@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
+  integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=
+
+is-extendable@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4"
+  integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==
+  dependencies:
+    is-plain-object "^2.0.4"
+
+is-extglob@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
+  integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=
+
+is-extglob@^2.1.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+  integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
+
+is-finite@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
+  integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=
+  dependencies:
+    number-is-nan "^1.0.0"
+
+is-fullwidth-code-point@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
+  integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
+
+is-generator-function@^1.0.7:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.7.tgz#d2132e529bb0000a7f80794d4bdf5cd5e5813522"
+  integrity sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw==
+
+is-glob@^2.0.0, is-glob@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
+  integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=
+  dependencies:
+    is-extglob "^1.0.0"
+
+is-glob@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
+  integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=
+  dependencies:
+    is-extglob "^2.1.0"
+
+is-installed-globally@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80"
+  integrity sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=
+  dependencies:
+    global-dirs "^0.1.0"
+    is-path-inside "^1.0.0"
+
+is-npm@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4"
+  integrity sha1-8vtjpl5JBbQGyGBydloaTceTufQ=
+
+is-number@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
+  integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=
+  dependencies:
+    kind-of "^3.0.2"
+
+is-number@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
+  integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=
+  dependencies:
+    kind-of "^3.0.2"
+
+is-number@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff"
+  integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==
+
+is-obj@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
+  integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8=
+
+is-path-inside@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036"
+  integrity sha1-jvW33lBDej/cprToZe96pVy0gDY=
+  dependencies:
+    path-is-inside "^1.0.1"
+
+is-plain-object@^2.0.3, is-plain-object@^2.0.4:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
+  integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==
+  dependencies:
+    isobject "^3.0.1"
+
+is-posix-bracket@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
+  integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=
+
+is-primitive@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
+  integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU=
+
+is-redirect@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24"
+  integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=
+
+is-regex@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae"
+  integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==
+  dependencies:
+    has "^1.0.3"
+
+is-retry-allowed@^1.0.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4"
+  integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==
+
+is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
+  integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
+
+is-symbol@^1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937"
+  integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==
+  dependencies:
+    has-symbols "^1.0.1"
+
+is-typedarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
+  integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
+
+is-utf8@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
+  integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=
+
+is-valid-glob@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-0.3.0.tgz#d4b55c69f51886f9b65c70d6c2622d37e29f48fe"
+  integrity sha1-1LVcafUYhvm2XHDWwmItN+KfSP4=
+
+is-windows@^1.0.1, is-windows@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
+  integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
+
+isarray@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
+  integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
+
+isarray@1.0.0, isarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+  integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
+
+isarray@2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e"
+  integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=
+
+isexe@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+  integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
+
+isobject@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
+  integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=
+  dependencies:
+    isarray "1.0.0"
+
+isobject@^3.0.0, isobject@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
+  integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
+
+isstream@~0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
+  integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
+
+"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+  integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
+
+js-tokens@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
+  integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls=
+
+js-yaml@3.13.1:
+  version "3.13.1"
+  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
+  integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
+  dependencies:
+    argparse "^1.0.7"
+    esprima "^4.0.0"
+
+jsbn@~0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
+  integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
+
+jsesc@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b"
+  integrity sha1-RsP+yMGJKxKwgz25vHYiF226s0s=
+
+jsesc@^2.5.1:
+  version "2.5.2"
+  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
+  integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
+
+jsesc@~0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
+  integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=
+
+json-schema-traverse@^0.4.1:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
+  integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
+
+json-schema@0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
+  integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
+
+json-stable-stringify-without-jsonify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
+  integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
+
+json-stringify-safe@~5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
+  integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
+
+json3@3.3.2:
+  version "3.3.2"
+  resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1"
+  integrity sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=
+
+json5@^2.1.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.1.tgz#81b6cb04e9ba496f1c7005d07b4368a2638f90b6"
+  integrity sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==
+  dependencies:
+    minimist "^1.2.0"
+
+jsonschema@^1.1.0, jsonschema@^1.1.1:
+  version "1.2.5"
+  resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.2.5.tgz#bab69d97fa28946aec0a56a9cc266d23fe80ae61"
+  integrity sha512-kVTF+08x25PQ0CjuVc0gRM9EUPb0Fe9Ln/utFOgcdxEIOHuU7ooBk/UPTd7t1M91pP35m0MU1T8M5P7vP1bRRw==
+
+jsprim@^1.2.2:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
+  integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=
+  dependencies:
+    assert-plus "1.0.0"
+    extsprintf "1.3.0"
+    json-schema "0.2.3"
+    verror "1.10.0"
+
+kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
+  version "3.2.2"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
+  integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=
+  dependencies:
+    is-buffer "^1.1.5"
+
+kind-of@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57"
+  integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc=
+  dependencies:
+    is-buffer "^1.1.5"
+
+kind-of@^5.0.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d"
+  integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==
+
+kind-of@^6.0.0, kind-of@^6.0.2:
+  version "6.0.3"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
+  integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
+
+kuler@1.0.x:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/kuler/-/kuler-1.0.1.tgz#ef7c784f36c9fb6e16dd3150d152677b2b0228a6"
+  integrity sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==
+  dependencies:
+    colornames "^1.1.1"
+
+latest-version@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15"
+  integrity sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=
+  dependencies:
+    package-json "^4.0.0"
+
+launchpad@^0.7.0:
+  version "0.7.5"
+  resolved "https://registry.yarnpkg.com/launchpad/-/launchpad-0.7.5.tgz#a16950c937572f10ef01c9be945a96f7aef8e427"
+  integrity sha512-gsYFgT8XKL3X2XZHPPPrgwM0JqeQwGpSWnzg7EYadBY3MirbQrTVq6L4fm6l7UE2T+7gnfuhiGkKr/xxuU/fdw==
+  dependencies:
+    async "^2.0.1"
+    browserstack "^1.2.0"
+    debug "^2.2.0"
+    mkdirp "^0.5.1"
+    plist "^2.0.1"
+    q "^1.4.1"
+    rimraf "^3.0.0"
+    underscore "^1.8.3"
+
+lazystream@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4"
+  integrity sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=
+  dependencies:
+    readable-stream "^2.0.5"
+
+load-json-file@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
+  integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=
+  dependencies:
+    graceful-fs "^4.1.2"
+    parse-json "^2.2.0"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+    strip-bom "^2.0.0"
+
+locate-path@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
+  integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==
+  dependencies:
+    p-locate "^3.0.0"
+    path-exists "^3.0.0"
+
+lodash._baseassign@^3.0.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e"
+  integrity sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=
+  dependencies:
+    lodash._basecopy "^3.0.0"
+    lodash.keys "^3.0.0"
+
+lodash._basecopy@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36"
+  integrity sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=
+
+lodash._basecreate@^3.0.0:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz#1bc661614daa7fc311b7d03bf16806a0213cf821"
+  integrity sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=
+
+lodash._getnative@^3.0.0:
+  version "3.9.1"
+  resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
+  integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=
+
+lodash._isiterateecall@^3.0.0:
+  version "3.0.9"
+  resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c"
+  integrity sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=
+
+lodash._reinterpolate@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
+  integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=
+
+lodash.camelcase@^4.3.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
+  integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY=
+
+lodash.create@3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/lodash.create/-/lodash.create-3.1.1.tgz#d7f2849f0dbda7e04682bb8cd72ab022461debe7"
+  integrity sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=
+  dependencies:
+    lodash._baseassign "^3.0.0"
+    lodash._basecreate "^3.0.0"
+    lodash._isiterateecall "^3.0.0"
+
+lodash.defaults@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
+  integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=
+
+lodash.difference@^4.5.0:
+  version "4.5.0"
+  resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c"
+  integrity sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=
+
+lodash.flatten@^4.4.0:
+  version "4.4.0"
+  resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f"
+  integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=
+
+lodash.isarguments@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a"
+  integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=
+
+lodash.isarray@^3.0.0:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55"
+  integrity sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=
+
+lodash.isequal@^4.0.0:
+  version "4.5.0"
+  resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
+  integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
+
+lodash.isplainobject@^4.0.6:
+  version "4.0.6"
+  resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
+  integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=
+
+lodash.keys@^3.0.0:
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a"
+  integrity sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=
+  dependencies:
+    lodash._getnative "^3.0.0"
+    lodash.isarguments "^3.0.0"
+    lodash.isarray "^3.0.0"
+
+lodash.padend@^4.6.1:
+  version "4.6.1"
+  resolved "https://registry.yarnpkg.com/lodash.padend/-/lodash.padend-4.6.1.tgz#53ccba047d06e158d311f45da625f4e49e6f166e"
+  integrity sha1-U8y6BH0G4VjTEfRdpiX05J5vFm4=
+
+lodash.sortby@^4.7.0:
+  version "4.7.0"
+  resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
+  integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
+
+lodash.template@^4.4.0:
+  version "4.5.0"
+  resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab"
+  integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==
+  dependencies:
+    lodash._reinterpolate "^3.0.0"
+    lodash.templatesettings "^4.0.0"
+
+lodash.templatesettings@^4.0.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33"
+  integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==
+  dependencies:
+    lodash._reinterpolate "^3.0.0"
+
+lodash.union@^4.6.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88"
+  integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=
+
+lodash@^3.0.0, lodash@^3.10.1:
+  version "3.10.1"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
+  integrity sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=
+
+lodash@^4.0.0, lodash@^4.16.6, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.2, lodash@^4.17.4:
+  version "4.17.15"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
+  integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
+
+log-symbols@2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a"
+  integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==
+  dependencies:
+    chalk "^2.0.1"
+
+logform@^1.9.1:
+  version "1.10.0"
+  resolved "https://registry.yarnpkg.com/logform/-/logform-1.10.0.tgz#c9d5598714c92b546e23f4e78147c40f1e02012e"
+  integrity sha512-em5ojIhU18fIMOw/333mD+ZLE2fis0EzXl1ZwHx4iQzmpQi6odNiY/t+ITNr33JZhT9/KEaH+UPIipr6a9EjWg==
+  dependencies:
+    colors "^1.2.1"
+    fast-safe-stringify "^2.0.4"
+    fecha "^2.3.3"
+    ms "^2.1.1"
+    triple-beam "^1.2.0"
+
+logform@^2.1.1:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/logform/-/logform-2.1.2.tgz#957155ebeb67a13164069825ce67ddb5bb2dd360"
+  integrity sha512-+lZh4OpERDBLqjiwDLpAWNQu6KMjnlXH2ByZwCuSqVPJletw0kTWJf5CgSNAUKn1KUkv3m2cUz/LK8zyEy7wzQ==
+  dependencies:
+    colors "^1.2.1"
+    fast-safe-stringify "^2.0.4"
+    fecha "^2.3.3"
+    ms "^2.1.1"
+    triple-beam "^1.3.0"
+
+lolex@1.3.2:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/lolex/-/lolex-1.3.2.tgz#7c3da62ffcb30f0f5a80a2566ca24e45d8a01f31"
+  integrity sha1-fD2mL/yzDw9agKJWbKJORdigHzE=
+
+lolex@^1.6.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/lolex/-/lolex-1.6.0.tgz#3a9a0283452a47d7439e72731b9e07d7386e49f6"
+  integrity sha1-OpoCg0UqR9dDnnJzG54H1zhuSfY=
+
+loose-envify@^1.0.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
+  integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
+  dependencies:
+    js-tokens "^3.0.0 || ^4.0.0"
+
+loud-rejection@^1.0.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
+  integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=
+  dependencies:
+    currently-unhandled "^0.4.1"
+    signal-exit "^3.0.0"
+
+lower-case@^1.1.1:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac"
+  integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw=
+
+lowercase-keys@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
+  integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==
+
+lru-cache@^4.0.1, lru-cache@^4.0.2:
+  version "4.1.5"
+  resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
+  integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
+  dependencies:
+    pseudomap "^1.0.2"
+    yallist "^2.1.2"
+
+magic-string@^0.22.4:
+  version "0.22.5"
+  resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.22.5.tgz#8e9cf5afddf44385c1da5bc2a6a0dbd10b03657e"
+  integrity sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==
+  dependencies:
+    vlq "^0.2.2"
+
+make-dir@^1.0.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c"
+  integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==
+  dependencies:
+    pify "^3.0.0"
+
+map-cache@^0.2.2:
+  version "0.2.2"
+  resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
+  integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=
+
+map-obj@^1.0.0, map-obj@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
+  integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=
+
+map-visit@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f"
+  integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=
+  dependencies:
+    object-visit "^1.0.0"
+
+matcher@^1.1.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/matcher/-/matcher-1.1.1.tgz#51d8301e138f840982b338b116bb0c09af62c1c2"
+  integrity sha512-+BmqxWIubKTRKNWx/ahnCkk3mG8m7OturVlqq6HiojGJTd5hVYbgZm6WzcYPCoB+KBT4Vd6R7WSRG2OADNaCjg==
+  dependencies:
+    escape-string-regexp "^1.0.4"
+
+math-random@^1.0.1:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c"
+  integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==
+
+md5@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9"
+  integrity sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=
+  dependencies:
+    charenc "~0.0.1"
+    crypt "~0.0.1"
+    is-buffer "~1.1.1"
+
+media-typer@0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
+  integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
+
+meow@^3.7.0:
+  version "3.7.0"
+  resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb"
+  integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=
+  dependencies:
+    camelcase-keys "^2.0.0"
+    decamelize "^1.1.2"
+    loud-rejection "^1.0.0"
+    map-obj "^1.0.1"
+    minimist "^1.1.3"
+    normalize-package-data "^2.3.4"
+    object-assign "^4.0.1"
+    read-pkg-up "^1.0.1"
+    redent "^1.0.0"
+    trim-newlines "^1.0.0"
+
+merge-descriptors@1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
+  integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
+
+merge-stream@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1"
+  integrity sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=
+  dependencies:
+    readable-stream "^2.0.1"
+
+methods@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
+  integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
+
+micromatch@^2.3.11, micromatch@^2.3.7:
+  version "2.3.11"
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
+  integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=
+  dependencies:
+    arr-diff "^2.0.0"
+    array-unique "^0.2.1"
+    braces "^1.8.2"
+    expand-brackets "^0.1.4"
+    extglob "^0.3.1"
+    filename-regex "^2.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.1"
+    kind-of "^3.0.2"
+    normalize-path "^2.0.1"
+    object.omit "^2.0.0"
+    parse-glob "^3.0.4"
+    regex-cache "^0.4.2"
+
+micromatch@^3.0.4:
+  version "3.1.10"
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
+  integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==
+  dependencies:
+    arr-diff "^4.0.0"
+    array-unique "^0.3.2"
+    braces "^2.3.1"
+    define-property "^2.0.2"
+    extend-shallow "^3.0.2"
+    extglob "^2.0.4"
+    fragment-cache "^0.2.1"
+    kind-of "^6.0.2"
+    nanomatch "^1.2.9"
+    object.pick "^1.3.0"
+    regex-not "^1.0.0"
+    snapdragon "^0.8.1"
+    to-regex "^3.0.2"
+
+mime-db@1.43.0, "mime-db@>= 1.43.0 < 2":
+  version "1.43.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58"
+  integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==
+
+mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24:
+  version "2.1.26"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06"
+  integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==
+  dependencies:
+    mime-db "1.43.0"
+
+mime@1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
+  integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==
+
+mime@1.6.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
+  integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
+
+mime@^2.3.1:
+  version "2.4.4"
+  resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5"
+  integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==
+
+minimalistic-assert@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
+  integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
+
+minimatch-all@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/minimatch-all/-/minimatch-all-1.1.0.tgz#40c496a27a2e128d19bf758e76bb01a0c7145787"
+  integrity sha1-QMSWonouEo0Zv3WOdrsBoMcUV4c=
+  dependencies:
+    minimatch "^3.0.2"
+
+"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
+  integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
+  dependencies:
+    brace-expansion "^1.1.7"
+
+minimist@0.0.8:
+  version "0.0.8"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
+  integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
+
+minimist@^1.1.3, minimist@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
+  integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
+
+minimist@~0.0.1:
+  version "0.0.10"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
+  integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=
+
+mixin-deep@^1.2.0:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
+  integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==
+  dependencies:
+    for-in "^1.0.2"
+    is-extendable "^1.0.1"
+
+mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
+  integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
+  dependencies:
+    minimist "0.0.8"
+
+mocha@^3.4.2:
+  version "3.5.3"
+  resolved "https://registry.yarnpkg.com/mocha/-/mocha-3.5.3.tgz#1e0480fe36d2da5858d1eb6acc38418b26eaa20d"
+  integrity sha512-/6na001MJWEtYxHOV1WLfsmR4YIynkUEhBwzsb+fk2qmQ3iqsi258l/Q2MWHJMImAcNpZ8DEdYAK72NHoIQ9Eg==
+  dependencies:
+    browser-stdout "1.3.0"
+    commander "2.9.0"
+    debug "2.6.8"
+    diff "3.2.0"
+    escape-string-regexp "1.0.5"
+    glob "7.1.1"
+    growl "1.9.2"
+    he "1.1.1"
+    json3 "3.3.2"
+    lodash.create "3.1.1"
+    mkdirp "0.5.1"
+    supports-color "3.1.2"
+
+mocha@^6.2.2:
+  version "6.2.2"
+  resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.2.2.tgz#5d8987e28940caf8957a7d7664b910dc5b2fea20"
+  integrity sha512-FgDS9Re79yU1xz5d+C4rv1G7QagNGHZ+iXF81hO8zY35YZZcLEsJVfFolfsqKFWunATEvNzMK0r/CwWd/szO9A==
+  dependencies:
+    ansi-colors "3.2.3"
+    browser-stdout "1.3.1"
+    debug "3.2.6"
+    diff "3.5.0"
+    escape-string-regexp "1.0.5"
+    find-up "3.0.0"
+    glob "7.1.3"
+    growl "1.10.5"
+    he "1.2.0"
+    js-yaml "3.13.1"
+    log-symbols "2.2.0"
+    minimatch "3.0.4"
+    mkdirp "0.5.1"
+    ms "2.1.1"
+    node-environment-flags "1.0.5"
+    object.assign "4.1.0"
+    strip-json-comments "2.0.1"
+    supports-color "6.0.0"
+    which "1.3.1"
+    wide-align "1.1.3"
+    yargs "13.3.0"
+    yargs-parser "13.1.1"
+    yargs-unparser "1.6.0"
+
+mout@^1.0.0:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/mout/-/mout-1.2.2.tgz#c9b718a499806a0632cede178e80f436259e777d"
+  integrity sha512-w0OUxFEla6z3d7sVpMZGBCpQvYh8PHS1wZ6Wu9GNKHMpAHWJ0if0LsQZh3DlOqw55HlhJEOMLpFnwtxp99Y5GA==
+
+ms@2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+  integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
+
+ms@2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
+  integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
+
+ms@^2.1.1:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
+  integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+
+multer@^1.3.0:
+  version "1.4.2"
+  resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.2.tgz#2f1f4d12dbaeeba74cb37e623f234bf4d3d2057a"
+  integrity sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg==
+  dependencies:
+    append-field "^1.0.0"
+    busboy "^0.2.11"
+    concat-stream "^1.5.2"
+    mkdirp "^0.5.1"
+    object-assign "^4.1.1"
+    on-finished "^2.3.0"
+    type-is "^1.6.4"
+    xtend "^4.0.0"
+
+multipipe@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-1.0.2.tgz#cc13efd833c9cda99f224f868461b8e1a3fd939d"
+  integrity sha1-zBPv2DPJzamfIk+GhGG44aP9k50=
+  dependencies:
+    duplexer2 "^0.1.2"
+    object-assign "^4.1.0"
+
+mz@^2.4.0, mz@^2.6.0:
+  version "2.7.0"
+  resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32"
+  integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==
+  dependencies:
+    any-promise "^1.0.0"
+    object-assign "^4.0.1"
+    thenify-all "^1.0.0"
+
+nanomatch@^1.2.9:
+  version "1.2.13"
+  resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
+  integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==
+  dependencies:
+    arr-diff "^4.0.0"
+    array-unique "^0.3.2"
+    define-property "^2.0.2"
+    extend-shallow "^3.0.2"
+    fragment-cache "^0.2.1"
+    is-windows "^1.0.2"
+    kind-of "^6.0.2"
+    object.pick "^1.3.0"
+    regex-not "^1.0.0"
+    snapdragon "^0.8.1"
+    to-regex "^3.0.1"
+
+native-promise-only@^0.8.1:
+  version "0.8.1"
+  resolved "https://registry.yarnpkg.com/native-promise-only/-/native-promise-only-0.8.1.tgz#20a318c30cb45f71fe7adfbf7b21c99c1472ef11"
+  integrity sha1-IKMYwwy0X3H+et+/eyHJnBRy7xE=
+
+negotiator@0.6.2:
+  version "0.6.2"
+  resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
+  integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
+
+nice-try@^1.0.4:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
+  integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
+
+no-case@^2.2.0:
+  version "2.3.2"
+  resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac"
+  integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==
+  dependencies:
+    lower-case "^1.1.1"
+
+node-environment-flags@1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.5.tgz#fa930275f5bf5dae188d6192b24b4c8bbac3d76a"
+  integrity sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==
+  dependencies:
+    object.getownpropertydescriptors "^2.0.3"
+    semver "^5.7.0"
+
+nomnom@^1.8.1:
+  version "1.8.1"
+  resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.8.1.tgz#2151f722472ba79e50a76fc125bb8c8f2e4dc2a7"
+  integrity sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=
+  dependencies:
+    chalk "~0.4.0"
+    underscore "~1.6.0"
+
+normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
+  version "2.5.0"
+  resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
+  integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
+  dependencies:
+    hosted-git-info "^2.1.4"
+    resolve "^1.10.0"
+    semver "2 || 3 || 4 || 5"
+    validate-npm-package-license "^3.0.1"
+
+normalize-path@^2.0.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
+  integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=
+  dependencies:
+    remove-trailing-separator "^1.0.1"
+
+normalize-path@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
+  integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
+
+npm-run-path@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
+  integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=
+  dependencies:
+    path-key "^2.0.0"
+
+number-is-nan@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
+  integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
+
+oauth-sign@~0.9.0:
+  version "0.9.0"
+  resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
+  integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
+
+object-assign@^4, object-assign@^4.0.0, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+  integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
+
+object-component@0.0.3:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291"
+  integrity sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=
+
+object-copy@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
+  integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw=
+  dependencies:
+    copy-descriptor "^0.1.0"
+    define-property "^0.2.5"
+    kind-of "^3.0.3"
+
+object-inspect@^1.7.0:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67"
+  integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==
+
+object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
+  integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
+
+object-visit@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
+  integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=
+  dependencies:
+    isobject "^3.0.0"
+
+object.assign@4.1.0, object.assign@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da"
+  integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==
+  dependencies:
+    define-properties "^1.1.2"
+    function-bind "^1.1.1"
+    has-symbols "^1.0.0"
+    object-keys "^1.0.11"
+
+object.entries@^1.1.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.1.tgz#ee1cf04153de02bb093fec33683900f57ce5399b"
+  integrity sha512-ilqR7BgdyZetJutmDPfXCDffGa0/Yzl2ivVNpbx/g4UeWrCdRnFDUBrKJGLhGieRHDATnyZXWBeCb29k9CJysQ==
+  dependencies:
+    define-properties "^1.1.3"
+    es-abstract "^1.17.0-next.1"
+    function-bind "^1.1.1"
+    has "^1.0.3"
+
+object.getownpropertydescriptors@^2.0.3:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649"
+  integrity sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==
+  dependencies:
+    define-properties "^1.1.3"
+    es-abstract "^1.17.0-next.1"
+
+object.omit@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
+  integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=
+  dependencies:
+    for-own "^0.1.4"
+    is-extendable "^0.1.1"
+
+object.pick@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
+  integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=
+  dependencies:
+    isobject "^3.0.1"
+
+obuf@^1.0.0, obuf@^1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e"
+  integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==
+
+on-finished@^2.3.0, on-finished@~2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
+  integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=
+  dependencies:
+    ee-first "1.1.1"
+
+on-headers@~1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
+  integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
+
+once@^1.3.0, once@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+  integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
+  dependencies:
+    wrappy "1"
+
+one-time@0.0.4:
+  version "0.0.4"
+  resolved "https://registry.yarnpkg.com/one-time/-/one-time-0.0.4.tgz#f8cdf77884826fe4dff93e3a9cc37b1e4480742e"
+  integrity sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=
+
+opn@^3.0.2:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/opn/-/opn-3.0.3.tgz#b6d99e7399f78d65c3baaffef1fb288e9b85243a"
+  integrity sha1-ttmec5n3jWXDuq/+8fsojpuFJDo=
+  dependencies:
+    object-assign "^4.0.1"
+
+optimist@^0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
+  integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY=
+  dependencies:
+    minimist "~0.0.1"
+    wordwrap "~0.0.2"
+
+ordered-read-streams@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz#7137e69b3298bb342247a1bbee3881c80e2fd78b"
+  integrity sha1-cTfmmzKYuzQiR6G77jiByA4v14s=
+  dependencies:
+    is-stream "^1.0.1"
+    readable-stream "^2.0.1"
+
+os-homedir@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
+  integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
+
+os-tmpdir@^1.0.0, os-tmpdir@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+  integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
+
+osenv@^0.1.3:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
+  integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==
+  dependencies:
+    os-homedir "^1.0.0"
+    os-tmpdir "^1.0.0"
+
+p-finally@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
+  integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
+
+p-limit@^2.0.0:
+  version "2.2.2"
+  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e"
+  integrity sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==
+  dependencies:
+    p-try "^2.0.0"
+
+p-locate@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
+  integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==
+  dependencies:
+    p-limit "^2.0.0"
+
+p-try@^2.0.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
+  integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
+
+package-json@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed"
+  integrity sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=
+  dependencies:
+    got "^6.7.1"
+    registry-auth-token "^3.0.1"
+    registry-url "^3.0.3"
+    semver "^5.1.0"
+
+param-case@2.1.x:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247"
+  integrity sha1-35T9jPZTHs915r75oIWPvHK+Ikc=
+  dependencies:
+    no-case "^2.2.0"
+
+parse-glob@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
+  integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw=
+  dependencies:
+    glob-base "^0.3.0"
+    is-dotfile "^1.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.0"
+
+parse-json@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
+  integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=
+  dependencies:
+    error-ex "^1.2.0"
+
+parse-passwd@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
+  integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=
+
+parse5@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608"
+  integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==
+
+parseqs@0.0.5:
+  version "0.0.5"
+  resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d"
+  integrity sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=
+  dependencies:
+    better-assert "~1.0.0"
+
+parseuri@0.0.5:
+  version "0.0.5"
+  resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a"
+  integrity sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=
+  dependencies:
+    better-assert "~1.0.0"
+
+parseurl@~1.3.3:
+  version "1.3.3"
+  resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
+  integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
+
+pascalcase@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
+  integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=
+
+path-dirname@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
+  integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=
+
+path-exists@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
+  integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=
+  dependencies:
+    pinkie-promise "^2.0.0"
+
+path-exists@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
+  integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=
+
+path-is-absolute@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+  integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
+
+path-is-inside@^1.0.1, path-is-inside@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
+  integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=
+
+path-key@^2.0.0, path-key@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
+  integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
+
+path-parse@^1.0.6:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
+  integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
+
+path-to-regexp@0.1.7:
+  version "0.1.7"
+  resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
+  integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
+
+path-to-regexp@^1.0.1, path-to-regexp@^1.7.0:
+  version "1.8.0"
+  resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a"
+  integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==
+  dependencies:
+    isarray "0.0.1"
+
+path-type@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
+  integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=
+  dependencies:
+    graceful-fs "^4.1.2"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+pathval@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0"
+  integrity sha1-uULm1L3mUwBe9rcTYd74cn0GReA=
+
+pem@^1.8.3:
+  version "1.14.3"
+  resolved "https://registry.yarnpkg.com/pem/-/pem-1.14.3.tgz#347e5a5c194a5f7612b88083e45042fcc4fb4901"
+  integrity sha512-Q+AMVMD3fzeVvZs5PHeI+pVt0hgZY2fjhkliBW43qyONLgCXPVk1ryim43F9eupHlNGLJNT5T/NNrzhUdiC5Zg==
+  dependencies:
+    es6-promisify "^6.0.0"
+    md5 "^2.2.1"
+    os-tmpdir "^1.0.1"
+    which "^1.3.1"
+
+pend@~1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
+  integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA=
+
+performance-now@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
+  integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
+
+pify@^2.0.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
+  integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
+
+pify@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
+  integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
+
+pinkie-promise@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
+  integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o=
+  dependencies:
+    pinkie "^2.0.0"
+
+pinkie@^2.0.0:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
+  integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
+
+plist@^2.0.1:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/plist/-/plist-2.1.0.tgz#57ccdb7a0821df21831217a3cad54e3e146a1025"
+  integrity sha1-V8zbeggh3yGDEhejytVOPhRqECU=
+  dependencies:
+    base64-js "1.2.0"
+    xmlbuilder "8.2.2"
+    xmldom "0.1.x"
+
+plylog@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/plylog/-/plylog-1.1.0.tgz#f6f354e2ae0b01f6db4ed111f4b3855da9c37417"
+  integrity sha512-/QnY5aSVaP54va6hruzNtAj02HpsLlAt7V5EndMrtq6ZUTZJKUja43rgiUtGXqm95yrSJjbZoPW0yQQQwLpoJA==
+  dependencies:
+    logform "^1.9.1"
+    winston "^3.0.0"
+    winston-transport "^4.2.0"
+
+polymer-analyzer@^3.1.3, polymer-analyzer@^3.2.2:
+  version "3.2.4"
+  resolved "https://registry.yarnpkg.com/polymer-analyzer/-/polymer-analyzer-3.2.4.tgz#7d76356620a2328e8bc9e30e47069f9729260ca1"
+  integrity sha512-JmxUhMajTuC18tLXbTtu2+aN2x9bTX+4MvCD4IZKJ0rtAL8jWi1iRLfogpHJB4Ig9Dc8EEEuEYipLuzPFl3vqA==
+  dependencies:
+    "@babel/generator" "^7.0.0-beta.42"
+    "@babel/traverse" "^7.0.0-beta.42"
+    "@babel/types" "^7.0.0-beta.42"
+    "@types/babel-generator" "^6.25.1"
+    "@types/babel-traverse" "^6.25.2"
+    "@types/babel-types" "^6.25.1"
+    "@types/babylon" "^6.16.2"
+    "@types/chai-subset" "^1.3.0"
+    "@types/chalk" "^0.4.30"
+    "@types/clone" "^0.1.30"
+    "@types/cssbeautify" "^0.3.1"
+    "@types/doctrine" "^0.0.1"
+    "@types/is-windows" "^0.2.0"
+    "@types/minimatch" "^3.0.1"
+    "@types/parse5" "^2.2.34"
+    "@types/path-is-inside" "^1.0.0"
+    "@types/resolve" "0.0.6"
+    "@types/whatwg-url" "^6.4.0"
+    babylon "^7.0.0-beta.42"
+    cancel-token "^0.1.1"
+    chalk "^1.1.3"
+    clone "^2.0.0"
+    cssbeautify "^0.3.1"
+    doctrine "^2.0.2"
+    dom5 "^3.0.0"
+    indent "0.0.2"
+    is-windows "^1.0.2"
+    jsonschema "^1.1.0"
+    minimatch "^3.0.4"
+    parse5 "^4.0.0"
+    path-is-inside "^1.0.2"
+    resolve "^1.5.0"
+    shady-css-parser "^0.1.0"
+    stable "^0.1.6"
+    strip-indent "^2.0.0"
+    vscode-uri "=1.0.6"
+    whatwg-url "^6.4.0"
+
+polymer-build@^3.1.0:
+  version "3.1.4"
+  resolved "https://registry.yarnpkg.com/polymer-build/-/polymer-build-3.1.4.tgz#ab539f1a13d803518b13b73ffd09198431d98142"
+  integrity sha512-OhTOPG5Y/tK2HqGZ5XA/CVDh+TuOaDv7wTZWXDCg6hxeMgNKuljDMn2coyGU5NLM0pLbS+gwFAc2ZJ5cWHCHNg==
+  dependencies:
+    "@babel/core" "^7.0.0"
+    "@babel/plugin-external-helpers" "^7.0.0"
+    "@babel/plugin-proposal-async-generator-functions" "^7.0.0"
+    "@babel/plugin-proposal-object-rest-spread" "^7.0.0"
+    "@babel/plugin-syntax-async-generators" "^7.0.0"
+    "@babel/plugin-syntax-dynamic-import" "^7.0.0"
+    "@babel/plugin-syntax-import-meta" "^7.0.0"
+    "@babel/plugin-syntax-object-rest-spread" "^7.0.0"
+    "@babel/plugin-transform-arrow-functions" "^7.0.0"
+    "@babel/plugin-transform-async-to-generator" "^7.0.0"
+    "@babel/plugin-transform-block-scoped-functions" "^7.0.0"
+    "@babel/plugin-transform-block-scoping" "^7.0.0"
+    "@babel/plugin-transform-classes" "^7.0.0"
+    "@babel/plugin-transform-computed-properties" "^7.0.0"
+    "@babel/plugin-transform-destructuring" "^7.0.0"
+    "@babel/plugin-transform-duplicate-keys" "^7.0.0"
+    "@babel/plugin-transform-exponentiation-operator" "^7.0.0"
+    "@babel/plugin-transform-for-of" "^7.0.0"
+    "@babel/plugin-transform-function-name" "^7.0.0"
+    "@babel/plugin-transform-instanceof" "^7.0.0"
+    "@babel/plugin-transform-literals" "^7.0.0"
+    "@babel/plugin-transform-modules-amd" "^7.0.0"
+    "@babel/plugin-transform-object-super" "^7.0.0"
+    "@babel/plugin-transform-parameters" "^7.0.0"
+    "@babel/plugin-transform-regenerator" "^7.0.0"
+    "@babel/plugin-transform-shorthand-properties" "^7.0.0"
+    "@babel/plugin-transform-spread" "^7.0.0"
+    "@babel/plugin-transform-sticky-regex" "^7.0.0"
+    "@babel/plugin-transform-template-literals" "^7.0.0"
+    "@babel/plugin-transform-typeof-symbol" "^7.0.0"
+    "@babel/plugin-transform-unicode-regex" "^7.0.0"
+    "@babel/traverse" "^7.0.0"
+    "@polymer/esm-amd-loader" "^1.0.0"
+    "@types/babel-types" "^6.25.1"
+    "@types/babylon" "^6.16.2"
+    "@types/gulp-if" "0.0.33"
+    "@types/html-minifier" "^3.5.1"
+    "@types/is-windows" "^0.2.0"
+    "@types/mz" "0.0.31"
+    "@types/parse5" "^2.2.34"
+    "@types/resolve" "0.0.7"
+    "@types/uuid" "^3.4.3"
+    "@types/vinyl" "^2.0.0"
+    "@types/vinyl-fs" "^2.4.8"
+    babel-plugin-minify-guarded-expressions "^0.4.3"
+    babel-preset-minify "^0.5.0"
+    babylon "^7.0.0-beta.42"
+    css-slam "^2.1.2"
+    dom5 "^3.0.0"
+    gulp-if "^2.0.2"
+    html-minifier "^3.5.10"
+    matcher "^1.1.0"
+    multipipe "^1.0.2"
+    mz "^2.6.0"
+    parse5 "^4.0.0"
+    plylog "^1.0.0"
+    polymer-analyzer "^3.1.3"
+    polymer-bundler "^4.0.9"
+    polymer-project-config "^4.0.3"
+    regenerator-runtime "^0.11.1"
+    stream "0.0.2"
+    sw-precache "^5.1.1"
+    uuid "^3.2.1"
+    vinyl "^1.2.0"
+    vinyl-fs "^2.4.4"
+
+polymer-bundler@^4.0.9:
+  version "4.0.10"
+  resolved "https://registry.yarnpkg.com/polymer-bundler/-/polymer-bundler-4.0.10.tgz#abc8d33977652f031068d034c8104841e80d4cbb"
+  integrity sha512-nwlN3LQlQDqbZ2sUH3394C/dHZUDHq8tpdS5HARvPDb0Q9IXWD+znOR1cr7wSjF0EZN4LiUH5hWyUoV4QSjhpQ==
+  dependencies:
+    "@types/babel-generator" "^6.25.1"
+    "@types/babel-traverse" "^6.25.3"
+    babel-generator "^6.26.1"
+    babel-traverse "^6.26.0"
+    babel-types "^6.26.0"
+    clone "^2.1.0"
+    command-line-args "^5.0.2"
+    command-line-usage "^5.0.5"
+    dom5 "^3.0.0"
+    espree "^3.5.2"
+    magic-string "^0.22.4"
+    mkdirp "^0.5.1"
+    parse5 "^4.0.0"
+    polymer-analyzer "^3.2.2"
+    rollup "^1.3.0"
+    source-map "^0.5.6"
+    vscode-uri "=1.0.6"
+
+polymer-project-config@^4.0.0, polymer-project-config@^4.0.3:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/polymer-project-config/-/polymer-project-config-4.0.3.tgz#ef0c1a676ce4809907986c8e910745660de8024f"
+  integrity sha512-Drr+Imq+znhBC8XSt9pMlmPixoGnIOmleV5SD6mto1zOGC5oCDbSNsQL2v89DWOk+9aSUO79vnWwOmEPDSvYfw==
+  dependencies:
+    "@types/parse5" "^2.2.34"
+    browser-capabilities "^1.0.0"
+    jsonschema "^1.1.1"
+    minimatch-all "^1.1.0"
+    plylog "^1.0.0"
+    winston "^3.0.0"
+
+polyserve@^0.27.13:
+  version "0.27.15"
+  resolved "https://registry.yarnpkg.com/polyserve/-/polyserve-0.27.15.tgz#261fa5a0873c8d95fd7068598f44c9dac20cf9c4"
+  integrity sha512-AaFgANt+tUUVgHLw+BnaVYcn649JiwL1ru0TOZUKj1gGGn/Bq2S16gxql+1muGpRaAsgFu13Zu7k5XkwatwwSg==
+  dependencies:
+    "@types/compression" "^0.0.33"
+    "@types/content-type" "^1.1.0"
+    "@types/escape-html" "0.0.20"
+    "@types/express" "^4.0.36"
+    "@types/mime" "^2.0.0"
+    "@types/mz" "0.0.29"
+    "@types/opn" "^3.0.28"
+    "@types/parse5" "^2.2.34"
+    "@types/pem" "^1.8.1"
+    "@types/resolve" "0.0.6"
+    "@types/serve-static" "^1.7.31"
+    "@types/spdy" "^3.4.1"
+    bower-config "^1.4.1"
+    browser-capabilities "^1.0.0"
+    command-line-args "^5.0.2"
+    command-line-usage "^5.0.5"
+    compression "^1.6.2"
+    content-type "^1.0.2"
+    cors "^2.8.4"
+    escape-html "^1.0.3"
+    express "^4.8.5"
+    find-port "^1.0.1"
+    http-proxy-middleware "^0.17.2"
+    lru-cache "^4.0.2"
+    mime "^2.3.1"
+    mz "^2.4.0"
+    opn "^3.0.2"
+    pem "^1.8.3"
+    polymer-build "^3.1.0"
+    polymer-project-config "^4.0.0"
+    requirejs "^2.3.4"
+    resolve "^1.5.0"
+    send "^0.16.2"
+    spdy "^3.3.3"
+
+posix-character-classes@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
+  integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
+
+prepend-http@^1.0.1:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
+  integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=
+
+preserve@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
+  integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=
+
+pretty-bytes@^4.0.2:
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-4.0.2.tgz#b2bf82e7350d65c6c33aa95aaa5a4f6327f61cd9"
+  integrity sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk=
+
+private@^0.1.6:
+  version "0.1.8"
+  resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"
+  integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==
+
+process-nextick-args@~2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
+  integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
+
+progress@2.0.3:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
+  integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
+
+proxy-addr@~2.0.5:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34"
+  integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==
+  dependencies:
+    forwarded "~0.1.2"
+    ipaddr.js "1.9.0"
+
+pseudomap@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
+  integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
+
+psl@^1.1.24:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/psl/-/psl-1.7.0.tgz#f1c4c47a8ef97167dea5d6bbf4816d736e884a3c"
+  integrity sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==
+
+punycode@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
+  integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
+
+punycode@^2.1.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
+  integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
+
+q@^1.4.1, q@^1.5.1:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
+  integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
+
+qs@6.7.0:
+  version "6.7.0"
+  resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
+  integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
+
+qs@~6.5.2:
+  version "6.5.2"
+  resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
+  integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
+
+randomatic@^3.0.0:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed"
+  integrity sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==
+  dependencies:
+    is-number "^4.0.0"
+    kind-of "^6.0.0"
+    math-random "^1.0.1"
+
+range-parser@~1.2.0, range-parser@~1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
+  integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
+
+raw-body@2.4.0:
+  version "2.4.0"
+  resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332"
+  integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==
+  dependencies:
+    bytes "3.1.0"
+    http-errors "1.7.2"
+    iconv-lite "0.4.24"
+    unpipe "1.0.0"
+
+rc@^1.0.1, rc@^1.1.6:
+  version "1.2.8"
+  resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
+  integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
+  dependencies:
+    deep-extend "^0.6.0"
+    ini "~1.3.0"
+    minimist "^1.2.0"
+    strip-json-comments "~2.0.1"
+
+read-pkg-up@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
+  integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=
+  dependencies:
+    find-up "^1.0.0"
+    read-pkg "^1.0.0"
+
+read-pkg@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
+  integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=
+  dependencies:
+    load-json-file "^1.0.0"
+    normalize-package-data "^2.3.2"
+    path-type "^1.0.0"
+
+readable-stream@1.1.x:
+  version "1.1.14"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
+  integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk=
+  dependencies:
+    core-util-is "~1.0.0"
+    inherits "~2.0.1"
+    isarray "0.0.1"
+    string_decoder "~0.10.x"
+
+"readable-stream@>=1.0.33-1 <1.1.0-0":
+  version "1.0.34"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c"
+  integrity sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=
+  dependencies:
+    core-util-is "~1.0.0"
+    inherits "~2.0.1"
+    isarray "0.0.1"
+    string_decoder "~0.10.x"
+
+readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6:
+  version "2.3.7"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
+  integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
+  dependencies:
+    core-util-is "~1.0.0"
+    inherits "~2.0.3"
+    isarray "~1.0.0"
+    process-nextick-args "~2.0.0"
+    safe-buffer "~5.1.1"
+    string_decoder "~1.1.1"
+    util-deprecate "~1.0.1"
+
+readable-stream@^3.0.1, readable-stream@^3.1.1, readable-stream@^3.4.0:
+  version "3.5.0"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.5.0.tgz#465d70e6d1087f6162d079cd0b5db7fbebfd1606"
+  integrity sha512-gSz026xs2LfxBPudDuI41V1lka8cxg64E66SGe78zJlsUofOg/yqwezdIcdfwik6B4h8LFmWPA9ef9X3FiNFLA==
+  dependencies:
+    inherits "^2.0.3"
+    string_decoder "^1.1.1"
+    util-deprecate "^1.0.1"
+
+redent@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"
+  integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=
+  dependencies:
+    indent-string "^2.1.0"
+    strip-indent "^1.0.1"
+
+reduce-flatten@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-1.0.1.tgz#258c78efd153ddf93cb561237f61184f3696e327"
+  integrity sha1-JYx479FT3fk8tWEjf2EYTzaW4yc=
+
+regenerate-unicode-properties@^8.1.0:
+  version "8.1.0"
+  resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e"
+  integrity sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==
+  dependencies:
+    regenerate "^1.4.0"
+
+regenerate@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
+  integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==
+
+regenerator-runtime@^0.11.0, regenerator-runtime@^0.11.1:
+  version "0.11.1"
+  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
+  integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
+
+regenerator-transform@^0.14.0:
+  version "0.14.1"
+  resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.1.tgz#3b2fce4e1ab7732c08f665dfdb314749c7ddd2fb"
+  integrity sha512-flVuee02C3FKRISbxhXl9mGzdbWUVHubl1SMaknjxkFB1/iqpJhArQUvRxOOPEc/9tAiX0BaQ28FJH10E4isSQ==
+  dependencies:
+    private "^0.1.6"
+
+regex-cache@^0.4.2:
+  version "0.4.4"
+  resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd"
+  integrity sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==
+  dependencies:
+    is-equal-shallow "^0.1.3"
+
+regex-not@^1.0.0, regex-not@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
+  integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==
+  dependencies:
+    extend-shallow "^3.0.2"
+    safe-regex "^1.1.0"
+
+regexpu-core@^4.6.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.6.0.tgz#2037c18b327cfce8a6fea2a4ec441f2432afb8b6"
+  integrity sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg==
+  dependencies:
+    regenerate "^1.4.0"
+    regenerate-unicode-properties "^8.1.0"
+    regjsgen "^0.5.0"
+    regjsparser "^0.6.0"
+    unicode-match-property-ecmascript "^1.0.4"
+    unicode-match-property-value-ecmascript "^1.1.0"
+
+registry-auth-token@^3.0.1:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.4.0.tgz#d7446815433f5d5ed6431cd5dca21048f66b397e"
+  integrity sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==
+  dependencies:
+    rc "^1.1.6"
+    safe-buffer "^5.0.1"
+
+registry-url@^3.0.3:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942"
+  integrity sha1-PU74cPc93h138M+aOBQyRE4XSUI=
+  dependencies:
+    rc "^1.0.1"
+
+regjsgen@^0.5.0:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.1.tgz#48f0bf1a5ea205196929c0d9798b42d1ed98443c"
+  integrity sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==
+
+regjsparser@^0.6.0:
+  version "0.6.2"
+  resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.2.tgz#fd62c753991467d9d1ffe0a9f67f27a529024b96"
+  integrity sha512-E9ghzUtoLwDekPT0DYCp+c4h+bvuUpe6rRHCTYn6eGoqj1LgKXxT6I0Il4WbjhQkOghzi/V+y03bPKvbllL93Q==
+  dependencies:
+    jsesc "~0.5.0"
+
+relateurl@0.2.x:
+  version "0.2.7"
+  resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
+  integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=
+
+remove-trailing-separator@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
+  integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8=
+
+repeat-element@^1.1.2:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce"
+  integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==
+
+repeat-string@^1.5.2, repeat-string@^1.6.1:
+  version "1.6.1"
+  resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
+  integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
+
+repeating@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
+  integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=
+  dependencies:
+    is-finite "^1.0.0"
+
+replace-ext@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924"
+  integrity sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=
+
+request@2.88.0, request@^2.85.0:
+  version "2.88.0"
+  resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
+  integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
+  dependencies:
+    aws-sign2 "~0.7.0"
+    aws4 "^1.8.0"
+    caseless "~0.12.0"
+    combined-stream "~1.0.6"
+    extend "~3.0.2"
+    forever-agent "~0.6.1"
+    form-data "~2.3.2"
+    har-validator "~5.1.0"
+    http-signature "~1.2.0"
+    is-typedarray "~1.0.0"
+    isstream "~0.1.2"
+    json-stringify-safe "~5.0.1"
+    mime-types "~2.1.19"
+    oauth-sign "~0.9.0"
+    performance-now "^2.1.0"
+    qs "~6.5.2"
+    safe-buffer "^5.1.2"
+    tough-cookie "~2.4.3"
+    tunnel-agent "^0.6.0"
+    uuid "^3.3.2"
+
+require-directory@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+  integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
+
+require-main-filename@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
+  integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
+
+requirejs@^2.3.4:
+  version "2.3.6"
+  resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.3.6.tgz#e5093d9601c2829251258c0b9445d4d19fa9e7c9"
+  integrity sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg==
+
+requires-port@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
+  integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
+
+resolve-dir@^1.0.0, resolve-dir@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43"
+  integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=
+  dependencies:
+    expand-tilde "^2.0.0"
+    global-modules "^1.0.0"
+
+resolve-url@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
+  integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
+
+resolve@^1.10.0, resolve@^1.3.2, resolve@^1.5.0:
+  version "1.15.0"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.0.tgz#1b7ca96073ebb52e741ffd799f6b39ea462c67f5"
+  integrity sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==
+  dependencies:
+    path-parse "^1.0.6"
+
+ret@~0.1.10:
+  version "0.1.15"
+  resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
+  integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
+
+rimraf@^2.5.4:
+  version "2.7.1"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
+  integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
+  dependencies:
+    glob "^7.1.3"
+
+rimraf@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.0.tgz#614176d4b3010b75e5c390eb0ee96f6dc0cebb9b"
+  integrity sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==
+  dependencies:
+    glob "^7.1.3"
+
+rimraf@~2.6.2:
+  version "2.6.3"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
+  integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
+  dependencies:
+    glob "^7.1.3"
+
+rollup@^1.3.0:
+  version "1.29.1"
+  resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.29.1.tgz#8715d0a4ca439be3079f8095989ec8aa60f637bc"
+  integrity sha512-dGQ+b9d1FOX/gluiggTAVnTvzQZUEkCi/TwZcax7ujugVRHs0nkYJlV9U4hsifGEMojnO+jvEML2CJQ6qXgbHA==
+  dependencies:
+    "@types/estree" "*"
+    "@types/node" "*"
+    acorn "^7.1.0"
+
+safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
+  integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
+
+safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
+  integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
+
+safe-regex@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
+  integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4=
+  dependencies:
+    ret "~0.1.10"
+
+"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
+  integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+
+samsam@1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.1.2.tgz#bec11fdc83a9fda063401210e40176c3024d1567"
+  integrity sha1-vsEf3IOp/aBjQBIQ5AF2wwJNFWc=
+
+samsam@1.x, samsam@^1.1.3:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.3.0.tgz#8d1d9350e25622da30de3e44ba692b5221ab7c50"
+  integrity sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==
+
+samsam@~1.1:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.1.3.tgz#9f5087419b4d091f232571e7fa52e90b0f552621"
+  integrity sha1-n1CHQZtNCR8jJXHn+lLpCw9VJiE=
+
+sauce-connect-launcher@^1.0.0:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/sauce-connect-launcher/-/sauce-connect-launcher-1.3.1.tgz#31137f57b0f7176e1c0525b7fb09c6da746647cf"
+  integrity sha512-vIf9qDol3q2FlYzrKt0dr3kvec6LSjX2WS+/mVnAJIhqh1evSkPKCR2AzcJrnSmx9Xt9PtV0tLY7jYh0wsQi8A==
+  dependencies:
+    adm-zip "~0.4.3"
+    async "^2.1.2"
+    https-proxy-agent "^3.0.0"
+    lodash "^4.16.6"
+    rimraf "^2.5.4"
+
+select-hose@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
+  integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=
+
+selenium-standalone@^6.7.0:
+  version "6.17.0"
+  resolved "https://registry.yarnpkg.com/selenium-standalone/-/selenium-standalone-6.17.0.tgz#0f24b691836205ee9bc3d7a6f207ebcb28170cd9"
+  integrity sha512-5PSnDHwMiq+OCiAGlhwQ8BM9xuwFfvBOZ7Tfbw+ifkTnOy0PWbZmI1B9gPGuyGHpbQ/3J3CzIK7BYwrQ7EjtWQ==
+  dependencies:
+    async "^2.6.2"
+    commander "^2.19.0"
+    cross-spawn "^6.0.5"
+    debug "^4.1.1"
+    lodash "^4.17.11"
+    minimist "^1.2.0"
+    mkdirp "^0.5.1"
+    progress "2.0.3"
+    request "2.88.0"
+    tar-stream "2.0.0"
+    urijs "^1.19.1"
+    which "^1.3.1"
+    yauzl "^2.10.0"
+
+semver-diff@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36"
+  integrity sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=
+  dependencies:
+    semver "^5.0.3"
+
+"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.7.0:
+  version "5.7.1"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
+  integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
+
+send@0.17.1:
+  version "0.17.1"
+  resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
+  integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==
+  dependencies:
+    debug "2.6.9"
+    depd "~1.1.2"
+    destroy "~1.0.4"
+    encodeurl "~1.0.2"
+    escape-html "~1.0.3"
+    etag "~1.8.1"
+    fresh "0.5.2"
+    http-errors "~1.7.2"
+    mime "1.6.0"
+    ms "2.1.1"
+    on-finished "~2.3.0"
+    range-parser "~1.2.1"
+    statuses "~1.5.0"
+
+send@^0.16.1, send@^0.16.2:
+  version "0.16.2"
+  resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1"
+  integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==
+  dependencies:
+    debug "2.6.9"
+    depd "~1.1.2"
+    destroy "~1.0.4"
+    encodeurl "~1.0.2"
+    escape-html "~1.0.3"
+    etag "~1.8.1"
+    fresh "0.5.2"
+    http-errors "~1.6.2"
+    mime "1.4.1"
+    ms "2.0.0"
+    on-finished "~2.3.0"
+    range-parser "~1.2.0"
+    statuses "~1.4.0"
+
+serve-static@1.14.1:
+  version "1.14.1"
+  resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9"
+  integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==
+  dependencies:
+    encodeurl "~1.0.2"
+    escape-html "~1.0.3"
+    parseurl "~1.3.3"
+    send "0.17.1"
+
+server-destroy@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/server-destroy/-/server-destroy-1.0.1.tgz#f13bf928e42b9c3e79383e61cc3998b5d14e6cdd"
+  integrity sha1-8Tv5KOQrnD55OD5hzDmYtdFObN0=
+
+serviceworker-cache-polyfill@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/serviceworker-cache-polyfill/-/serviceworker-cache-polyfill-4.0.0.tgz#de19ee73bef21ab3c0740a37b33db62464babdeb"
+  integrity sha1-3hnuc77yGrPAdAo3sz22JGS6ves=
+
+set-blocking@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
+  integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
+
+set-value@^2.0.0, set-value@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
+  integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==
+  dependencies:
+    extend-shallow "^2.0.1"
+    is-extendable "^0.1.1"
+    is-plain-object "^2.0.3"
+    split-string "^3.0.1"
+
+setprototypeof@1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
+  integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==
+
+setprototypeof@1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
+  integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==
+
+shady-css-parser@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/shady-css-parser/-/shady-css-parser-0.1.0.tgz#534dc79c8ca5884c5ed92a4e5a13d6d863bca428"
+  integrity sha512-irfJUUkEuDlNHKZNAp2r7zOyMlmbfVJ+kWSfjlCYYUx/7dJnANLCyTzQZsuxy5NJkvtNwSxY5Gj8MOlqXUQPyA==
+
+shebang-command@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
+  integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=
+  dependencies:
+    shebang-regex "^1.0.0"
+
+shebang-regex@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
+  integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
+
+signal-exit@^3.0.0, signal-exit@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
+  integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
+
+simple-swizzle@^0.2.2:
+  version "0.2.2"
+  resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
+  integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=
+  dependencies:
+    is-arrayish "^0.3.1"
+
+sinon-chai@^2.10.0:
+  version "2.14.0"
+  resolved "https://registry.yarnpkg.com/sinon-chai/-/sinon-chai-2.14.0.tgz#da7dd4cc83cd6a260b67cca0f7a9fdae26a1205d"
+  integrity sha512-9stIF1utB0ywNHNT7RgiXbdmen8QDCRsrTjw+G9TgKt1Yexjiv8TOWZ6WHsTPz57Yky3DIswZvEqX8fpuHNDtQ==
+
+sinon@^1.17.1:
+  version "1.17.7"
+  resolved "https://registry.yarnpkg.com/sinon/-/sinon-1.17.7.tgz#4542a4f49ba0c45c05eb2e9dd9d203e2b8efe0bf"
+  integrity sha1-RUKk9JugxFwF6y6d2dID4rjv4L8=
+  dependencies:
+    formatio "1.1.1"
+    lolex "1.3.2"
+    samsam "1.1.2"
+    util ">=0.10.3 <1"
+
+sinon@^2.3.5:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/sinon/-/sinon-2.4.1.tgz#021fd64b54cb77d9d2fb0d43cdedfae7629c3a36"
+  integrity sha512-vFTrO9Wt0ECffDYIPSP/E5bBugt0UjcBQOfQUMh66xzkyPEnhl/vM2LRZi2ajuTdkH07sA6DzrM6KvdvGIH8xw==
+  dependencies:
+    diff "^3.1.0"
+    formatio "1.2.0"
+    lolex "^1.6.0"
+    native-promise-only "^0.8.1"
+    path-to-regexp "^1.7.0"
+    samsam "^1.1.3"
+    text-encoding "0.6.4"
+    type-detect "^4.0.0"
+
+snapdragon-node@^2.0.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
+  integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==
+  dependencies:
+    define-property "^1.0.0"
+    isobject "^3.0.0"
+    snapdragon-util "^3.0.1"
+
+snapdragon-util@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2"
+  integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==
+  dependencies:
+    kind-of "^3.2.0"
+
+snapdragon@^0.8.1:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d"
+  integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==
+  dependencies:
+    base "^0.11.1"
+    debug "^2.2.0"
+    define-property "^0.2.5"
+    extend-shallow "^2.0.1"
+    map-cache "^0.2.2"
+    source-map "^0.5.6"
+    source-map-resolve "^0.5.0"
+    use "^3.1.0"
+
+socket.io-adapter@~1.1.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz#ab3f0d6f66b8fc7fca3959ab5991f82221789be9"
+  integrity sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==
+
+socket.io-client@2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.3.0.tgz#14d5ba2e00b9bcd145ae443ab96b3f86cbcc1bb4"
+  integrity sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==
+  dependencies:
+    backo2 "1.0.2"
+    base64-arraybuffer "0.1.5"
+    component-bind "1.0.0"
+    component-emitter "1.2.1"
+    debug "~4.1.0"
+    engine.io-client "~3.4.0"
+    has-binary2 "~1.0.2"
+    has-cors "1.1.0"
+    indexof "0.0.1"
+    object-component "0.0.3"
+    parseqs "0.0.5"
+    parseuri "0.0.5"
+    socket.io-parser "~3.3.0"
+    to-array "0.1.4"
+
+socket.io-parser@~3.3.0:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.0.tgz#2b52a96a509fdf31440ba40fed6094c7d4f1262f"
+  integrity sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==
+  dependencies:
+    component-emitter "1.2.1"
+    debug "~3.1.0"
+    isarray "2.0.1"
+
+socket.io-parser@~3.4.0:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.4.0.tgz#370bb4a151df2f77ce3345ff55a7072cc6e9565a"
+  integrity sha512-/G/VOI+3DBp0+DJKW4KesGnQkQPFmUCbA/oO2QGT6CWxU7hLGWqU3tyuzeSK/dqcyeHsQg1vTe9jiZI8GU9SCQ==
+  dependencies:
+    component-emitter "1.2.1"
+    debug "~4.1.0"
+    isarray "2.0.1"
+
+socket.io@^2.0.3:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.3.0.tgz#cd762ed6a4faeca59bc1f3e243c0969311eb73fb"
+  integrity sha512-2A892lrj0GcgR/9Qk81EaY2gYhCBxurV0PfmmESO6p27QPrUK1J3zdns+5QPqvUYK2q657nSj0guoIil9+7eFg==
+  dependencies:
+    debug "~4.1.0"
+    engine.io "~3.4.0"
+    has-binary2 "~1.0.2"
+    socket.io-adapter "~1.1.0"
+    socket.io-client "2.3.0"
+    socket.io-parser "~3.4.0"
+
+source-map-resolve@^0.5.0:
+  version "0.5.3"
+  resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a"
+  integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==
+  dependencies:
+    atob "^2.1.2"
+    decode-uri-component "^0.2.0"
+    resolve-url "^0.2.1"
+    source-map-url "^0.4.0"
+    urix "^0.1.0"
+
+source-map-url@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
+  integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=
+
+source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7:
+  version "0.5.7"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
+  integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
+
+source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
+  integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+
+spdx-correct@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4"
+  integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==
+  dependencies:
+    spdx-expression-parse "^3.0.0"
+    spdx-license-ids "^3.0.0"
+
+spdx-exceptions@^2.1.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977"
+  integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==
+
+spdx-expression-parse@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0"
+  integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==
+  dependencies:
+    spdx-exceptions "^2.1.0"
+    spdx-license-ids "^3.0.0"
+
+spdx-license-ids@^3.0.0:
+  version "3.0.5"
+  resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654"
+  integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==
+
+spdy-transport@^2.0.18:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-2.1.1.tgz#c54815d73858aadd06ce63001e7d25fa6441623b"
+  integrity sha512-q7D8c148escoB3Z7ySCASadkegMmUZW8Wb/Q1u0/XBgDKMO880rLQDj8Twiew/tYi7ghemKUi/whSYOwE17f5Q==
+  dependencies:
+    debug "^2.6.8"
+    detect-node "^2.0.3"
+    hpack.js "^2.1.6"
+    obuf "^1.1.1"
+    readable-stream "^2.2.9"
+    safe-buffer "^5.0.1"
+    wbuf "^1.7.2"
+
+spdy@^3.3.3:
+  version "3.4.7"
+  resolved "https://registry.yarnpkg.com/spdy/-/spdy-3.4.7.tgz#42ff41ece5cc0f99a3a6c28aabb73f5c3b03acbc"
+  integrity sha1-Qv9B7OXMD5mjpsKKq7c/XDsDrLw=
+  dependencies:
+    debug "^2.6.8"
+    handle-thing "^1.2.5"
+    http-deceiver "^1.2.7"
+    safe-buffer "^5.0.1"
+    select-hose "^2.0.0"
+    spdy-transport "^2.0.18"
+
+split-string@^3.0.1, split-string@^3.0.2:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
+  integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==
+  dependencies:
+    extend-shallow "^3.0.0"
+
+sprintf-js@~1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+  integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
+
+sshpk@^1.7.0:
+  version "1.16.1"
+  resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
+  integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==
+  dependencies:
+    asn1 "~0.2.3"
+    assert-plus "^1.0.0"
+    bcrypt-pbkdf "^1.0.0"
+    dashdash "^1.12.0"
+    ecc-jsbn "~0.1.1"
+    getpass "^0.1.1"
+    jsbn "~0.1.0"
+    safer-buffer "^2.0.2"
+    tweetnacl "~0.14.0"
+
+stable@^0.1.6:
+  version "0.1.8"
+  resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
+  integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==
+
+stack-trace@0.0.x:
+  version "0.0.10"
+  resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
+  integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=
+
+stacky@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/stacky/-/stacky-1.3.1.tgz#3f117e5187b9a73d23f876d69f05c85b11804a12"
+  integrity sha1-PxF+UYe5pz0j+HbWnwXIWxGAShI=
+  dependencies:
+    chalk "^1.1.1"
+    lodash "^3.0.0"
+
+static-extend@^0.1.1:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
+  integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=
+  dependencies:
+    define-property "^0.2.5"
+    object-copy "^0.1.0"
+
+"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
+  integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
+
+statuses@~1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
+  integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==
+
+stream-shift@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d"
+  integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==
+
+stream@0.0.2:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/stream/-/stream-0.0.2.tgz#7f5363f057f6592c5595f00bc80a27f5cec1f0ef"
+  integrity sha1-f1Nj8Ff2WSxVlfALyAon9c7B8O8=
+  dependencies:
+    emitter-component "^1.1.1"
+
+streamsearch@0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a"
+  integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=
+
+"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
+  integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
+  dependencies:
+    is-fullwidth-code-point "^2.0.0"
+    strip-ansi "^4.0.0"
+
+string-width@^3.0.0, string-width@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
+  integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==
+  dependencies:
+    emoji-regex "^7.0.1"
+    is-fullwidth-code-point "^2.0.0"
+    strip-ansi "^5.1.0"
+
+string.prototype.trimleft@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz#9bdb8ac6abd6d602b17a4ed321870d2f8dcefc74"
+  integrity sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==
+  dependencies:
+    define-properties "^1.1.3"
+    function-bind "^1.1.1"
+
+string.prototype.trimright@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz#440314b15996c866ce8a0341894d45186200c5d9"
+  integrity sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==
+  dependencies:
+    define-properties "^1.1.3"
+    function-bind "^1.1.1"
+
+string_decoder@^1.1.1:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
+  integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
+  dependencies:
+    safe-buffer "~5.2.0"
+
+string_decoder@~0.10.x:
+  version "0.10.31"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
+  integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=
+
+string_decoder@~1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
+  integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
+  dependencies:
+    safe-buffer "~5.1.0"
+
+strip-ansi@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+  integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
+  dependencies:
+    ansi-regex "^2.0.0"
+
+strip-ansi@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
+  integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
+  dependencies:
+    ansi-regex "^3.0.0"
+
+strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
+  integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
+  dependencies:
+    ansi-regex "^4.1.0"
+
+strip-ansi@~0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.1.1.tgz#39e8a98d044d150660abe4a6808acf70bb7bc991"
+  integrity sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=
+
+strip-bom-stream@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz#e7144398577d51a6bed0fa1994fa05f43fd988ee"
+  integrity sha1-5xRDmFd9Uaa+0PoZlPoF9D/ZiO4=
+  dependencies:
+    first-chunk-stream "^1.0.0"
+    strip-bom "^2.0.0"
+
+strip-bom@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
+  integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=
+  dependencies:
+    is-utf8 "^0.2.0"
+
+strip-eof@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
+  integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
+
+strip-indent@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2"
+  integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=
+  dependencies:
+    get-stdin "^4.0.1"
+
+strip-indent@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68"
+  integrity sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=
+
+strip-json-comments@2.0.1, strip-json-comments@~2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+  integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
+
+supports-color@3.1.2:
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5"
+  integrity sha1-cqJiiU2dQIuVbKBf83su2KbiotU=
+  dependencies:
+    has-flag "^1.0.0"
+
+supports-color@6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a"
+  integrity sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==
+  dependencies:
+    has-flag "^3.0.0"
+
+supports-color@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
+  integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
+
+supports-color@^5.3.0:
+  version "5.5.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
+  integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
+  dependencies:
+    has-flag "^3.0.0"
+
+sw-precache@^5.1.1:
+  version "5.2.1"
+  resolved "https://registry.yarnpkg.com/sw-precache/-/sw-precache-5.2.1.tgz#06134f319eec68f3b9583ce9a7036b1c119f7179"
+  integrity sha512-8FAy+BP/FXE+ILfiVTt+GQJ6UEf4CVHD9OfhzH0JX+3zoy2uFk7Vn9EfXASOtVmmIVbL3jE/W8Z66VgPSZcMhw==
+  dependencies:
+    dom-urls "^1.1.0"
+    es6-promise "^4.0.5"
+    glob "^7.1.1"
+    lodash.defaults "^4.2.0"
+    lodash.template "^4.4.0"
+    meow "^3.7.0"
+    mkdirp "^0.5.1"
+    pretty-bytes "^4.0.2"
+    sw-toolbox "^3.4.0"
+    update-notifier "^2.3.0"
+
+sw-toolbox@^3.4.0:
+  version "3.6.0"
+  resolved "https://registry.yarnpkg.com/sw-toolbox/-/sw-toolbox-3.6.0.tgz#26df1d1c70348658e4dea2884319149b7b3183b5"
+  integrity sha1-Jt8dHHA0hljk3qKIQxkUm3sxg7U=
+  dependencies:
+    path-to-regexp "^1.0.1"
+    serviceworker-cache-polyfill "^4.0.0"
+
+table-layout@^0.4.3:
+  version "0.4.5"
+  resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-0.4.5.tgz#d906de6a25fa09c0c90d1d08ecd833ecedcb7378"
+  integrity sha512-zTvf0mcggrGeTe/2jJ6ECkJHAQPIYEwDoqsiqBjI24mvRmQbInK5jq33fyypaCBxX08hMkfmdOqj6haT33EqWw==
+  dependencies:
+    array-back "^2.0.0"
+    deep-extend "~0.6.0"
+    lodash.padend "^4.6.1"
+    typical "^2.6.1"
+    wordwrapjs "^3.0.0"
+
+tar-stream@2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.0.0.tgz#8829bbf83067bc0288a9089db49c56be395b6aea"
+  integrity sha512-n2vtsWshZOVr/SY4KtslPoUlyNh06I2SGgAOCZmquCEjlbV/LjY2CY80rDtdQRHFOYXNlgBDo6Fr3ww2CWPOtA==
+  dependencies:
+    bl "^2.2.0"
+    end-of-stream "^1.4.1"
+    fs-constants "^1.0.0"
+    inherits "^2.0.3"
+    readable-stream "^3.1.1"
+
+tar-stream@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.0.tgz#d1aaa3661f05b38b5acc9b7020efdca5179a2cc3"
+  integrity sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw==
+  dependencies:
+    bl "^3.0.0"
+    end-of-stream "^1.4.1"
+    fs-constants "^1.0.0"
+    inherits "^2.0.3"
+    readable-stream "^3.1.1"
+
+temp@^0.8.1:
+  version "0.8.4"
+  resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.4.tgz#8c97a33a4770072e0a05f919396c7665a7dd59f2"
+  integrity sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==
+  dependencies:
+    rimraf "~2.6.2"
+
+term-size@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69"
+  integrity sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=
+  dependencies:
+    execa "^0.7.0"
+
+ternary-stream@^2.0.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/ternary-stream/-/ternary-stream-2.1.1.tgz#4ad64b98668d796a085af2c493885a435a8a8bfc"
+  integrity sha512-j6ei9hxSoyGlqTmoMjOm+QNvUKDOIY6bNl4Uh1lhBvl6yjPW2iLqxDUYyfDPZknQ4KdRziFl+ec99iT4l7g0cw==
+  dependencies:
+    duplexify "^3.5.0"
+    fork-stream "^0.0.4"
+    merge-stream "^1.0.0"
+    through2 "^2.0.1"
+
+text-encoding@0.6.4:
+  version "0.6.4"
+  resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.6.4.tgz#e399a982257a276dae428bb92845cb71bdc26d19"
+  integrity sha1-45mpgiV6J22uQou5KEXLcb3CbRk=
+
+text-hex@1.0.x:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5"
+  integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==
+
+thenify-all@^1.0.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726"
+  integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=
+  dependencies:
+    thenify ">= 3.1.0 < 4"
+
+"thenify@>= 3.1.0 < 4":
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.0.tgz#e69e38a1babe969b0108207978b9f62b88604839"
+  integrity sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=
+  dependencies:
+    any-promise "^1.0.0"
+
+through2-filter@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-2.0.0.tgz#60bc55a0dacb76085db1f9dae99ab43f83d622ec"
+  integrity sha1-YLxVoNrLdghdsfna6Zq0P4PWIuw=
+  dependencies:
+    through2 "~2.0.0"
+    xtend "~4.0.0"
+
+through2-filter@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-3.0.0.tgz#700e786df2367c2c88cd8aa5be4cf9c1e7831254"
+  integrity sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==
+  dependencies:
+    through2 "~2.0.0"
+    xtend "~4.0.0"
+
+through2@^0.6.0:
+  version "0.6.5"
+  resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48"
+  integrity sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=
+  dependencies:
+    readable-stream ">=1.0.33-1 <1.1.0-0"
+    xtend ">=4.0.0 <4.1.0-0"
+
+through2@^2.0.0, through2@^2.0.1, through2@~2.0.0:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
+  integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==
+  dependencies:
+    readable-stream "~2.3.6"
+    xtend "~4.0.1"
+
+timed-out@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f"
+  integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=
+
+to-absolute-glob@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/to-absolute-glob/-/to-absolute-glob-0.1.1.tgz#1cdfa472a9ef50c239ee66999b662ca0eb39937f"
+  integrity sha1-HN+kcqnvUMI57maZm2YsoOs5k38=
+  dependencies:
+    extend-shallow "^2.0.1"
+
+to-array@0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890"
+  integrity sha1-F+bBH3PdTz10zaek/zI46a2b+JA=
+
+to-fast-properties@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
+  integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=
+
+to-fast-properties@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
+  integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=
+
+to-object-path@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
+  integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=
+  dependencies:
+    kind-of "^3.0.2"
+
+to-regex-range@^2.1.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38"
+  integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=
+  dependencies:
+    is-number "^3.0.0"
+    repeat-string "^1.6.1"
+
+to-regex@^3.0.1, to-regex@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
+  integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==
+  dependencies:
+    define-property "^2.0.2"
+    extend-shallow "^3.0.2"
+    regex-not "^1.0.2"
+    safe-regex "^1.1.0"
+
+toidentifier@1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
+  integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
+
+tough-cookie@~2.4.3:
+  version "2.4.3"
+  resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
+  integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==
+  dependencies:
+    psl "^1.1.24"
+    punycode "^1.4.1"
+
+tr46@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09"
+  integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=
+  dependencies:
+    punycode "^2.1.0"
+
+trim-newlines@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
+  integrity sha1-WIeWa7WCpFA6QetST301ARgVphM=
+
+trim-right@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
+  integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=
+
+triple-beam@^1.2.0, triple-beam@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9"
+  integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==
+
+tunnel-agent@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
+  integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=
+  dependencies:
+    safe-buffer "^5.0.1"
+
+tweetnacl@^0.14.3, tweetnacl@~0.14.0:
+  version "0.14.5"
+  resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
+  integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
+
+type-detect@0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822"
+  integrity sha1-C6XsKohWQORw6k6FBZcZANrFiCI=
+
+type-detect@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2"
+  integrity sha1-diIXzAbbJY7EiQihKY6LlRIejqI=
+
+type-detect@^4.0.0, type-detect@^4.0.5:
+  version "4.0.8"
+  resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
+  integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
+
+type-is@^1.6.4, type-is@~1.6.17, type-is@~1.6.18:
+  version "1.6.18"
+  resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
+  integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
+  dependencies:
+    media-typer "0.3.0"
+    mime-types "~2.1.24"
+
+typedarray@^0.0.6:
+  version "0.0.6"
+  resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
+  integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
+
+typical@^2.6.1:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/typical/-/typical-2.6.1.tgz#5c080e5d661cbbe38259d2e70a3c7253e873881d"
+  integrity sha1-XAgOXWYcu+OCWdLnCjxyU+hziB0=
+
+typical@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4"
+  integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==
+
+ua-parser-js@^0.7.15:
+  version "0.7.21"
+  resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.21.tgz#853cf9ce93f642f67174273cc34565ae6f308777"
+  integrity sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ==
+
+uglify-js@3.4.x:
+  version "3.4.10"
+  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f"
+  integrity sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==
+  dependencies:
+    commander "~2.19.0"
+    source-map "~0.6.1"
+
+underscore@^1.8.3:
+  version "1.9.2"
+  resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.2.tgz#0c8d6f536d6f378a5af264a72f7bec50feb7cf2f"
+  integrity sha512-D39qtimx0c1fI3ya1Lnhk3E9nONswSKhnffBI0gME9C99fYOkNi04xs8K6pePLhvl1frbDemkaBQ5ikWllR2HQ==
+
+underscore@~1.6.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.6.0.tgz#8b38b10cacdef63337b8b24e4ff86d45aea529a8"
+  integrity sha1-izixDKze9jM3uLJOT/htRa6lKag=
+
+unicode-canonical-property-names-ecmascript@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818"
+  integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==
+
+unicode-match-property-ecmascript@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c"
+  integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==
+  dependencies:
+    unicode-canonical-property-names-ecmascript "^1.0.4"
+    unicode-property-aliases-ecmascript "^1.0.4"
+
+unicode-match-property-value-ecmascript@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz#5b4b426e08d13a80365e0d657ac7a6c1ec46a277"
+  integrity sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==
+
+unicode-property-aliases-ecmascript@^1.0.4:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz#a9cc6cc7ce63a0a3023fc99e341b94431d405a57"
+  integrity sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==
+
+union-value@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847"
+  integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==
+  dependencies:
+    arr-union "^3.1.0"
+    get-value "^2.0.6"
+    is-extendable "^0.1.1"
+    set-value "^2.0.1"
+
+unique-stream@^2.0.2:
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-2.3.1.tgz#c65d110e9a4adf9a6c5948b28053d9a8d04cbeac"
+  integrity sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==
+  dependencies:
+    json-stable-stringify-without-jsonify "^1.0.1"
+    through2-filter "^3.0.0"
+
+unique-string@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a"
+  integrity sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=
+  dependencies:
+    crypto-random-string "^1.0.0"
+
+unpipe@1.0.0, unpipe@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
+  integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=
+
+unset-value@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559"
+  integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=
+  dependencies:
+    has-value "^0.3.1"
+    isobject "^3.0.0"
+
+untildify@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/untildify/-/untildify-2.1.0.tgz#17eb2807987f76952e9c0485fc311d06a826a2e0"
+  integrity sha1-F+soB5h/dpUunASF/DEdBqgmouA=
+  dependencies:
+    os-homedir "^1.0.0"
+
+unzip-response@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97"
+  integrity sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=
+
+update-notifier@^2.2.0, update-notifier@^2.3.0:
+  version "2.5.0"
+  resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.5.0.tgz#d0744593e13f161e406acb1d9408b72cad08aff6"
+  integrity sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==
+  dependencies:
+    boxen "^1.2.1"
+    chalk "^2.0.1"
+    configstore "^3.0.0"
+    import-lazy "^2.1.0"
+    is-ci "^1.0.10"
+    is-installed-globally "^0.1.0"
+    is-npm "^1.0.0"
+    latest-version "^3.0.0"
+    semver-diff "^2.0.0"
+    xdg-basedir "^3.0.0"
+
+upper-case@^1.1.1:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598"
+  integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=
+
+uri-js@^4.2.2:
+  version "4.2.2"
+  resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
+  integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
+  dependencies:
+    punycode "^2.1.0"
+
+urijs@^1.16.1, urijs@^1.19.1:
+  version "1.19.2"
+  resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.2.tgz#f9be09f00c4c5134b7cb3cf475c1dd394526265a"
+  integrity sha512-s/UIq9ap4JPZ7H1EB5ULo/aOUbWqfDi7FKzMC2Nz+0Si8GiT1rIEaprt8hy3Vy2Ex2aJPpOQv4P4DuOZ+K1c6w==
+
+urix@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
+  integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=
+
+url-parse-lax@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73"
+  integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=
+  dependencies:
+    prepend-http "^1.0.1"
+
+use@^3.1.0:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
+  integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
+
+util-deprecate@^1.0.1, util-deprecate@~1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+  integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
+
+"util@>=0.10.3 <1":
+  version "0.12.1"
+  resolved "https://registry.yarnpkg.com/util/-/util-0.12.1.tgz#f908e7b633e7396c764e694dd14e716256ce8ade"
+  integrity sha512-MREAtYOp+GTt9/+kwf00IYoHZyjM8VU4aVrkzUlejyqaIjd2GztVl5V9hGXKlvBKE3gENn/FMfHE5v6hElXGcQ==
+  dependencies:
+    inherits "^2.0.3"
+    is-arguments "^1.0.4"
+    is-generator-function "^1.0.7"
+    object.entries "^1.1.0"
+    safe-buffer "^5.1.2"
+
+utils-merge@1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
+  integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
+
+uuid@^3.2.1, uuid@^3.3.2:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
+  integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
+
+vali-date@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/vali-date/-/vali-date-1.0.0.tgz#1b904a59609fb328ef078138420934f6b86709a6"
+  integrity sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=
+
+validate-npm-package-license@^3.0.1:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
+  integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==
+  dependencies:
+    spdx-correct "^3.0.0"
+    spdx-expression-parse "^3.0.0"
+
+vargs@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/vargs/-/vargs-0.1.0.tgz#6b6184da6520cc3204ce1b407cac26d92609ebff"
+  integrity sha1-a2GE2mUgzDIEzhtAfKwm2SYJ6/8=
+
+vary@^1, vary@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
+  integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
+
+verror@1.10.0:
+  version "1.10.0"
+  resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
+  integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=
+  dependencies:
+    assert-plus "^1.0.0"
+    core-util-is "1.0.2"
+    extsprintf "^1.2.0"
+
+vinyl-fs@^2.4.4:
+  version "2.4.4"
+  resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-2.4.4.tgz#be6ff3270cb55dfd7d3063640de81f25d7532239"
+  integrity sha1-vm/zJwy1Xf19MGNkDegfJddTIjk=
+  dependencies:
+    duplexify "^3.2.0"
+    glob-stream "^5.3.2"
+    graceful-fs "^4.0.0"
+    gulp-sourcemaps "1.6.0"
+    is-valid-glob "^0.3.0"
+    lazystream "^1.0.0"
+    lodash.isequal "^4.0.0"
+    merge-stream "^1.0.0"
+    mkdirp "^0.5.0"
+    object-assign "^4.0.0"
+    readable-stream "^2.0.4"
+    strip-bom "^2.0.0"
+    strip-bom-stream "^1.0.0"
+    through2 "^2.0.0"
+    through2-filter "^2.0.0"
+    vali-date "^1.0.0"
+    vinyl "^1.0.0"
+
+vinyl@^1.0.0, vinyl@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884"
+  integrity sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=
+  dependencies:
+    clone "^1.0.0"
+    clone-stats "^0.0.1"
+    replace-ext "0.0.1"
+
+vlq@^0.2.2:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.3.tgz#8f3e4328cf63b1540c0d67e1b2778386f8975b26"
+  integrity sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==
+
+vscode-uri@=1.0.6:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-1.0.6.tgz#6b8f141b0bbc44ad7b07e94f82f168ac7608ad4d"
+  integrity sha512-sLI2L0uGov3wKVb9EB+vIQBl9tVP90nqRvxSoJ35vI3NjxE8jfsE5DSOhWgSunHSZmKS4OCi2jrtfxK7uyp2ww==
+
+wbuf@^1.1.0, wbuf@^1.7.2:
+  version "1.7.3"
+  resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df"
+  integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==
+  dependencies:
+    minimalistic-assert "^1.0.0"
+
+wct-browser-legacy@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/wct-browser-legacy/-/wct-browser-legacy-1.0.2.tgz#6be39174bd37e2903028d3dbd2292f9c4ec59767"
+  integrity sha512-23rbZwBh/DxWU36htJN9lsyBq3NxgVbuyMUq7fgFP6ZVTel+uFWO6LPXPoZQ6VyvXvlUYLE5PxY+ZdJ88a4COw==
+  dependencies:
+    "@polymer/polymer" "^3.0.0"
+    "@polymer/sinonjs" "^1.14.1"
+    "@polymer/test-fixture" "^3.0.0-pre.1"
+    "@webcomponents/webcomponentsjs" "^2.0.0"
+    accessibility-developer-tools "^2.12.0"
+    async "^1.5.2"
+    chai "^3.5.0"
+    lodash "^3.10.1"
+    mocha "^3.4.2"
+    sinon "^1.17.1"
+    sinon-chai "^2.10.0"
+    stacky "^1.3.1"
+
+wct-local@^2.1.1:
+  version "2.1.5"
+  resolved "https://registry.yarnpkg.com/wct-local/-/wct-local-2.1.5.tgz#f7986753e3ad9a35d39178a9989350523561fff1"
+  integrity sha512-eqoZhjGy4Xq2tY0uB46Grkw/ztq+/rC0ImbYKl62unFHXtOgal+kkvnxR3SLRFNM8ty9+ItgycPeH0IpTqVL+w==
+  dependencies:
+    "@types/express" "^4.0.30"
+    "@types/freeport" "^1.0.19"
+    "@types/launchpad" "^0.6.0"
+    "@types/which" "^1.3.1"
+    chalk "^2.3.0"
+    cleankill "^2.0.0"
+    freeport "^1.0.4"
+    launchpad "^0.7.0"
+    selenium-standalone "^6.7.0"
+    which "^1.0.8"
+
+wct-sauce@^2.0.2:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/wct-sauce/-/wct-sauce-2.1.0.tgz#67d0be346aabbbc28384e8d143b8d3ca7ba774c0"
+  integrity sha512-c3R4PJcbpS7Gxv2vZ4HDAqpXV6cT9peslAWMU7hHH9PMhKDPbn8RNa6E4DVL0tOmZznB+3cRmtZ6+vJ/aDwu1A==
+  dependencies:
+    chalk "^2.4.1"
+    cleankill "^2.0.0"
+    lodash "^4.17.10"
+    request "^2.85.0"
+    sauce-connect-launcher "^1.0.0"
+    temp "^0.8.1"
+    uuid "^3.2.1"
+
+wd@^1.2.0:
+  version "1.12.1"
+  resolved "https://registry.yarnpkg.com/wd/-/wd-1.12.1.tgz#067eb3674db00eeb9e506701f9314657c44d5a89"
+  integrity sha512-O99X8OnOgkqfmsPyLIRzG9LmZ+rjmdGFBCyhGpnsSL4MB4xzHoeWmSVcumDiQ5QqPZcwGkszTgeJvjk2VjtiNw==
+  dependencies:
+    archiver "^3.0.0"
+    async "^2.0.0"
+    lodash "^4.0.0"
+    mkdirp "^0.5.1"
+    q "^1.5.1"
+    request "2.88.0"
+    vargs "^0.1.0"
+
+web-component-tester@^6.9.2:
+  version "6.9.2"
+  resolved "https://registry.yarnpkg.com/web-component-tester/-/web-component-tester-6.9.2.tgz#40a7b824f2cf3cbc4305552bdfc3357977ded48a"
+  integrity sha512-s2kB/+IE8XWcnxY1fqSpqTiiHEGHWgUWariAbiRlxmAvWSuvaCVNALHYebsZrLCNCLHKcJR8/sGv/bw0MWMvjw==
+  dependencies:
+    "@polymer/sinonjs" "^1.14.1"
+    "@polymer/test-fixture" "^0.0.3"
+    "@webcomponents/webcomponentsjs" "^1.0.7"
+    accessibility-developer-tools "^2.12.0"
+    async "^2.4.1"
+    body-parser "^1.17.2"
+    bower-config "^1.4.0"
+    chalk "^1.1.3"
+    cleankill "^2.0.0"
+    express "^4.15.3"
+    findup-sync "^2.0.0"
+    glob "^7.1.2"
+    lodash "^3.10.1"
+    multer "^1.3.0"
+    nomnom "^1.8.1"
+    polyserve "^0.27.13"
+    resolve "^1.5.0"
+    semver "^5.3.0"
+    send "^0.16.1"
+    server-destroy "^1.0.1"
+    sinon "^2.3.5"
+    sinon-chai "^2.10.0"
+    socket.io "^2.0.3"
+    stacky "^1.3.1"
+    wd "^1.2.0"
+  optionalDependencies:
+    update-notifier "^2.2.0"
+    wct-local "^2.1.1"
+    wct-sauce "^2.0.2"
+
+webidl-conversions@^4.0.2:
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
+  integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==
+
+whatwg-url@^6.4.0:
+  version "6.5.0"
+  resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.5.0.tgz#f2df02bff176fd65070df74ad5ccbb5a199965a8"
+  integrity sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==
+  dependencies:
+    lodash.sortby "^4.7.0"
+    tr46 "^1.0.1"
+    webidl-conversions "^4.0.2"
+
+which-module@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
+  integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
+
+which@1.3.1, which@^1.0.8, which@^1.2.14, which@^1.2.9, which@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
+  integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
+  dependencies:
+    isexe "^2.0.0"
+
+wide-align@1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
+  integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==
+  dependencies:
+    string-width "^1.0.2 || 2"
+
+widest-line@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.1.tgz#7438764730ec7ef4381ce4df82fb98a53142a3fc"
+  integrity sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==
+  dependencies:
+    string-width "^2.1.1"
+
+winston-transport@^4.2.0, winston-transport@^4.3.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.3.0.tgz#df68c0c202482c448d9b47313c07304c2d7c2c66"
+  integrity sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A==
+  dependencies:
+    readable-stream "^2.3.6"
+    triple-beam "^1.2.0"
+
+winston@^3.0.0:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/winston/-/winston-3.2.1.tgz#63061377976c73584028be2490a1846055f77f07"
+  integrity sha512-zU6vgnS9dAWCEKg/QYigd6cgMVVNwyTzKs81XZtTFuRwJOcDdBg7AU0mXVyNbs7O5RH2zdv+BdNZUlx7mXPuOw==
+  dependencies:
+    async "^2.6.1"
+    diagnostics "^1.1.1"
+    is-stream "^1.1.0"
+    logform "^2.1.1"
+    one-time "0.0.4"
+    readable-stream "^3.1.1"
+    stack-trace "0.0.x"
+    triple-beam "^1.3.0"
+    winston-transport "^4.3.0"
+
+wordwrap@~0.0.2:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
+  integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc=
+
+wordwrapjs@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/wordwrapjs/-/wordwrapjs-3.0.0.tgz#c94c372894cadc6feb1a66bff64e1d9af92c5d1e"
+  integrity sha512-mO8XtqyPvykVCsrwj5MlOVWvSnCdT+C+QVbm6blradR7JExAhbkZ7hZ9A+9NUtwzSqrlUo9a67ws0EiILrvRpw==
+  dependencies:
+    reduce-flatten "^1.0.1"
+    typical "^2.6.1"
+
+wrap-ansi@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09"
+  integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==
+  dependencies:
+    ansi-styles "^3.2.0"
+    string-width "^3.0.0"
+    strip-ansi "^5.0.0"
+
+wrappy@1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+  integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
+
+write-file-atomic@^2.0.0:
+  version "2.4.3"
+  resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481"
+  integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==
+  dependencies:
+    graceful-fs "^4.1.11"
+    imurmurhash "^0.1.4"
+    signal-exit "^3.0.2"
+
+ws@^7.1.2:
+  version "7.2.1"
+  resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.1.tgz#03ed52423cd744084b2cf42ed197c8b65a936b8e"
+  integrity sha512-sucePNSafamSKoOqoNfBd8V0StlkzJKL2ZAhGQinCfNQ+oacw+Pk7lcdAElecBF2VkLNZRiIb5Oi1Q5lVUVt2A==
+
+ws@~6.1.0:
+  version "6.1.4"
+  resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9"
+  integrity sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==
+  dependencies:
+    async-limiter "~1.0.0"
+
+xdg-basedir@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4"
+  integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=
+
+xmlbuilder@8.2.2:
+  version "8.2.2"
+  resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-8.2.2.tgz#69248673410b4ba42e1a6136551d2922335aa773"
+  integrity sha1-aSSGc0ELS6QuGmE2VR0pIjNap3M=
+
+xmldom@0.1.x:
+  version "0.1.31"
+  resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.31.tgz#b76c9a1bd9f0a9737e5a72dc37231cf38375e2ff"
+  integrity sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==
+
+xmlhttprequest-ssl@~1.5.4:
+  version "1.5.5"
+  resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e"
+  integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=
+
+"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@~4.0.0, xtend@~4.0.1:
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
+  integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
+
+y18n@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
+  integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==
+
+yallist@^2.1.2:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
+  integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
+
+yargs-parser@13.1.1, yargs-parser@^13.1.1:
+  version "13.1.1"
+  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0"
+  integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==
+  dependencies:
+    camelcase "^5.0.0"
+    decamelize "^1.2.0"
+
+yargs-unparser@1.6.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f"
+  integrity sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==
+  dependencies:
+    flat "^4.1.0"
+    lodash "^4.17.15"
+    yargs "^13.3.0"
+
+yargs@13.3.0, yargs@^13.3.0:
+  version "13.3.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.0.tgz#4c657a55e07e5f2cf947f8a366567c04a0dedc83"
+  integrity sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==
+  dependencies:
+    cliui "^5.0.0"
+    find-up "^3.0.0"
+    get-caller-file "^2.0.1"
+    require-directory "^2.1.1"
+    require-main-filename "^2.0.0"
+    set-blocking "^2.0.0"
+    string-width "^3.0.0"
+    which-module "^2.0.0"
+    y18n "^4.0.0"
+    yargs-parser "^13.1.1"
+
+yauzl@^2.10.0:
+  version "2.10.0"
+  resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9"
+  integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=
+  dependencies:
+    buffer-crc32 "~0.2.3"
+    fd-slicer "~1.1.0"
+
+yeast@0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"
+  integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk=
+
+zip-stream@^2.1.2:
+  version "2.1.3"
+  resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-2.1.3.tgz#26cc4bdb93641a8590dd07112e1f77af1758865b"
+  integrity sha512-EkXc2JGcKhO5N5aZ7TmuNo45budRaFGHOmz24wtJR7znbNqDPmdZtUauKX6et8KAVseAMBOyWJqEpXcHTBsh7Q==
+  dependencies:
+    archiver-utils "^2.1.0"
+    compress-commons "^2.1.1"
+    readable-stream "^3.4.0"
diff --git a/polymer-bridges b/polymer-bridges
new file mode 160000
index 0000000..855f478
--- /dev/null
+++ b/polymer-bridges
@@ -0,0 +1 @@
+Subproject commit 855f4781b702de120953a64da5c277ea4908deaa
diff --git a/tools/bzl/license-map.py b/tools/bzl/license-map.py
index 2779130..c32579c 100644
--- a/tools/bzl/license-map.py
+++ b/tools/bzl/license-map.py
@@ -3,56 +3,138 @@
 # reads bazel query XML files, to join target names with their licenses.
 
 from __future__ import print_function
+from collections import namedtuple
 
 import argparse
+import json
 from collections import defaultdict
-from shutil import copyfileobj
 from sys import stdout, stderr
 import xml.etree.ElementTree as ET
 
-
 DO_NOT_DISTRIBUTE = "//lib:LICENSE-DO_NOT_DISTRIBUTE"
 
 LICENSE_PREFIX = "//lib:LICENSE-"
 
 parser = argparse.ArgumentParser()
 parser.add_argument("--asciidoctor", action="store_true")
+parser.add_argument("--json-map", action="append", dest="json_maps")
 parser.add_argument("xmls", nargs="+")
 args = parser.parse_args()
 
-entries = defaultdict(list)
-graph = defaultdict(list)
-handled_rules = []
 
-for xml in args.xmls:
-    tree = ET.parse(xml)
-    root = tree.getroot()
+def read_file(filename):
+    "Reads file and returns its content"
+    with open(filename) as fd:
+        return fd.read()
 
-    for child in root:
-        rule_name = child.attrib["name"]
-        if rule_name in handled_rules:
-            # already handled in other xml files
-            continue
+# List of files in package to which license is applied.
+# kind - enum, one of
+#   AllFiles - license applies to all files in package
+#   OnlySpecificFiles - license applies to all files from "files" list
+#   AllFilesExceptSpecific - license applies to all files in package
+#      except several files. "files" contains list of exceptions
+# files - defines list of files for the following kinds:
+#   OnlySpecificFiles, AllFilesExceptSpecific.
+#   Each item is a string, but not necessary a real name of a file.
+#   It can be any string, understandable by human (like directory name)
+LicensedFiles = namedtuple("LicensedFiles", ["kind", "files"])
 
-        handled_rules.append(rule_name)
-        for c in list(child):
-            if c.tag != "rule-input":
+# PackageInfo - contains information about pacakge/files in packages to
+#   which license is applied.
+# name - name of the package, as specified in package.json file
+# version - optional package version. Exists only if different versions
+#   of the same package have different licenses
+# licensed_files - instance of LicensedFiles
+PackageInfo = namedtuple("PackageInfo", ["name", "version", "licensed_files"])
+
+# LicenseMapItem - describe one type of license and a list of packages
+#   under this license
+# name - name of the license
+# safename - name which is safe to use as an asciidoc bookmark name
+# packages - list of PackageInfo
+# license_text - license text as string
+LicenseMapItem = namedtuple("LicenseMapItem",
+                            ["name", "safename", "packages", "license_text"])
+
+
+def load_xmls(xml_filenames):
+    """Load xml files produced by bazel query
+     and converts them to a list of LicenseMapItem
+
+    Args:
+         xml_filenames: list of string; each string is a filename
+    Returns:
+        list of LicenseMapItem
+    """
+    entries = defaultdict(list)
+    graph = defaultdict(list)
+    handled_rules = set()
+    for xml in xml_filenames:
+        tree = ET.parse(xml)
+        root = tree.getroot()
+
+        for child in root:
+            rule_name = child.attrib["name"]
+            if rule_name in handled_rules:
+                # already handled in other xml files
                 continue
 
-            license_name = c.attrib["name"]
-            if LICENSE_PREFIX in license_name:
-                entries[rule_name].append(license_name)
-                graph[license_name].append(rule_name)
+            handled_rules.add(rule_name)
+            for c in list(child):
+                if c.tag != "rule-input":
+                    continue
 
-if len(graph[DO_NOT_DISTRIBUTE]):
-    print("DO_NOT_DISTRIBUTE license found in:", file=stderr)
-    for target in graph[DO_NOT_DISTRIBUTE]:
-        print(target, file=stderr)
-    exit(1)
+                license_name = c.attrib["name"]
+                if LICENSE_PREFIX in license_name:
+                    entries[rule_name].append(license_name)
+                    graph[license_name].append(rule_name)
 
-if args.asciidoctor:
-    # We don't want any blank line before "= Gerrit Code Review - Licenses"
-    print("""= Gerrit Code Review - Licenses
+    if len(graph[DO_NOT_DISTRIBUTE]):
+        print("DO_NOT_DISTRIBUTE license found in:", file=stderr)
+        for target in graph[DO_NOT_DISTRIBUTE]:
+            print(target, file=stderr)
+        exit(1)
+
+    result = []
+    for n in sorted(graph.keys()):
+        if len(graph[n]) == 0:
+            continue
+
+        name = n[len(LICENSE_PREFIX):]
+        safename = name.replace(".", "_")
+        packages_names = []
+        for d in sorted(graph[n]):
+            if d.startswith("//lib:") or d.startswith("//lib/"):
+                p = d[len("//lib:"):]
+            else:
+                p = d[d.index(":") + 1:].lower()
+            if "__" in p:
+                p = p[:p.index("__")]
+            packages_names.append(p)
+
+        filename = n[2:].replace(":", "/")
+        content = read_file(filename)
+        result.append(LicenseMapItem(
+            name=name,
+            safename=safename,
+            license_text=content,
+            packages=[PackageInfo(name=name, version=None,
+                                  licensed_files=LicensedFiles(kind="All",
+                                                               files=[])) for
+                      name
+                      in packages_names]
+        )
+        )
+
+    return result
+
+def main():
+    xml_data = load_xmls(args.xmls)
+    json_map_data = load_jsons(args.json_maps)
+
+    if args.asciidoctor:
+        # We don't want any blank line before "= Gerrit Code Review - Licenses"
+        print("""= Gerrit Code Review - Licenses
 
 // DO NOT EDIT - GENERATED AUTOMATICALLY.
 
@@ -93,41 +175,134 @@
 == Licenses
 """)
 
-for n in sorted(graph.keys()):
-    if len(graph[n]) == 0:
-        continue
+    for data in xml_data + json_map_data:
+        name = data.name
+        safename = data.safename
+        print()
+        print("[[%s]]" % safename)
+        print(name)
+        print()
+        for p in data.packages:
+            package_notice = ""
+            if p.licensed_files.kind == "OnlySpecificFiles":
+                package_notice = " - only the following file(s):"
+            elif p.licensed_files.kind == "AllFilesExceptSpecific":
+                package_notice = " - except the following file(s):"
 
-    name = n[len(LICENSE_PREFIX):]
-    safename = name.replace(".", "_")
-    print()
-    print("[[%s]]" % safename)
-    print(name)
-    print()
-    for d in sorted(graph[n]):
-        if d.startswith("//lib:") or d.startswith("//lib/"):
-            p = d[len("//lib:"):]
-        else:
-            p = d[d.index(":")+1:].lower()
-        if "__" in p:
-            p = p[:p.index("__")]
-        print("* " + p)
-    print()
-    print("[[%s_license]]" % safename)
-    print("----")
-    filename = n[2:].replace(":", "/")
-    try:
-        with open(filename, errors='ignore') as fd:
-            copyfileobj(fd, stdout)
-    except TypeError:
-        with open(filename) as fd:
-            copyfileobj(fd, stdout)
-    print()
-    print("----")
-    print()
+            print("* " + get_package_display_name(p) + package_notice)
+            for file in p.licensed_files.files:
+                print("** " + file)
+        print()
+        print("[[%s_license]]" % safename)
+        print("----")
+        license_text = data.license_text
+        print(data.license_text.rstrip("\r\n"))
+        print()
+        print("----")
+        print()
 
-if args.asciidoctor:
-    print("""
+    if args.asciidoctor:
+        print("""
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
 """)
+
+def load_jsons(json_filenames):
+    """Loads information about licenses from jsons files.
+    The json files are generated by license-map-generator.ts tool
+
+    Args:
+         json_filenames: list of string; each string is a filename
+    Returns:
+        list of LicenseMapItem
+    """
+    result = []
+    for json_map in json_filenames:
+        with open(json_map, 'r') as f:
+            licenses_list = json.load(f)
+        for license_id, license in licenses_list.items():
+            name = license["licenseName"]
+            safename = name.replace(".", "_")
+            packages = []
+            for p in license["packages"]:
+                package = PackageInfo(name=p["name"], version=p["version"],
+                                      licensed_files=get_licensed_files(
+                                          p["licensedFiles"]))
+                packages.append(package)
+            result.append(LicenseMapItem(
+                name=name,
+                safename=safename,
+                license_text=license["licenseText"],
+                packages=sorted(remove_duplicated_packages(packages),
+                                key=lambda package: get_package_display_name(
+                                    package)),
+            ))
+    return result
+
+def get_licensed_files(json_licensed_file_dict):
+    """Convert json dictionary to LicensedFiles"""
+    kind = json_licensed_file_dict["kind"]
+    if kind == "AllFiles":
+        return LicensedFiles(kind="All", files=[])
+    if kind == "OnlySpecificFiles" or kind == "AllFilesExceptSpecific":
+        return LicensedFiles(kind=kind, files=sorted(json_licensed_file_dict["files"]))
+    raise Exception("Invalid licensed files kind: %s".format(kind))
+
+def get_package_display_name(package):
+    """Returns a human-readable name of package with optional version"""
+    if package.version:
+        return package.name + " - " + package.version
+    else:
+        return package.name
+
+
+def can_merge_packages(package_info_list):
+    """Returns true if all versions of a package can be replaced with
+    a package name
+
+    Args:
+        package_info_list: list of PackageInfo. Method assumes,
+        that all items in package_info_list have the same package name,
+        but different package version.
+
+    Returns:
+        True if it is safe to print only a package name (without versions)
+        False otherwise
+    """
+    first = package_info_list[0]
+    for package in package_info_list:
+        if package.licensed_files != first.licensed_files:
+            return False
+    return True
+
+
+def remove_duplicated_packages(package_info_list):
+    """ Keep only the name of a package if all versions of the package
+    have the same licensed files.
+
+    Args:
+        package_info_list: list of PackageInfo. All items in the list
+           have the same license.
+
+    Returns:
+        list of PackageInfo with removed/replaced items.
+
+    Keep single version of package if all versions have the same
+    license files."""
+    name_to_package = defaultdict(list)
+    for package in package_info_list:
+        name_to_package[package.name].append(package)
+
+    result = []
+    for package_name, packages in name_to_package.items():
+        if can_merge_packages(packages):
+            package = packages[0]
+            result.append(PackageInfo(name=package.name, version=None,
+                                      licensed_files=package.licensed_files))
+        else:
+            result.extend(packages)
+    return result
+
+if __name__ == "__main__":
+    main()
\ No newline at end of file
diff --git a/tools/bzl/license.bzl b/tools/bzl/license.bzl
index 5a6bf7f..cdb13d0 100644
--- a/tools/bzl/license.bzl
+++ b/tools/bzl/license.bzl
@@ -1,8 +1,26 @@
+"""This file contains rules to generate and test the license map"""
+
 def normalize_target_name(target):
     return target.replace("//", "").replace("/", "__").replace(":", "___")
 
-def license_map(name, targets = [], opts = [], **kwargs):
-    """Generate XML for all targets that depend directly on a LICENSE file"""
+def license_map(name, targets = [], opts = [], json_maps = [], **kwargs):
+    """Generate text represantation for pacakges' and libs' licenses
+
+    Args:
+        name: of the rule
+        targets: list of targets for which licenses should be added the output file.
+            The list must not include targets, for which json_map is passed in json_maps parameter
+        opts: command line options for license-map.py tool
+        json_maps: list of json files. Such files can be produced by node_modules_licenses rule
+            for node_modules licenses.
+        **kwargs: Args passed through to genrule
+
+    Generate: text file with the name
+        gen_license_txt_{name}
+
+    """
+
+    # Generate XML for all targets that depend directly on a LICENSE file
     xmls = []
     tools = ["//tools/bzl:license-map.py", "//lib:all-licenses"]
     for target in targets:
@@ -22,10 +40,17 @@
             opts = ["--output=xml"],
         )
 
+    # Add all files from the json_maps list to license-map.py command-line arguments
+    json_maps_locations = []
+
+    for json_map in json_maps:
+        json_maps_locations.append("--json-map=$(location %s)" % json_map)
+        tools.append(json_map)
+
     # post process the XML into our favorite format.
     native.genrule(
         name = "gen_license_txt_" + name,
-        cmd = "python $(location //tools/bzl:license-map.py) %s %s > $@" % (" ".join(opts), " ".join(xmls)),
+        cmd = "python $(location //tools/bzl:license-map.py) %s %s %s > $@" % (" ".join(opts), " ".join(json_maps_locations), " ".join(xmls)),
         outs = [name + ".gen.txt"],
         tools = tools,
         **kwargs
diff --git a/tools/eclipse/gerrit_daemon.launch b/tools/eclipse/gerrit_daemon.launch
index d00f7bf..4f6c599 100644
--- a/tools/eclipse/gerrit_daemon.launch
+++ b/tools/eclipse/gerrit_daemon.launch
@@ -11,7 +11,7 @@
 </listAttribute>
 <booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
 <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="Main"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="daemon --console-log --show-stack-trace -d ${resource_loc:/gerrit}/../gerrit_testsite"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="daemon --console-log --show-stack-trace --dev-cdn http://localhost:8081 -d ${resource_loc:/gerrit}/../gerrit_testsite"/>
 <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="gerrit"/>
 <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Dgerrit.plugin-classes=${resource_loc:/gerrit/eclipse-out}/plugins"/>
 </launchConfiguration>
diff --git a/tools/js/bower2bazel.py b/tools/js/bower2bazel.py
deleted file mode 100755
index a03f764..0000000
--- a/tools/js/bower2bazel.py
+++ /dev/null
@@ -1,262 +0,0 @@
-#!/usr/bin/env python
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""
-Suggested call sequence:
-
-python tools/js/bower2bazel.py -w lib/js/bower_archives.bzl \
-  -b lib/js/bower_components.bzl
-"""
-
-from __future__ import print_function
-
-import collections
-import json
-import hashlib
-import optparse
-import os
-import subprocess
-import sys
-import tempfile
-import glob
-import bowerutil
-
-# list of licenses for packages that don't specify one in their bower.json file
-package_licenses = {
-    "codemirror-minified": "codemirror-minified",
-    "es6-promise": "es6-promise",
-    "fetch": "fetch",
-    "font-roboto-local": "polymer",
-    "iron-a11y-announcer": "polymer",
-    "iron-a11y-keys-behavior": "polymer",
-    "iron-autogrow-textarea": "polymer",
-    "iron-behaviors": "polymer",
-    "iron-dropdown": "polymer",
-    "iron-fit-behavior": "polymer",
-    "iron-flex-layout": "polymer",
-    "iron-form-element-behavior": "polymer",
-    "iron-icon": "polymer",
-    "iron-iconset-svg": "polymer",
-    "iron-input": "polymer",
-    "iron-menu-behavior": "polymer",
-    "iron-meta": "polymer",
-    "iron-overlay-behavior": "polymer",
-    "iron-resizable-behavior": "polymer",
-    "iron-selector": "polymer",
-    "iron-validatable-behavior": "polymer",
-    "moment": "moment",
-    "neon-animation": "polymer",
-    "page": "page.js",
-    "paper-button": "polymer",
-    "paper-icon-button": "polymer",
-    "paper-input": "polymer",
-    "paper-item": "polymer",
-    "paper-listbox": "polymer",
-    "paper-toggle-button": "polymer",
-    "paper-styles": "polymer",
-    "paper-tabs": "polymer",
-    "polymer": "polymer",
-    "polymer-resin": "polymer",
-    "promise-polyfill": "promise-polyfill",
-    "web-animations-js": "Apache2.0",
-    "webcomponentsjs": "polymer",
-    "paper-material": "polymer",
-    "paper-styles": "polymer",
-    "paper-behaviors": "polymer",
-    "paper-ripple": "polymer",
-    "iron-checked-element-behavior": "polymer",
-    "font-roboto-local": "polymer",
-}
-
-
-def build_bower_json(version_targets, seeds):
-    """Generate bower JSON file, return its path.
-
-    Args:
-      version_targets: bazel target names of the versions.json file.
-      seeds: an iterable of bower package names of the seed packages, ie.
-        the packages whose versions we control manually.
-    """
-    bower_json = collections.OrderedDict()
-    bower_json['name'] = 'bower2bazel-output'
-    bower_json['version'] = '0.0.0'
-    bower_json['description'] = 'Auto-generated bower.json for dependency ' + \
-                                'management'
-    bower_json['private'] = True
-    bower_json['dependencies'] = {}
-
-    seeds = set(seeds)
-    for v in version_targets:
-        path = os.path.join("bazel-out/*-fastbuild/bin",
-                            v.lstrip("/").replace(":", "/"))
-        fs = glob.glob(path)
-        err_msg = '%s: file not found or multiple files found: %s' % (path, fs)
-        assert len(fs) == 1, err_msg
-        with open(fs[0]) as f:
-            j = json.load(f)
-            if "" in j:
-                # drop dummy entries.
-                del j[""]
-
-            trimmed = {}
-            for k, v in j.items():
-                if k in seeds:
-                    trimmed[k] = v
-
-            bower_json['dependencies'].update(trimmed)
-
-    tmpdir = tempfile.mkdtemp()
-    ret = os.path.join(tmpdir, 'bower.json')
-    with open(ret, 'w') as f:
-        json.dump(bower_json, f, indent=2)
-    return ret
-
-
-def decode(input):
-    try:
-        return input.decode("utf-8")
-    except TypeError:
-        return input
-
-
-def bower_command(args):
-    base = subprocess.check_output(["bazel", "info", "output_base"]).strip()
-    exp = os.path.join(decode(base), "external", "bower", "*npm_binary.tgz")
-    fs = sorted(glob.glob(exp))
-    err_msg = "bower tarball not found or have multiple versions %s" % fs
-    assert len(fs) == 1, err_msg
-    return ["python",
-            os.getcwd() + "/tools/js/run_npm_binary.py", sorted(fs)[0]] + args
-
-
-def main(args):
-    opts = optparse.OptionParser()
-    opts.add_option('-w', help='.bzl output for WORKSPACE')
-    opts.add_option('-b', help='.bzl output for //lib:BUILD')
-    opts, args = opts.parse_args()
-
-    target_str = subprocess.check_output([
-        "bazel", "query", "kind(bower_component_bundle, //polygerrit-ui/...)"])
-    seed_str = subprocess.check_output(
-        ["bazel", "query",
-         "attr(seed, 1, kind(bower_component, deps(//polygerrit-ui/...)))"])
-    targets = [s for s in decode(target_str).split('\n') if s]
-    seeds = [s for s in decode(seed_str).split('\n') if s]
-    prefix = "//lib/js:"
-    non_seeds = [s for s in seeds if not s.startswith(prefix)]
-    assert not non_seeds, non_seeds
-    seeds = set([s[len(prefix):] for s in seeds])
-
-    version_targets = [t + "-versions.json" for t in targets]
-    subprocess.check_call(['bazel', 'build'] + version_targets)
-    bower_json_path = build_bower_json(version_targets, seeds)
-    dir = os.path.dirname(bower_json_path)
-    cmd = bower_command(["install"])
-
-    build_out = sys.stdout
-    if opts.b:
-        build_out = open(opts.b + ".tmp", 'w')
-
-    ws_out = sys.stdout
-    if opts.b:
-        ws_out = open(opts.w + ".tmp", 'w')
-
-    header = """# DO NOT EDIT
-# generated with the following command:
-#
-#   %s
-#
-
-""" % ' '.join(sys.argv)
-
-    ws_out.write(header)
-    build_out.write(header)
-
-    oldwd = os.getcwd()
-    os.chdir(dir)
-    subprocess.check_call(cmd)
-
-    interpret_bower_json(seeds, ws_out, build_out)
-    ws_out.close()
-    build_out.close()
-
-    os.chdir(oldwd)
-    os.rename(opts.w + ".tmp", opts.w)
-    os.rename(opts.b + ".tmp", opts.b)
-
-
-def dump_workspace(data, seeds, out):
-    out.write('load("//tools/bzl:js.bzl", "bower_archive")\n\n')
-    out.write('def load_bower_archives():\n')
-
-    for d in data:
-        if d["name"] in seeds:
-            continue
-        out.write("""    bower_archive(
-        name = "%(name)s",
-        package = "%(normalized-name)s",
-        version = "%(version)s",
-        sha1 = "%(bazel-sha1)s",
-    )
-""" % d)
-
-
-def dump_build(data, seeds, out):
-    out.write('load("//tools/bzl:js.bzl", "bower_component")\n\n')
-    out.write('def define_bower_components():\n')
-    for d in data:
-        out.write("    bower_component(\n")
-        out.write("        name = \"%s\",\n" % d["name"])
-        out.write("        license = \"//lib:LICENSE-%s\",\n" % d["bazel-license"])
-        deps = sorted(d.get("dependencies", {}).keys())
-        if deps:
-            if len(deps) == 1:
-                out.write("        deps = [\":%s\"],\n" % deps[0])
-            else:
-                out.write("        deps = [\n")
-                for dep in deps:
-                    out.write("            \":%s\",\n" % dep)
-                out.write("        ],\n")
-        if d["name"] in seeds:
-            out.write("        seed = True,\n")
-        out.write("    )\n")
-    # done
-
-
-def interpret_bower_json(seeds, ws_out, build_out):
-    out = subprocess.check_output(["find", "bower_components/", "-name",
-                                   ".bower.json"])
-
-    data = []
-    for f in sorted(decode(out).split('\n')):
-        if not f:
-            continue
-        pkg = json.load(open(f))
-        pkg_name = pkg["name"]
-
-        pkg["bazel-sha1"] = bowerutil.hash_bower_component(
-            hashlib.sha1(), os.path.dirname(f)).hexdigest()
-        license = package_licenses.get(pkg_name, "DO_NOT_DISTRIBUTE")
-
-        pkg["bazel-license"] = license
-        pkg["normalized-name"] = pkg["_originalSource"]
-        data.append(pkg)
-
-    dump_workspace(data, seeds, ws_out)
-    dump_build(data, seeds, build_out)
-
-
-if __name__ == '__main__':
-    main(sys.argv[1:])
diff --git a/tools/node_tools/.gitignore b/tools/node_tools/.gitignore
new file mode 100644
index 0000000..2ccbe46
--- /dev/null
+++ b/tools/node_tools/.gitignore
@@ -0,0 +1 @@
+/node_modules/
diff --git a/tools/node_tools/BUILD b/tools/node_tools/BUILD
new file mode 100644
index 0000000..018674c
--- /dev/null
+++ b/tools/node_tools/BUILD
@@ -0,0 +1,34 @@
+load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary")
+
+package(default_visibility = ["//visibility:public"])
+
+# By default, rollup_bundle rule uses rollup from @npm workspace
+# and it expects that all plugins are installed in the same workspace.
+# This rule defines another rollup-bin from @tools_npm workspace.
+# Usage: rollup_bundle(rollup_bin = "//tools/node_tools:rollup-bin, ...)
+nodejs_binary(
+    name = "rollup-bin",
+    data = [
+        "@tools_npm//:node_modules",
+    ],
+    # The entry point must be "@tools_npm:node_modules/rollup/dist/bin/rollup",
+    # But bazel doesn't run it correctly with the following command line:
+    # bazel test --test_env=GERRIT_NOTEDB=ON --spawn_strategy=standalone \
+    #    --genrule_strategy=standalone --test_output errors --test_summary detailed \
+    #    --flaky_test_attempts 3 --test_verbose_timeout_warnings --build_tests_only \
+    #    --subcommands //...
+    # This command line appears in Gerrit CI.
+    # For details, see comment in rollup-runner.js file
+    entry_point = "//tools/node_tools:rollup-runner.js",
+)
+
+# Create a tsc_wrapped compiler rule to use in the ts_library
+# compiler attribute when using self-managed dependencies
+nodejs_binary(
+    name = "tsc_wrapped-bin",
+    # Point bazel to your node_modules to find the entry point
+    data = ["@tools_npm//:node_modules"],
+    # It seems, bazel uses different approaches to compile ts files (it runs some
+    # ts service in background). It works without any workaround.
+    entry_point = "@tools_npm//:node_modules/@bazel/typescript/internal/tsc_wrapped/tsc_wrapped.js",
+)
diff --git a/tools/node_tools/legacy/BUILD b/tools/node_tools/legacy/BUILD
new file mode 100644
index 0000000..ed0946e
--- /dev/null
+++ b/tools/node_tools/legacy/BUILD
@@ -0,0 +1,15 @@
+load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary")
+
+package(default_visibility = ["//visibility:public"])
+
+nodejs_binary(
+    name = "polymer-bundler-bin",
+    data = ["@tools_npm//:node_modules"],
+    entry_point = "@tools_npm//:node_modules/polymer-bundler/lib/bin/polymer-bundler.js",
+)
+
+nodejs_binary(
+    name = "crisper-bin",
+    data = ["@tools_npm//:node_modules"],
+    entry_point = "@tools_npm//:node_modules/crisper/bin/crisper",
+)
diff --git a/tools/node_tools/legacy/index.bzl b/tools/node_tools/legacy/index.bzl
new file mode 100644
index 0000000..fe66bf8
--- /dev/null
+++ b/tools/node_tools/legacy/index.bzl
@@ -0,0 +1,66 @@
+""" File contains a wrapper for legacy polymer-bundler and crisper tools. """
+
+# File must be removed after get rid of HTML imports
+
+def _polymer_bundler_tool_impl(ctx):
+    """Wrapper for the polymer-bundler and crisper command-line tools"""
+
+    html_bundled_file = ctx.actions.declare_file(ctx.label.name + "_tmp.html")
+    ctx.actions.run(
+        executable = ctx.executable._bundler,
+        outputs = [html_bundled_file],
+        inputs = ctx.files.srcs,
+        arguments = [
+            "--inline-css",
+            "--sourcemaps",
+            "--strip-comments",
+            "--root",
+            ctx.file.entry_point.dirname,
+            "--out-file",
+            html_bundled_file.path,
+            "--in-file",
+            ctx.file.entry_point.basename,
+        ],
+    )
+
+    output_js_file = ctx.outputs.js
+    if ctx.attr.script_src_value:
+        output_js_file = ctx.actions.declare_file(ctx.attr.script_src_value, sibling = ctx.outputs.html)
+    script_src_value = ctx.attr.script_src_value if ctx.attr.script_src_value else ctx.outputs.js.path
+
+    ctx.actions.run(
+        executable = ctx.executable._crisper,
+        outputs = [ctx.outputs.html, output_js_file],
+        inputs = [html_bundled_file],
+        arguments = ["-s", html_bundled_file.path, "-h", ctx.outputs.html.path, "-j", output_js_file.path, "--always-write-script", "--script-in-head=false"],
+    )
+
+    if ctx.attr.script_src_value:
+        ctx.actions.expand_template(
+            template = output_js_file,
+            output = ctx.outputs.js,
+            substitutions = {},
+        )
+
+polymer_bundler_tool = rule(
+    implementation = _polymer_bundler_tool_impl,
+    attrs = {
+        "entry_point": attr.label(allow_single_file = True, mandatory = True),
+        "srcs": attr.label_list(allow_files = True),
+        "script_src_value": attr.string(),
+        "_bundler": attr.label(
+            default = ":polymer-bundler-bin",
+            executable = True,
+            cfg = "host",
+        ),
+        "_crisper": attr.label(
+            default = ":crisper-bin",
+            executable = True,
+            cfg = "host",
+        ),
+    },
+    outputs = {
+        "html": "%{name}.html",
+        "js": "%{name}.js",
+    },
+)
diff --git a/tools/node_tools/node_modules_licenses/BUILD b/tools/node_tools/node_modules_licenses/BUILD
new file mode 100644
index 0000000..7f7490e
--- /dev/null
+++ b/tools/node_tools/node_modules_licenses/BUILD
@@ -0,0 +1,61 @@
+load("@npm_bazel_typescript//:index.bzl", "ts_config", "ts_library")
+load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary")
+load("@npm_bazel_rollup//:index.bzl", "rollup_bundle")
+
+package(default_visibility = ["//visibility:public"])
+
+ts_library(
+    name = "licenses-map",
+    srcs = glob(["*.ts"]),
+    compiler = "//tools/node_tools:tsc_wrapped-bin",
+    node_modules = "@tools_npm//:node_modules",
+    tsconfig = "tsconfig.json",
+    deps = [
+        "@tools_npm//@types/node",
+    ],
+)
+
+# rollup_bundle - workaround for https://github.com/bazelbuild/rules_nodejs/issues/1522
+# The ts_library rule ("license-map") transpiles each .ts file to .js file.
+# The "license-map" rule includes multiple .ts files and produces multiple output files.
+# The nodejs_binary requires only one file as an entry_point. It is expected, that other
+# .js files from ts_library are also available, but because of the bug they are not available.
+# As a workaround we are using rollup_bundle to group all files together.
+rollup_bundle(
+    name = "license-map-generator-bundle",
+    config_file = "rollup.config.js",
+    entry_point = "license-map-generator.ts",
+    format = "cjs",
+    rollup_bin = "//tools/node_tools:rollup-bin",
+    deps = [
+        ":licenses-map",
+        "@tools_npm//rollup",
+        "@tools_npm//rollup-plugin-node-resolve",
+    ],
+)
+
+nodejs_binary(
+    name = "license-map-generator-bin",
+    entry_point = "license-map-generator-bundle.js",
+)
+
+# (TODO)dmfilippov Find a better way to fix it (another workaround or submit a bug to
+# plugin's authors or to a ts_config rule author).
+# The following genrule is a workaround for a bazel intellij plugin's bug.
+# According to the documentation, the ts_config_rules section should be added
+# to a .bazelproject file if a project uses typescript
+# (https://ij.bazel.build/docs/dynamic-languages-typescript.html)
+# Unfortunately, this doesn't work. It seems, that the plugin expects some output from
+# the ts_config rule, but the rule doesn't produce any output.
+# To workaround the issue, the tsconfig_editor genrule was added. The genrule only copies
+# input file to the output file, but this is enough to make bazel plugins works.
+# So, if you have any problem a typescript editor (import errors, types not found, etc...) -
+# try to build this rule from the command line
+# (bazel build tools/node_tools/node_modules/licenses:tsconfig_editor) and then sync bazel project
+# in intellij.
+genrule(
+    name = "tsconfig_editor",
+    srcs = ["tsconfig.json"],
+    outs = ["tsconfig_editor.json"],
+    cmd = "cp $< $@",
+)
diff --git a/tools/node_tools/node_modules_licenses/README.md b/tools/node_tools/node_modules_licenses/README.md
new file mode 100644
index 0000000..b3258ee
--- /dev/null
+++ b/tools/node_tools/node_modules_licenses/README.md
@@ -0,0 +1,14 @@
+This directory contains a tool to produce json file with information about licenses for npm
+workspace.
+
+The tool consists of:
+* Command-line tool (entry point license-map-generator.ts) which gets as input a list of files in
+    a node_modules folder, licenses config and produces a json file with packages grouped by their
+    licenses.
+  If the tool finds a file with an inappropriate license, then it returns error.
+
+  Exact format for input and output data of the tool can be found in the source code.
+
+* Bazel rule node_modules_licenses (in the node_modules_licenses.bzl file), which wraps
+  command-line tool and allows to call it
+    during the build
diff --git a/tools/node_tools/node_modules_licenses/base-types.ts b/tools/node_tools/node_modules_licenses/base-types.ts
new file mode 100644
index 0000000..3c067d1
--- /dev/null
+++ b/tools/node_tools/node_modules_licenses/base-types.ts
@@ -0,0 +1,24 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** Aliases to use in the code*/
+export type PackageName = string;
+export type PackageVersion = string;
+export type FilePath = string;
+export type DirPath = string;
+export type LicenseName = string;
+export type LicenseTypeName = string;
diff --git a/tools/node_tools/node_modules_licenses/installed-node-modules-map.ts b/tools/node_tools/node_modules_licenses/installed-node-modules-map.ts
new file mode 100644
index 0000000..3f4955e
--- /dev/null
+++ b/tools/node_tools/node_modules_licenses/installed-node-modules-map.ts
@@ -0,0 +1,101 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { PackageName, PackageVersion, DirPath, FilePath } from "./base-types";
+import {fail} from "./utils";
+import * as path from "path";
+import * as fs from "fs";
+
+/**
+ * Describe one installed package from node_modules
+ */
+export interface InstalledPackage {
+  /** Package name (it is calculated based on path to module) */
+  name: PackageName;
+  /** Package version from package.json */
+  version: PackageVersion;
+  /**
+   * Path to the top-level package directory, where package.json is placed
+   * This path is relative to process working directory (because bazel pass all paths relative to it)
+   */
+  rootPath: DirPath;
+  /** All files in package. Path is relative to rootPath */
+  files: FilePath[];
+}
+
+/**
+ * Calculates all installed packages from a list of files
+ * It is expected, that the addPackageJson method is called first for
+ * all package.json files first and then the addFile method is called for all files (including package.json)
+ */
+export class InsalledPackagesBuilder {
+  private readonly rootPathToPackageMap: Map<DirPath, InstalledPackage> = new Map();
+
+  public addPackageJson(packageJsonPath: string) {
+    const pack = this.createInstalledPackage(packageJsonPath);
+    this.rootPathToPackageMap.set(pack.rootPath, pack)
+  }
+  public addFile(file: string) {
+    const pack = this.findPackageForFile(file)!;
+    pack.files.push(path.relative(pack.rootPath, file));
+  }
+
+  /**
+   * Create new InstalledPackage.
+   *  The name of a package is a relative path to the closest node_modules parent.
+   * For example for the packageJsonFile='/a/node_modules/b/node_modules/d/e/package.json'
+   * the package name is 'd/e'
+   */
+  private createInstalledPackage(packageJsonFile: string): InstalledPackage {
+    const nameParts: Array<string> = [];
+    const rootPath = path.dirname(packageJsonFile);
+    let currentDir = rootPath;
+    while(currentDir != "") {
+      const partName = path.basename(currentDir);
+      if(partName === "node_modules") {
+        const version = JSON.parse(fs.readFileSync(packageJsonFile, {encoding: 'utf-8'}))["version"];
+        if(!version) {
+          fail(`Can't get version for ${packageJsonFile}`)
+        }
+        return {
+          name: nameParts.reverse().join("/"),
+          rootPath: rootPath,
+          version: version,
+          files: []
+        };
+      }
+      nameParts.push(partName);
+      currentDir = path.dirname(currentDir);
+    }
+    fail(`Can't create package info for '${packageJsonFile}'`)
+  }
+
+  private findPackageForFile(filePath: FilePath): InstalledPackage {
+    let currentDir = path.dirname(filePath);
+    while(currentDir != "") {
+      if(this.rootPathToPackageMap.has(currentDir)) {
+        return this.rootPathToPackageMap.get(currentDir)!;
+      }
+      currentDir = path.dirname(currentDir);
+    }
+    fail(`Can't find package for '${filePath}'`);
+  }
+
+  public build(): InstalledPackage[] {
+    return [...this.rootPathToPackageMap.values()];
+  }
+}
diff --git a/tools/node_tools/node_modules_licenses/license-map-generator.ts b/tools/node_tools/node_modules_licenses/license-map-generator.ts
new file mode 100644
index 0000000..c0c2315
--- /dev/null
+++ b/tools/node_tools/node_modules_licenses/license-map-generator.ts
@@ -0,0 +1,85 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * This is a command-line tool to calculate licenses for files in npm packages.
+ * The tool expected the following inputs:
+ *
+ * config.js - information about licenses for packages. The js file must be a module
+ *   and must have array of {@link PackageInfo} as a default export.
+ *
+ * node-modules-files.txt - list of files (one per line) to calculate license.
+ *   Each line must be a path to a file inside node_module directory
+ *   (full path or path relative to current work dir)
+ *
+ * shared-licenses.txt - list of files (one per line) with licenses texts. Each line is a path
+ *   to a file with license text. The files can be referenced by {@link SharedFileLicenseInfo}
+ *
+ * json-output.json - output file name. The {@link LicensesMap} defines the schema of this file.
+ *
+ * Note: It is expected, that config is compiled from .ts file end has default export.
+ * Typescript compiler checks that .ts file matches PackageInfo interface, so no additional
+ * validations are needed.
+ */
+
+import * as path from "path";
+import * as fs from "fs";
+import {PackageInfo} from "./package-license-info";
+import {fail, readMultilineParamFile} from "./utils";
+import {LicenseMapGenerator} from "./licenses-map";
+import {SharedLicensesProvider} from "./shared-licenses-provider";
+
+interface LicenseMapCommandLineArgs {
+  generatorParams: LicenseMapGeneratorParameters;
+  outputJsonPath: string;
+}
+
+export interface LicenseMapGeneratorParameters {
+  sharedLicensesFiles: string[];
+  nodeModulesFiles: string[];
+  packages: PackageInfo[];
+}
+
+function parseArguments(argv: string[]): LicenseMapCommandLineArgs {
+  if(argv.length < 6) {
+    fail("Invalid command line parameters\n" +
+        "\tUsage:\n\tnode license-map-generator config.js node-modules-files.txt shared-licenses.txt json-output.json");
+  }
+  const packages: PackageInfo[] = require(path.join(process.cwd(), argv[2])).default;
+  const nodeModulesFiles = readMultilineParamFile(argv[3]);
+  const sharedLicensesFiles = readMultilineParamFile(argv[4]);
+
+  return {
+    generatorParams: {
+      packages,
+      nodeModulesFiles,
+      sharedLicensesFiles,
+    },
+    outputJsonPath: argv[5]
+  }
+}
+
+function main() {
+  const args = parseArguments(process.argv);
+  const generator = new LicenseMapGenerator(args.generatorParams.packages, new SharedLicensesProvider(args.generatorParams.sharedLicensesFiles));
+  const licenseMap = generator.generateMap(args.generatorParams.nodeModulesFiles);
+  // JSON is quite small, so there are no reasons to minify it.
+  // Write it as multiline file with tabs (spaces).
+  fs.writeFileSync(args.outputJsonPath, JSON.stringify(licenseMap, null, 2), "utf-8");
+}
+
+main();
diff --git a/tools/node_tools/node_modules_licenses/licenses-map.ts b/tools/node_tools/node_modules_licenses/licenses-map.ts
new file mode 100644
index 0000000..9f277e5
--- /dev/null
+++ b/tools/node_tools/node_modules_licenses/licenses-map.ts
@@ -0,0 +1,279 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as path from "path";
+import * as fs from "fs";
+import {isSharedFileLicenseInfo, LicenseInfo, PackageInfo} from "./package-license-info";
+import {LicenseName, PackageName, FilePath, PackageVersion} from "./base-types";
+import { InstalledPackage, InsalledPackagesBuilder } from "./installed-node-modules-map";
+import {SharedLicensesProvider} from "./shared-licenses-provider";
+import {fail} from "./utils";
+
+interface FilteredFiles {
+  installedPackage: InstalledPackage;
+  /** Path relative to installedPackage */
+  includedFiles: FilePath[];
+  /** Path relative to installedPackage */
+  excludedFiles: FilePath[];
+}
+interface PackageLicensedFiles {
+  packageInfo: PackageInfo;
+  filteredFiles: FilteredFiles;
+}
+
+enum LicensedFilesDisplayInfoType {
+  AllFiles = "AllFiles",
+  OnlySpecificFiles = "OnlySpecificFiles",
+  AllFilesExceptSpecific = "AllFilesExceptSpecific",
+}
+
+interface AllFiles {
+  kind: LicensedFilesDisplayInfoType.AllFiles;
+}
+
+interface AllFilesExceptSpecificFiles {
+  kind: LicensedFilesDisplayInfoType.AllFilesExceptSpecific;
+  /** Path relative to installedPackage */
+  files: FilePath[]
+}
+
+interface OnlySpecificFiles {
+  kind: LicensedFilesDisplayInfoType.OnlySpecificFiles;
+  /** Path relative to installedPackage */
+  files: FilePath[];
+}
+
+export type FilteredFilesDisplayInfo = AllFiles | AllFilesExceptSpecificFiles | OnlySpecificFiles;
+
+export interface LicenseMapPackageInfo {
+  name: PackageName;
+  version: PackageVersion;
+  licensedFiles: FilteredFilesDisplayInfo;
+}
+
+export interface LicenseMapItem {
+  licenseName: LicenseName,
+  licenseText: string;
+  packages: LicenseMapPackageInfo[];
+}
+
+export type LicensesMap = { [licenseName: string]:  LicenseMapItem }
+
+/** LicenseMapGenerator calculates license map for nodeModulesFiles.
+ */
+export class LicenseMapGenerator {
+  /**
+   *  packages - information about licenses for packages
+   *  sharedLicensesProvider - returns text for shared licenses by name
+   */
+  public constructor(private readonly packages: ReadonlyArray<PackageInfo>, private readonly sharedLicensesProvider: SharedLicensesProvider) {
+  }
+
+  /** generateMap calculates LicenseMap for nodeModulesFiles
+   * Each (key, value) pair in this map has the following information:
+   * The key is a license name.
+   * The value contains information about packages and files for which this license
+   * is applied.
+   *
+   * The method tries to provide information in a compact way:
+   * 1) If all files in the package have the same license, then it stores a name of the package
+   *    without list of files
+   * 2) If different files in the package has different licenses, then the method calculates
+   *    which list is shorter - list of included files or list of excluded files.
+   */
+  public generateMap(nodeModulesFiles: ReadonlyArray<string>): LicensesMap {
+    const installedPackages = this.getInstalledPackages(nodeModulesFiles);
+    const licensedFilesGroupedByLicense = this.getLicensedFilesGroupedByLicense(installedPackages);
+
+    const result: LicensesMap = {};
+    licensedFilesGroupedByLicense.forEach((packageLicensedFiles, licenseName) => {
+      result[licenseName] = this.getLicenseMapItem(licenseName, packageLicensedFiles);
+    });
+    return result;
+  }
+
+  private getLicenseMapItem(licenseName: string, packagesLicensedFiles: PackageLicensedFiles[]): LicenseMapItem {
+    const packages: LicenseMapPackageInfo[] = [];
+    let licenseText: string = "";
+    packagesLicensedFiles.forEach((packageLicensedFiles) => {
+      const packageLicenseText = this.getLicenseText(packageLicensedFiles);
+      if (licenseText.length !== 0 && packageLicenseText !== licenseText) {
+        fail(`There are different license texts for license '${licenseName}'.\n` +
+            "Probably, you have multiple version of the same package.\n" +
+            "In this case you must define different license name for each version"
+        );
+      }
+      licenseText = packageLicenseText;
+      packages.push({
+        name: packageLicensedFiles.packageInfo.name,
+        version: packageLicensedFiles.filteredFiles.installedPackage.version,
+        licensedFiles: this.getFilteredFilesDisplayInfo(packageLicensedFiles.filteredFiles)
+      });
+    });
+    return {
+      licenseName,
+      licenseText,
+      packages
+    };
+  }
+
+  /** getFilteredFilesDisplayInfo calculates the best method to display information about
+   * filteredFiles in filteredFiles.installedPackage
+   * In the current implementation - the best method is a method with a shorter list of files
+   *
+   * Each {@link PackageInfo} has a filter for files (by default all files
+   * are included). Applying filter to files from an installedPackage returns 2 lists of files:
+   * includedFiles (i.e. files with {@link PackageInfo.license} license) and excludedFiles
+   * (i.e. files which have different license(s)).
+   *
+   * A text representaion of license-map must have full information about per-file licenses if
+   * needed, but we want to produce files lists there as short as possible
+   */
+  private getFilteredFilesDisplayInfo(filteredFiles: FilteredFiles): FilteredFilesDisplayInfo {
+    if (filteredFiles.includedFiles.length > 0 && filteredFiles.excludedFiles.length === 0) {
+      /** All files from package are included (i.e. all files have the same license).
+       * It is enough to print only installedPackage name.
+       * */
+      return {
+        kind: LicensedFilesDisplayInfoType.AllFiles
+      }
+    } else if (filteredFiles.includedFiles.length <= filteredFiles.excludedFiles.length) {
+      /** After applying filter, the number of files with filteredFiles.license is less than
+       * the number of excluded files.
+       * It is more convenient to print information about license in the format:
+       * GIT license - fontPackage (only files A,B,C)*/
+      return {
+        kind: LicensedFilesDisplayInfoType.OnlySpecificFiles,
+        files: filteredFiles.includedFiles
+      };
+    } else {
+      /** Only few files from filteredFiles.installedPackage has filteredFiles.license.
+       * It is more convenient to print information about license in the format:
+       * Apache license - fontPackage (except files A,B,C)
+       */
+      return {
+        kind: LicensedFilesDisplayInfoType.AllFilesExceptSpecific,
+        files: filteredFiles.excludedFiles
+      }
+    }
+  }
+
+  private getLicensedFilesGroupedByLicense(installedPackages: InstalledPackage[]): Map<LicenseName, PackageLicensedFiles[]> {
+    const result: Map<LicenseName, PackageLicensedFiles[]> = new Map();
+    installedPackages.forEach(installedPackage => {
+      // It is possible that different files in package have different licenses.
+      // See the getPackageInfosForInstalledPackage method for details.
+      const packageInfos = this.findPackageInfosForInstalledPackage(installedPackage);
+      if(packageInfos.length === 0) {
+        fail(`License for package '${installedPackage.name}-${installedPackage.version}' was not found`);
+      }
+
+      const allPackageLicensedFiles: Set<string> = new Set();
+      packageInfos.forEach(packInfo => {
+          const licensedFiles = this.filterFilesByPackageInfo(installedPackage, packInfo);
+          if(licensedFiles.includedFiles.length === 0) {
+            return;
+          }
+          const license = packInfo.license;
+          if (!license.type.allowed) {
+            fail(`Polygerrit bundle use files with invalid licence ${license.name} from` +
+                ` the package ${installedPackage.name}`);
+          }
+          if(!result.has(license.name)) {
+            result.set(license.name, []);
+          }
+          result.get(license.name)!.push({
+            packageInfo: packInfo,
+            filteredFiles: licensedFiles
+          });
+          licensedFiles.includedFiles.forEach((fileName) => {
+            if(allPackageLicensedFiles.has(fileName)) {
+              fail(`File '${fileName}' from '${installedPackage.name}' has multiple licenses.`)
+            }
+            allPackageLicensedFiles.add(fileName);
+          });
+        });
+      if(allPackageLicensedFiles.size !== installedPackage.files.length) {
+        fail(`Some files from '${installedPackage.name}' doesn't have a license, but they are used during build`);
+      }
+      });
+    return result;
+  }
+
+  /** getInstalledPackages Collects information about all installed packages */
+  private getInstalledPackages(nodeModulesFiles: ReadonlyArray<string>): InstalledPackage[] {
+    const builder = new InsalledPackagesBuilder();
+    // Register all package.json files - such files exists in the root folder of each module
+    nodeModulesFiles.filter(f => path.basename(f) === "package.json")
+      .forEach(packageJsonFile => builder.addPackageJson(packageJsonFile));
+    // Iterate through all files. builder adds each file to appropriate package
+    nodeModulesFiles.forEach(f => builder.addFile(f));
+    return builder.build();
+  }
+
+  /**
+   * findPackageInfosForInstalledPackage finds all possible licenses for the installedPackage.
+   * It is possible, that different files in package have different licenses.
+   * For example, @polymer/font-roboto-local package has files with 2 different licenses
+   * - .js files - Polymer license (i.e. BSD),
+   * - font files - Apache 2.0 license
+   * In this case, the package is defined several times with different filesFilter
+   */
+  private findPackageInfosForInstalledPackage(installedPackage: InstalledPackage): PackageInfo[] {
+    return this.packages.filter(packInfo => {
+      if(packInfo.name !== installedPackage.name) {
+        return false;
+      }
+      return !packInfo.versions || packInfo.versions.indexOf(installedPackage.version) >= 0;
+    });
+  }
+
+  /** Returns list of files which have license defined in packageInfo */
+  private filterFilesByPackageInfo(installedPackage: InstalledPackage, packageInfo: PackageInfo): FilteredFiles {
+    const filter = packageInfo.filesFilter;
+    if(!filter) {
+      return {
+        installedPackage,
+        includedFiles: installedPackage.files,
+        excludedFiles: [],
+      }
+    }
+    return installedPackage.files.reduce((result: FilteredFiles, f) => {
+      if(filter(f)) {
+        result.includedFiles.push(f);
+      } else {
+        result.excludedFiles.push(f);
+      }
+      return result;
+    }, {
+      installedPackage,
+      includedFiles: [],
+      excludedFiles: []
+    });
+  }
+
+  private getLicenseText(packageInfo: PackageLicensedFiles) {
+    if(isSharedFileLicenseInfo(packageInfo.packageInfo.license)) {
+      return this.sharedLicensesProvider.getText(packageInfo.packageInfo.license.sharedLicenseFile);
+    } else {
+      const filePath = path.join(packageInfo.filteredFiles.installedPackage.rootPath,
+          packageInfo.packageInfo.license.packageLicenseFile)
+      return fs.readFileSync(filePath, {encoding: 'utf-8'});
+    }
+  }
+}
+
diff --git a/tools/node_tools/node_modules_licenses/node_modules_licenses.bzl b/tools/node_tools/node_modules_licenses/node_modules_licenses.bzl
new file mode 100644
index 0000000..64c8b79
--- /dev/null
+++ b/tools/node_tools/node_modules_licenses/node_modules_licenses.bzl
@@ -0,0 +1,42 @@
+"""This file contains the rule to generate a license map for node modules"""
+
+def _node_modules_licenses_impl(ctx):
+    """Wrapper for the license-map-generator command-line tool"""
+
+    node_modules_args = ctx.actions.args()
+    node_modules_args.add_all(ctx.files.node_modules)
+    node_modules_args.use_param_file("%s", use_always = True)
+
+    licenses_texts_args = ctx.actions.args()
+    licenses_texts_args.add_all(ctx.files.licenses_texts)
+    licenses_texts_args.use_param_file("%s", use_always = True)
+
+    ctx.actions.run(
+        executable = ctx.executable._license_map_generator,
+        arguments = [ctx.file.licenses_config.path, node_modules_args, licenses_texts_args, ctx.outputs.json.path],
+        outputs = [ctx.outputs.json],
+        inputs = depset([ctx.file.licenses_config] + ctx.files.licenses_texts, transitive = [ctx.attr.node_modules.files]),
+    )
+
+# Rule to run license-map-generator.ts
+# node_modules - label of npm workspace in the format @npm//:node_modules
+# The output contains information about licenses for the workspace.
+# licenses_texts is a list of shared licenses
+# For details - see comments in the
+# tools/node_tools/node_modules_licenses/license-map-generator.ts file
+node_modules_licenses = rule(
+    implementation = _node_modules_licenses_impl,
+    attrs = {
+        "node_modules": attr.label(mandatory = True),
+        "licenses_texts": attr.label_list(allow_files = True, mandatory = True),
+        "licenses_config": attr.label(allow_single_file = True, mandatory = True),
+        "_license_map_generator": attr.label(
+            default = Label("//tools/node_tools/node_modules_licenses:license-map-generator-bin"),
+            executable = True,
+            cfg = "host",
+        ),
+    },
+    outputs = {
+        "json": "%{name}.json",
+    },
+)
diff --git a/tools/node_tools/node_modules_licenses/package-license-info.ts b/tools/node_tools/node_modules_licenses/package-license-info.ts
new file mode 100644
index 0000000..c5cdb0f
--- /dev/null
+++ b/tools/node_tools/node_modules_licenses/package-license-info.ts
@@ -0,0 +1,70 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {LicenseName, LicenseTypeName, PackageName, FilePath} from "./base-types";
+
+export interface LicenseType {
+  /** Name of license type (GPL, MIT, etc...) - can appear in Documentation*/
+  name: LicenseTypeName;
+  /** If true, the file with this license type can be used.
+   *  If false, build shouldn't use this file */
+  allowed: boolean;
+}
+
+/** Type to describe a license*/
+export type LicenseInfo = SharedFileLicenseInfo | PackageFileLicenseInfo;
+
+interface LicenseInfoBase {
+  /** Name of license - can appear in Documentation*/
+  name: LicenseName;
+  /** Type of license */
+  type: LicenseType;
+}
+
+/** Use SharedFileLicenseInfo if license text must be obtained from a list of predefined texts */
+export interface SharedFileLicenseInfo extends LicenseInfoBase {
+  /** Name of the file with license text. The path to the file is not important, only the filename is used */
+  sharedLicenseFile: string;
+}
+
+/** Use PackageFileLicenseInfo if license text must be obtained from package's file */
+export interface PackageFileLicenseInfo extends LicenseInfoBase {
+  /** Relative path to a file inside package*/
+  packageLicenseFile: string;
+}
+
+export function isSharedFileLicenseInfo(licenseInfo: LicenseInfo): licenseInfo is SharedFileLicenseInfo {
+  return (licenseInfo as SharedFileLicenseInfo).sharedLicenseFile !== undefined;
+}
+
+export function isPackageFileLicenseInfo(licenseInfo: LicenseInfo): licenseInfo is PackageFileLicenseInfo {
+  return (licenseInfo as PackageFileLicenseInfo).packageLicenseFile !== undefined;
+}
+
+export type FilesFilter = (fileName: FilePath) => boolean;
+
+/** Describes license for a whole package or to some files inside package */
+export interface PackageInfo {
+  /** Package name, as it appears in dependencies proprty of package.json */
+  name: PackageName;
+  /** Information about license*/
+  license: LicenseInfo;
+  /** If versions are set, then license applies only to a specific versions */
+  versions?: string[];
+  /** Predicate to select files to apply license. */
+  filesFilter?: FilesFilter;
+}
diff --git a/tools/node_tools/node_modules_licenses/rollup.config.js b/tools/node_tools/node_modules_licenses/rollup.config.js
new file mode 100644
index 0000000..5b4a848
--- /dev/null
+++ b/tools/node_tools/node_modules_licenses/rollup.config.js
@@ -0,0 +1,20 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export default {
+  external: ['fs', 'path']
+};
diff --git a/tools/node_tools/node_modules_licenses/shared-licenses-provider.ts b/tools/node_tools/node_modules_licenses/shared-licenses-provider.ts
new file mode 100644
index 0000000..3be85281
--- /dev/null
+++ b/tools/node_tools/node_modules_licenses/shared-licenses-provider.ts
@@ -0,0 +1,50 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as path from "path";
+import * as fs from "fs";
+import { fail } from "./utils";
+
+/** SharedLicensesProvider uses to get license's text
+ * when package itself doesn't have LICENSE file.
+ */
+export class SharedLicensesProvider {
+  private licenseNameToText: Map<string, string>;
+
+  /** constructor takes list of file paths with licenses texts.
+   * The path is used to load a license text,
+   * the filename (without dirname) is used as a license name.
+   * */
+  public constructor(sharedLicensesFiles: string[]) {
+    this.licenseNameToText = new Map();
+    sharedLicensesFiles.forEach(f => {
+      const licenseName = path.basename(f);
+      if(this.licenseNameToText.has(licenseName)) {
+        fail(`There are multiple files for the license's text '${licenseName}'`);
+      }
+      this.licenseNameToText.set(licenseName, fs.readFileSync(f, {encoding: 'utf-8'}));
+    });
+  }
+
+  public getText(licenseName: string): string {
+    if(!this.licenseNameToText.has(licenseName)) {
+      fail(`There are no text for license ${licenseName}`);
+    }
+    return this.licenseNameToText.get(licenseName)!;
+  }
+
+}
diff --git a/tools/node_tools/node_modules_licenses/tsconfig.json b/tools/node_tools/node_modules_licenses/tsconfig.json
new file mode 100644
index 0000000..2854857
--- /dev/null
+++ b/tools/node_tools/node_modules_licenses/tsconfig.json
@@ -0,0 +1,13 @@
+{
+  "compilerOptions": {
+    "target": "es6",
+    "module": "commonjs",
+    "allowSyntheticDefaultImports": true,
+    "esModuleInterop": true,
+    "strict": true,
+    "moduleResolution": "node",
+    "outDir": "out",
+    "types": ["node"]
+  },
+  "include": ["*.ts"]
+}
diff --git a/tools/node_tools/node_modules_licenses/utils.ts b/tools/node_tools/node_modules_licenses/utils.ts
new file mode 100644
index 0000000..5f8e7b3
--- /dev/null
+++ b/tools/node_tools/node_modules_licenses/utils.ts
@@ -0,0 +1,27 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as fs from "fs";
+
+export function fail(message: string): never {
+  console.error(message);
+  process.exit(1);
+}
+
+export function readMultilineParamFile(path: string): string[] {
+  return fs.readFileSync(path, {encoding: 'utf-8'}).split(/\r?\n/).filter(f => f.length > 0);
+}
diff --git a/tools/node_tools/package.json b/tools/node_tools/package.json
new file mode 100644
index 0000000..c25d02e
--- /dev/null
+++ b/tools/node_tools/package.json
@@ -0,0 +1,22 @@
+{
+  "name": "gerrit-build-tools",
+  "description": "Gerrit Build Tools",
+  "browser": false,
+  "dependencies": {
+    "@types/parse5": "^4.0.0",
+    "@bazel/rollup": "^0.41.0",
+    "@bazel/typescript": "^1.0.1",
+    "@types/node": "^10.17.12",
+    "crisper": "^2.1.1",
+    "dom5": "^3.0.1",
+    "polymer-bundler": "^4.0.10",
+    "polymer-cli": "^1.9.11",
+    "rollup": "^1.27.5",
+    "rollup-plugin-node-resolve": "^5.2.0",
+    "rollup-plugin-terser": "^5.1.3",
+    "typescript": "^3.7.4"
+  },
+  "devDependencies": {},
+  "license": "Apache-2.0",
+  "private": true
+}
diff --git a/tools/node_tools/polygerrit_app_preprocessor/.gitignore b/tools/node_tools/polygerrit_app_preprocessor/.gitignore
new file mode 100644
index 0000000..6a3417b
--- /dev/null
+++ b/tools/node_tools/polygerrit_app_preprocessor/.gitignore
@@ -0,0 +1 @@
+/out/
diff --git a/tools/node_tools/polygerrit_app_preprocessor/BUILD b/tools/node_tools/polygerrit_app_preprocessor/BUILD
new file mode 100644
index 0000000..b031293
--- /dev/null
+++ b/tools/node_tools/polygerrit_app_preprocessor/BUILD
@@ -0,0 +1,74 @@
+load("@npm_bazel_typescript//:index.bzl", "ts_library")
+load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary")
+load("@npm_bazel_rollup//:index.bzl", "rollup_bundle")
+
+package(default_visibility = ["//visibility:public"])
+
+ts_library(
+    name = "preprocessor",
+    srcs = glob(["*.ts"]),
+    node_modules = "@tools_npm//:node_modules",
+    tsconfig = "tsconfig.json",
+    deps = [
+        "//tools/node_tools/utils",
+        "@tools_npm//:node_modules",
+    ],
+)
+
+#rollup_bundle - workaround for https://github.com/bazelbuild/rules_nodejs/issues/1522
+rollup_bundle(
+    name = "preprocessor-bundle",
+    config_file = "rollup.config.js",
+    entry_point = "preprocessor.ts",
+    format = "cjs",
+    rollup_bin = "//tools/node_tools:rollup-bin",
+    deps = [
+        ":preprocessor",
+        "@tools_npm//rollup-plugin-node-resolve",
+    ],
+)
+
+rollup_bundle(
+    name = "links-updater-bundle",
+    config_file = "rollup.config.js",
+    entry_point = "links-updater.ts",
+    format = "cjs",
+    rollup_bin = "//tools/node_tools:rollup-bin",
+    deps = [
+        ":preprocessor",
+        "@tools_npm//rollup-plugin-node-resolve",
+    ],
+)
+
+nodejs_binary(
+    name = "preprocessor-bin",
+    data = ["@tools_npm//:node_modules"],
+    entry_point = "preprocessor-bundle.js",
+)
+
+nodejs_binary(
+    name = "links-updater-bin",
+    data = ["@tools_npm//:node_modules"],
+    entry_point = "links-updater-bundle.js",
+)
+
+# TODO(dmfilippov): Find a better way to fix it (another workaround or submit a bug to
+# Bazel IJ plugin's) authors or to a ts_config rule author).
+# The following genrule is a workaround for a bazel intellij plugin's bug.
+# According to the documentation, the ts_config_rules section should be added
+# to a .bazelproject file if a project uses typescript
+# (https://ij.bazel.build/docs/dynamic-languages-typescript.html)
+# Unfortunately, this doesn't work. It seems, that the plugin expects some output from
+# the ts_config rule, but the rule doesn't produce any output.
+# To workaround the issue, the tsconfig_editor genrule was added. The genrule only copies
+# input file to the output file, but this is enough to make bazel IJ plugins works.
+# So, if you have any problem a typescript editor (import errors, types not found, etc...) -
+# try to build this rule from the command line
+# (bazel build tools/node_tools/node_modules/licenses:tsconfig_editor) and then sync bazel project
+# in intellij.
+genrule(
+    name = "tsconfig_editor",
+    srcs = ["tsconfig.json"],
+    outs = ["tsconfig_editor.json"],
+    cmd = "cp $< $@",
+)
diff --git a/tools/node_tools/polygerrit_app_preprocessor/README.md b/tools/node_tools/polygerrit_app_preprocessor/README.md
new file mode 100644
index 0000000..91f2a2b
--- /dev/null
+++ b/tools/node_tools/polygerrit_app_preprocessor/README.md
@@ -0,0 +1,9 @@
+This directory contains bazel rules and CLI tools to preprocess HTML and JS files before bundling.
+
+There are 2 different tools here:
+* links-updater (and update_links rule) - updates link in HTML files.
+ Receives list of input and output files as well as a redirect.json file with information
+ about redirects.
+* preprocessor (and prepare_for_bundling rule) - split each HTML files to a pair of one HTML
+ and one JS files. The output HTML doesn't contain `<script>` tags and JS file contains
+  all scripts and imports from HTML file. For more details see source code.
diff --git a/tools/node_tools/polygerrit_app_preprocessor/index.bzl b/tools/node_tools/polygerrit_app_preprocessor/index.bzl
new file mode 100644
index 0000000..ba53815
--- /dev/null
+++ b/tools/node_tools/polygerrit_app_preprocessor/index.bzl
@@ -0,0 +1,184 @@
+"""This file contains rules to preprocess files before bundling"""
+
+def _update_links_impl(ctx):
+    """Wrapper for the links-update command-line tool"""
+
+    dir_name = ctx.label.name
+    output_files = []
+    input_js_files = []
+    output_js_files = []
+    js_files_args = ctx.actions.args()
+    js_files_args.set_param_file_format("multiline")
+    js_files_args.use_param_file("%s", use_always = True)
+
+    for f in ctx.files.srcs:
+        output_file = ctx.actions.declare_file(dir_name + "/" + f.path)
+        output_files.append(output_file)
+        if f.extension == "html":
+            input_js_files.append(f)
+            output_js_files.append(output_file)
+            js_files_args.add(f)
+            js_files_args.add(output_file)
+        else:
+            ctx.actions.expand_template(
+                output = output_file,
+                template = f,
+                substitutions = {},
+            )
+
+    ctx.actions.run(
+        executable = ctx.executable._updater,
+        outputs = output_js_files,
+        inputs = input_js_files + [ctx.file.redirects],
+        arguments = [js_files_args, ctx.file.redirects.path],
+    )
+    return [DefaultInfo(files = depset(output_files))]
+
+update_links = rule(
+    implementation = _update_links_impl,
+    attrs = {
+        "srcs": attr.label_list(allow_files = True),
+        "redirects": attr.label(allow_single_file = True, mandatory = True),
+        "_updater": attr.label(
+            default = ":links-updater-bin",
+            executable = True,
+            cfg = "host",
+        ),
+    },
+)
+
+def _get_node_modules_root(node_modules):
+    if node_modules == None or len(node_modules) == 0:
+        return None
+
+    node_module_root = node_modules[0].label.workspace_root
+    for target in node_modules:
+        if target.label.workspace_root != node_module_root:
+            fail("Only one node_modules workspace can be used")
+    return node_module_root + "/"
+
+def _get_relative_path(file, root):
+    root_len = len(root)
+    if file.path.startswith(root):
+        return file.path[root_len - 1:]
+    else:
+        fail("The file '%s' is not under the root '%s'." % (file.path, root))
+
+def _copy_file(ctx, src, target_name):
+    output_file = ctx.actions.declare_file(target_name)
+    ctx.actions.expand_template(
+        output = output_file,
+        template = src,
+        substitutions = {},
+    )
+    return output_file
+
+def _get_generated_files(ctx, files, files_root_path, target_dir):
+    gen_files_for_html = dict()
+    gen_files_for_js = dict()
+    copied_files = []
+    for f in files:
+        target_name = target_dir + _get_relative_path(f, files_root_path)
+        if f.extension == "html":
+            html_output_file = ctx.actions.declare_file(target_name)
+            js_output_file = ctx.actions.declare_file(target_name + "_gen.js")
+            gen_files_for_html.update([[f, {"html": html_output_file, "js": js_output_file}]])
+        elif f.extension == "js":
+            js_output_file = ctx.actions.declare_file(target_name)
+            gen_files_for_js.update([[f, {"js": js_output_file}]])
+        else:
+            copied_files.append(_copy_file(ctx, f, target_name))
+    return (gen_files_for_html, gen_files_for_js, copied_files)
+
+def _prepare_for_bundling_impl(ctx):
+    dir_name = ctx.label.name
+    all_output_files = []
+
+    node_modules_root = _get_node_modules_root(ctx.attr.node_modules)
+
+    html_files_dict = dict()
+    js_files_dict = dict()
+
+    root_path = ctx.bin_dir.path + "/" + ctx.attr.root_path
+    if not root_path.endswith("/"):
+        root_path = root_path + "/"
+
+    gen_files_for_html, gen_files_for_js, copied_files = _get_generated_files(ctx, ctx.files.srcs, root_path, dir_name)
+    html_files_dict.update(gen_files_for_html)
+    js_files_dict.update(gen_files_for_js)
+    all_output_files.extend(copied_files)
+
+    gen_files_for_html, gen_files_for_js, copied_files = _get_generated_files(ctx, ctx.files.additional_node_modules_to_preprocess, node_modules_root, dir_name)
+    html_files_dict.update(gen_files_for_html)
+    js_files_dict.update(gen_files_for_js)
+    all_output_files.extend(copied_files)
+
+    for f in ctx.files.node_modules:
+        target_name = dir_name + _get_relative_path(f, node_modules_root)
+        if html_files_dict.get(f) == None and js_files_dict.get(f) == None:
+            all_output_files.append(_copy_file(ctx, f, target_name))
+
+    preprocessed_output_files = []
+    html_files_args = ctx.actions.args()
+    html_files_args.set_param_file_format("multiline")
+    html_files_args.use_param_file("%s", use_always = True)
+
+    for src_path, output_files in html_files_dict.items():
+        html_files_args.add(src_path)
+        html_files_args.add(output_files["html"])
+        html_files_args.add(output_files["js"])
+        preprocessed_output_files.append(output_files["html"])
+        preprocessed_output_files.append(output_files["js"])
+
+    js_files_args = ctx.actions.args()
+    js_files_args.set_param_file_format("multiline")
+    js_files_args.use_param_file("%s", use_always = True)
+    for src_path, output_files in js_files_dict.items():
+        js_files_args.add(src_path)
+        js_files_args.add(output_files["js"])
+        preprocessed_output_files.append(output_files["js"])
+
+    all_output_files.extend(preprocessed_output_files)
+
+    ctx.actions.run(
+        executable = ctx.executable._preprocessor,
+        outputs = preprocessed_output_files,
+        inputs = ctx.files.srcs + ctx.files.additional_node_modules_to_preprocess,
+        arguments = [root_path, html_files_args, js_files_args],
+    )
+
+    entry_point_html = ctx.attr.entry_point
+    entry_point_js = ctx.attr.entry_point + "_gen.js"
+    ctx.actions.write(ctx.outputs.html, "<link rel=\"import\" href=\"./%s\" >" % entry_point_html)
+    ctx.actions.write(ctx.outputs.js, "import \"./%s\";" % entry_point_js)
+
+    return [
+        DefaultInfo(files = depset([ctx.outputs.html, ctx.outputs.js], transitive = [depset(all_output_files)])),
+        OutputGroupInfo(
+            js = depset([ctx.outputs.js] + [f for f in all_output_files if f.extension == "js"]),
+            html = depset([ctx.outputs.html] + [f for f in all_output_files if f.extension == "html"]),
+        ),
+    ]
+
+prepare_for_bundling = rule(
+    implementation = _prepare_for_bundling_impl,
+    attrs = {
+        "srcs": attr.label_list(allow_files = True),
+        "node_modules": attr.label_list(allow_files = True),
+        "_preprocessor": attr.label(
+            default = ":preprocessor-bin",
+            executable = True,
+            cfg = "host",
+        ),
+        "additional_node_modules_to_preprocess": attr.label_list(allow_files = True),
+        "root_path": attr.string(),
+        "entry_point": attr.string(
+            mandatory = True,
+            doc = "Path relative to root_path",
+        ),
+    },
+    outputs = {
+        "html": "%{name}/entry.html",
+        "js": "%{name}/entry.js",
+    },
+)
diff --git a/tools/node_tools/polygerrit_app_preprocessor/links-updater.ts b/tools/node_tools/polygerrit_app_preprocessor/links-updater.ts
new file mode 100644
index 0000000..eb7212b
--- /dev/null
+++ b/tools/node_tools/polygerrit_app_preprocessor/links-updater.ts
@@ -0,0 +1,123 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as fs from "fs";
+import * as parse5 from "parse5";
+import * as dom5 from "dom5";
+import {HtmlFileUtils, RedirectsResolver} from "./utils";
+import {Node} from 'dom5';
+import {readMultilineParamFile} from "../utils/command-line";
+import {FileUtils} from "../utils/file-utils";
+import { fail } from "../utils/common";
+import {JSONRedirects} from "./redirects";
+
+/** Update links in HTML file
+ * input_output_param_files - is a list of paths; each path is placed on a separate line
+ *   The first line is the path to a first input file (relative to process working directory)
+ *   The second line is the path to the output file  (relative to process working directory)
+ *   The next 2 lines describe the second file and so on.
+ * redirectFile.json describes how to update links (see {@link JSONRedirects} for exact format)
+ * Additionaly, update some test links (related to web-component-tester)
+ */
+
+function main() {
+  console.log(process.cwd());
+
+  if (process.argv.length < 4) {
+    console.info("Usage:\n\tnode links_updater.js input_output_param_files redirectFile.json\n");
+    process.exit(1);
+  }
+
+  const jsonRedirects: JSONRedirects = JSON.parse(fs.readFileSync(process.argv[3], {encoding: "utf-8"}));
+  const redirectsResolver = new RedirectsResolver(jsonRedirects.redirects);
+
+  const input = readMultilineParamFile(process.argv[2]);
+  const updater = new HtmlFileUpdater(redirectsResolver);
+  for(let i = 0; i < input.length; i += 2) {
+    const srcFile = input[i];
+    const targetFile = input[i + 1];
+    updater.updateFile(srcFile, targetFile);
+  }
+}
+
+/** Update all links in HTML file based on redirects.
+ * Additionally, update references to web-component-tester */
+class HtmlFileUpdater {
+  private static readonly Predicates = {
+    isScriptWithSrcTag: (node: Node) => node.tagName === "script" && dom5.hasAttribute(node, "src"),
+
+    isWebComponentTesterImport: (node: Node) => HtmlFileUpdater.Predicates.isScriptWithSrcTag(node) &&
+        dom5.getAttribute(node, "src")!.endsWith("/bower_components/web-component-tester/browser.js"),
+
+    isHtmlImport: (node: Node) => node.tagName === "link" && dom5.getAttribute(node, "rel") === "import" &&
+        dom5.hasAttribute(node, "href")
+  };
+  public constructor(private readonly redirectsResolver: RedirectsResolver) {
+  }
+
+  public updateFile(srcFile: string, targetFile: string) {
+    const html = fs.readFileSync(srcFile, "utf-8");
+    const ast = parse5.parseFragment(html, {locationInfo: true}) as Node;
+
+
+    const webComponentTesterImportNode = dom5.query(ast, HtmlFileUpdater.Predicates.isWebComponentTesterImport);
+    if(webComponentTesterImportNode) {
+      dom5.setAttribute(webComponentTesterImportNode,  "src", "/components/wct-browser-legacy/browser.js");
+    }
+
+    // Update all HTML imports
+    const updateHtmlImportHref = (htmlImportNode: Node) => this.updateRefAttribute(htmlImportNode, srcFile, "href");
+    dom5.queryAll(ast, HtmlFileUpdater.Predicates.isHtmlImport).forEach(updateHtmlImportHref);
+
+    // Update all <script src=...> tags
+    const updateScriptSrc = (scriptTagNode: Node) => this.updateRefAttribute(scriptTagNode, srcFile, "src");
+    dom5.queryAll(ast, HtmlFileUpdater.Predicates.isScriptWithSrcTag).forEach(updateScriptSrc);
+
+    const newContent = parse5.serialize(ast);
+    FileUtils.writeContent(targetFile, newContent);
+  }
+
+  private getResolvedPath(parentHtml: string, href: string) {
+    const originalPath = '/' + HtmlFileUtils.getPathRelativeToRoot(parentHtml, href);
+
+    const resolvedInfo = this.redirectsResolver.resolve(originalPath, true);
+    if (!resolvedInfo.insideNodeModules && resolvedInfo.target === originalPath) {
+      return href;
+    }
+    if (resolvedInfo.insideNodeModules) {
+      return '/node_modules/' + resolvedInfo.target;
+    }
+    if (href.startsWith('/')) {
+      return resolvedInfo.target;
+    }
+    return HtmlFileUtils.getPathRelativeToRoot(parentHtml, resolvedInfo.target);
+  }
+
+  private updateRefAttribute(node: Node, parentHtml: string, attributeName: string) {
+    const ref = dom5.getAttribute(node, attributeName);
+    if(!ref) {
+      fail(`Internal error - ${node} in ${parentHtml} doesn't have attribute ${attributeName}`);
+    }
+    const newRef = this.getResolvedPath(parentHtml, ref);
+    if(newRef === ref) {
+      return;
+    }
+    dom5.setAttribute(node,  attributeName, newRef);
+  }
+}
+
+main();
diff --git a/tools/node_tools/polygerrit_app_preprocessor/preprocessor.ts b/tools/node_tools/polygerrit_app_preprocessor/preprocessor.ts
new file mode 100644
index 0000000..a886373
--- /dev/null
+++ b/tools/node_tools/polygerrit_app_preprocessor/preprocessor.ts
@@ -0,0 +1,352 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as fs from "fs";
+import * as parse5 from "parse5";
+import * as dom5 from "dom5";
+import * as path from "path";
+import {Node} from 'dom5';
+import {fail, unexpectedSwitchValue} from "../utils/common";
+import {readMultilineParamFile} from "../utils/command-line";
+import {
+  HtmlSrcFilePath,
+  JsSrcFilePath,
+  HtmlTargetFilePath,
+  JsTargetFilePath,
+  FileUtils,
+  FilePath
+} from "../utils/file-utils";
+import {
+  AbsoluteWebPath,
+  getRelativeImport,
+  NodeModuleImportPath,
+  SrcWebSite
+} from "../utils/web-site-utils";
+
+/**
+ * Update source code by moving all scripts out of HTML files.
+ * Input:
+ *   input_output_html_param_file - list of file paths, each file path on a separate line
+ *      The first 3 line contains the path to the first input HTML file and 2 output paths
+ *         (for HTML and JS files)
+ *      The second 3 line contains paths for the second HTML file, and so on.
+ *
+ *   input_output_js_param_file - similar to input_output_html_param_file, but has only 2 lines
+ *      per file (input JS file and output JS file)
+ *
+ *   input_web_root_path - path (in filesystem) which should be treated as a web-site root path.
+
+ *    For each HTML file it creates 2 output files - HTML and JS file.
+ *      HTML file contains everything from HTML input file, except <script> tags.
+ *      JS file contains (in the same order, as in original HTML):
+ *      - inline javascript code from HTML file
+ *      - each <script src = "path/to/file.js" > from HTML is converted to
+ *           import 'path/to/output/file.js'
+ *        statement. Such import statement run all side-effects in file.js (i.e. it run all    #
+ *        global code).
+ *      - each <link rel="import" href = "path/to/file.html"> adds to .js file as
+ *           import 'path/to/output/file.html.js
+ *        i.e. instead of html, the .js script imports
+ *    Because output JS keeps the order of imports, all global variables are
+ *    initialized in a correct order (this is important for gerrit; it is impossible to use
+ *    AMD modules here).
+ */
+
+enum RefType {
+  Html,
+  InlineJS,
+  JSFile
+}
+
+type LinkOrScript = HtmlFileRef | HtmlFileNodeModuleRef | JsFileReference | JsFileNodeModuleReference | InlineJS;
+
+interface HtmlFileRef {
+  type: RefType.Html,
+  path: HtmlSrcFilePath;
+  isNodeModule: false;
+}
+
+interface HtmlFileNodeModuleRef {
+  type: RefType.Html,
+  path: NodeModuleImportPath;
+  isNodeModule: true;
+}
+
+
+function isHtmlFileRef(ref: LinkOrScript): ref is HtmlFileRef {
+  return ref.type === RefType.Html;
+}
+
+interface JsFileReference {
+  type: RefType.JSFile,
+  path: JsSrcFilePath;
+  isModule: boolean;
+  isNodeModule: false;
+}
+
+interface JsFileNodeModuleReference {
+  type: RefType.JSFile,
+  path: NodeModuleImportPath;
+  isModule: boolean;
+  isNodeModule: true;
+}
+
+interface InlineJS {
+  type: RefType.InlineJS,
+  isModule: boolean;
+  content: string;
+}
+
+interface HtmlOutputs {
+  html: HtmlTargetFilePath;
+  js: JsTargetFilePath;
+}
+
+interface JsOutputs {
+  js: JsTargetFilePath;
+}
+
+type HtmlSrcToOutputMap = Map<HtmlSrcFilePath, HtmlOutputs>;
+type JsSrcToOutputMap = Map<JsSrcFilePath, JsOutputs>;
+
+interface HtmlFileInfo {
+  src: HtmlSrcFilePath;
+  ast: parse5.AST.Document;
+  linksAndScripts: LinkOrScript[]
+}
+
+/** HtmlScriptAndLinksCollector walks through HTML file and collect
+ * all links and inline scripts.
+ */
+class HtmlScriptAndLinksCollector {
+  public constructor(private readonly webSite: SrcWebSite) {
+  }
+  public collect(src: HtmlSrcFilePath): HtmlFileInfo {
+    const ast = HtmlScriptAndLinksCollector.getAst(src);
+    const isHtmlImport = (node: Node) => node.tagName == "link" &&
+        dom5.getAttribute(node, "rel") == "import";
+    const isScriptTag = (node: Node) => node.tagName == "script";
+
+    const linksAndScripts: LinkOrScript[] = dom5
+      .nodeWalkAll(ast as Node, (node) => isHtmlImport(node) || isScriptTag(node))
+      .map((node) => {
+        if (isHtmlImport(node)) {
+          const href = dom5.getAttribute(node, "href");
+          if (!href) {
+            fail(`Tag <link rel="import...> in the file '${src}' doesn't have href attribute`);
+          }
+          if(this.webSite.isNodeModuleReference(href)) {
+            return {
+              type: RefType.Html,
+              path: this.webSite.getNodeModuleImport(href),
+              isNodeModule: true,
+            }
+          } else {
+            return {
+              type: RefType.Html,
+              path: this.webSite.resolveHtmlImport(src, href),
+              isNodeModule: false,
+            }
+          }
+        } else {
+          const isModule = dom5.getAttribute(node, "type") === "module";
+          if (dom5.hasAttribute(node, "src")) {
+            let srcPath = dom5.getAttribute(node, "src")!;
+            if(this.webSite.isNodeModuleReference(srcPath)) {
+              return {
+                type: RefType.JSFile,
+                isModule: isModule,
+                path: this.webSite.getNodeModuleImport(srcPath),
+                isNodeModule: true
+              };
+            } else {
+              return {
+                type: RefType.JSFile,
+                isModule: isModule,
+                path: this.webSite.resolveScriptSrc(src, srcPath),
+                isNodeModule: false
+              };
+            }
+          }
+          return {
+            type: RefType.InlineJS,
+            isModule: isModule,
+            content: dom5.getTextContent(node)
+          };
+        }
+      });
+    return {
+      src,
+      ast,
+      linksAndScripts
+    };
+  };
+
+  private static getAst(file: string): parse5.AST.Document {
+    const html = fs.readFileSync(file, "utf-8");
+    return parse5.parse(html, {locationInfo: true});
+  }
+
+}
+
+/** Generate js files */
+class ScriptGenerator {
+  public constructor(private readonly pathMapper: SrcToTargetPathMapper) {
+  }
+  public generateFromJs(src: JsSrcFilePath) {
+    FileUtils.copyFile(src, this.pathMapper.getJsTargetForJs(src));
+  }
+
+  public generateFromHtml(html: HtmlFileInfo) {
+    const content: string[] = [];
+    const src = html.src;
+    const targetJsFile: JsTargetFilePath = this.pathMapper.getJsTargetForHtml(src);
+    html.linksAndScripts.forEach((linkOrScript) => {
+      switch (linkOrScript.type) {
+        case RefType.Html:
+          if(linkOrScript.isNodeModule) {
+            const importPath = this.pathMapper.getJsTargetForHtmlInNodeModule(linkOrScript.path)
+            content.push(`import '${importPath}';`);
+          } else {
+            const importPath = this.pathMapper.getJsTargetForHtml(linkOrScript.path);
+            const htmlRelativePath = getRelativeImport(targetJsFile, importPath);
+            content.push(`import '${htmlRelativePath}';`);
+          }
+          break;
+        case RefType.JSFile:
+          if(linkOrScript.isNodeModule) {
+            content.push(`import '${linkOrScript.path}'`);
+          } else {
+            const importFromJs = this.pathMapper.getJsTargetForJs(linkOrScript.path);
+            const scriptRelativePath = getRelativeImport(targetJsFile, importFromJs);
+            content.push(`import '${scriptRelativePath}';`);
+          }
+          break;
+        case RefType.InlineJS:
+          content.push(linkOrScript.content);
+          break;
+        default:
+          unexpectedSwitchValue(linkOrScript);
+      }
+    });
+    FileUtils.writeContent(targetJsFile, content.join("\n"));
+  }
+}
+
+/** Generate html files*/
+class HtmlGenerator {
+  constructor(private readonly pathMapper: SrcToTargetPathMapper) {
+  }
+  public generateFromHtml(html: HtmlFileInfo) {
+    const ast = html.ast;
+    dom5.nodeWalkAll(ast as Node, (node) => node.tagName === "script")
+      .forEach((scriptNode) => dom5.remove(scriptNode));
+    const newContent = parse5.serialize(ast);
+    if(newContent.indexOf("<script") >= 0) {
+      fail(`Has content ${html.src}`);
+    }
+    FileUtils.writeContent(this.pathMapper.getHtmlTargetForHtml(html.src), newContent);
+  }
+}
+
+function readHtmlSrcToTargetMap(paramFile: string): HtmlSrcToOutputMap {
+  const htmlSrcToTarget: HtmlSrcToOutputMap = new Map();
+  const input = readMultilineParamFile(paramFile);
+  for(let i = 0; i < input.length; i += 3) {
+    const srcHtmlFile = path.resolve(input[i]) as HtmlSrcFilePath;
+    const targetHtmlFile = path.resolve(input[i + 1]) as HtmlTargetFilePath;
+    const targetJsFile = path.resolve(input[i + 2]) as JsTargetFilePath;
+    htmlSrcToTarget.set(srcHtmlFile, {
+      html: targetHtmlFile,
+      js: targetJsFile
+    });
+  }
+  return htmlSrcToTarget;
+}
+
+function readJsSrcToTargetMap(paramFile: string): JsSrcToOutputMap {
+  const jsSrcToTarget: JsSrcToOutputMap = new Map();
+  const input = readMultilineParamFile(paramFile);
+  for(let i = 0; i < input.length; i += 2) {
+    const srcJsFile = path.resolve(input[i]) as JsSrcFilePath;
+    const targetJsFile = path.resolve(input[i + 1]) as JsTargetFilePath;
+    jsSrcToTarget.set(srcJsFile as JsSrcFilePath, {
+      js: targetJsFile as JsTargetFilePath
+    });
+  }
+  return jsSrcToTarget;
+}
+
+class SrcToTargetPathMapper {
+  public constructor(
+      private readonly htmlSrcToTarget: HtmlSrcToOutputMap,
+      private readonly jsSrcToTarget: JsSrcToOutputMap) {
+  }
+  public getJsTargetForHtmlInNodeModule(file: NodeModuleImportPath): JsTargetFilePath {
+    return `${file}_gen.js` as JsTargetFilePath;
+  }
+
+  public getJsTargetForHtml(html: HtmlSrcFilePath): JsTargetFilePath {
+    return this.getHtmlOutputs(html).js;
+  }
+  public getHtmlTargetForHtml(html: HtmlSrcFilePath): HtmlTargetFilePath {
+    return this.getHtmlOutputs(html).html;
+  }
+  public getJsTargetForJs(js: JsSrcFilePath): JsTargetFilePath {
+    return this.getJsOutputs(js).js;
+  }
+
+  private getHtmlOutputs(html: HtmlSrcFilePath): HtmlOutputs {
+    if(!this.htmlSrcToTarget.has(html)) {
+      fail(`There are no outputs for the file '${html}'`);
+    }
+    return this.htmlSrcToTarget.get(html)!;
+  }
+  private getJsOutputs(js: JsSrcFilePath): JsOutputs {
+    if(!this.jsSrcToTarget.has(js)) {
+      fail(`There are no outputs for the file '${js}'`);
+    }
+    return this.jsSrcToTarget.get(js)!;
+  }
+}
+
+function main() {
+  if(process.argv.length < 5) {
+    const execFileName = path.basename(__filename);
+    fail(`Usage:\nnode ${execFileName} input_web_root_path input_output_html_param_file input_output_js_param_file\n`);
+  }
+
+  const srcWebSite = new SrcWebSite(path.resolve(process.argv[2]) as FilePath);
+  const htmlSrcToTarget: HtmlSrcToOutputMap = readHtmlSrcToTargetMap(process.argv[3]);
+  const jsSrcToTarget: JsSrcToOutputMap = readJsSrcToTargetMap(process.argv[4]);
+  const pathMapper = new SrcToTargetPathMapper(htmlSrcToTarget, jsSrcToTarget);
+
+  const scriptGenerator = new ScriptGenerator(pathMapper);
+  const htmlGenerator = new HtmlGenerator(pathMapper);
+  const scriptAndLinksCollector = new HtmlScriptAndLinksCollector(srcWebSite);
+
+  htmlSrcToTarget.forEach((targets, src) => {
+    const htmlFileInfo = scriptAndLinksCollector.collect(src);
+    scriptGenerator.generateFromHtml(htmlFileInfo);
+    htmlGenerator.generateFromHtml(htmlFileInfo);
+  });
+  jsSrcToTarget.forEach((targets, src) => {
+    scriptGenerator.generateFromJs(src);
+  });
+}
+
+main();
diff --git a/tools/node_tools/polygerrit_app_preprocessor/redirects.ts b/tools/node_tools/polygerrit_app_preprocessor/redirects.ts
new file mode 100644
index 0000000..0ccd78f
--- /dev/null
+++ b/tools/node_tools/polygerrit_app_preprocessor/redirects.ts
@@ -0,0 +1,62 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** redirects.json schema*/
+export interface JSONRedirects {
+  /** Short text description. Do not used anywhere*/
+  description?: string;
+  /** List of redirects, from the highest to lower priority. */
+  redirects: Redirect[];
+}
+
+/** Redirect - describes one redirect.
+ * Each link in the html file is converted to a path relative to site root
+ * Redirect is applied, if converted link started with 'from'
+ * */
+export interface Redirect {
+  /** from - path prefix. The '/' is added to the end of string if not present */
+  from: string;
+  /** New location - can be either other directory or node module*/
+  to: PathRedirect;
+}
+
+export type PathRedirect = RedirectToDir | RedirectToNodeModule;
+
+/** RedirectToDir - use another dir instead of original one*/
+export interface RedirectToDir {
+  /** New dir (relative to site root)*/
+  dir: string;
+  /** Redirects for files inside directory
+   * Key is the original relative path, value is the new relative path (relative to new dir) */
+  files?: { [name: string]: string }
+}
+
+export interface RedirectToNodeModule {
+  /** Import from this node module instead of directory*/
+  npm_module: string;
+  /** Redirects for files inside node module
+   * Key is the original relative path, value is the new relative path (relative to npm_module) */
+  files?: { [name: string]: string }
+}
+
+export function isRedirectToNodeModule(redirect: PathRedirect): redirect is RedirectToNodeModule {
+  return (redirect as RedirectToNodeModule).npm_module !== undefined;
+}
+
+export function isRedirectToDir(redirect: PathRedirect): redirect is RedirectToDir {
+  return (redirect as RedirectToDir).dir !== undefined;
+}
diff --git a/tools/node_tools/polygerrit_app_preprocessor/rollup.config.js b/tools/node_tools/polygerrit_app_preprocessor/rollup.config.js
new file mode 100644
index 0000000..1da4441
--- /dev/null
+++ b/tools/node_tools/polygerrit_app_preprocessor/rollup.config.js
@@ -0,0 +1,21 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+export default {
+  external: ['fs', 'path', 'parse5', 'dom5']
+};
diff --git a/tools/node_tools/polygerrit_app_preprocessor/tsconfig.json b/tools/node_tools/polygerrit_app_preprocessor/tsconfig.json
new file mode 100644
index 0000000..34ffb2f
--- /dev/null
+++ b/tools/node_tools/polygerrit_app_preprocessor/tsconfig.json
@@ -0,0 +1,12 @@
+{
+  "compilerOptions": {
+    "target": "es6",
+    "module": "commonjs",
+    "allowSyntheticDefaultImports": true,
+    "esModuleInterop": true,
+    "strict": true,
+    "moduleResolution": "node",
+    "outDir": "out"
+  },
+  "include": ["*.ts"]
+}
diff --git a/tools/node_tools/polygerrit_app_preprocessor/utils.ts b/tools/node_tools/polygerrit_app_preprocessor/utils.ts
new file mode 100644
index 0000000..4163d26
--- /dev/null
+++ b/tools/node_tools/polygerrit_app_preprocessor/utils.ts
@@ -0,0 +1,111 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as fs from "fs";
+import * as path from "path";
+import {FileUtils} from "../utils/file-utils";
+import {
+  Redirect,
+  isRedirectToNodeModule,
+  isRedirectToDir,
+  RedirectToNodeModule,
+  PathRedirect
+} from "./redirects";
+
+export class HtmlFileUtils {
+  public static getPathRelativeToRoot(parentHtml: string, fileHref: string): string {
+    if (fileHref.startsWith('/')) {
+      return fileHref.substring(1);
+    }
+    return path.join(path.dirname(parentHtml), fileHref);
+  }
+
+  public static getImportPathRelativeToParent(rootDir: string, parentFile: string, importPath: string) {
+    if (importPath.startsWith('/')) {
+      importPath = importPath.substr(1);
+    }
+    const parentDir = path.dirname(
+        path.resolve(path.join(rootDir, parentFile)));
+    const fullImportPath = path.resolve(path.join(rootDir, importPath));
+    const relativePath = path.relative(parentDir, fullImportPath);
+    return relativePath.startsWith('../') ?
+        relativePath : "./" + relativePath;
+  }
+}
+interface RedirectForFile {
+  to: PathRedirect;
+  pathToFile: string;
+}
+
+interface ResolvedPath {
+  target: string;
+  insideNodeModules: boolean;
+}
+
+/** RedirectsResolver based on the list of redirects, calculates
+ *  new import path
+ */
+export class RedirectsResolver {
+  public constructor(private readonly redirects: Redirect[]) {
+  }
+
+  /** resolve returns new path instead of pathRelativeToRoot; */
+  public resolve(pathRelativeToRoot: string, resolveNodeModules: boolean): ResolvedPath {
+    const redirect = this.findRedirect(pathRelativeToRoot);
+    if (!redirect) {
+      return {target: pathRelativeToRoot, insideNodeModules: false};
+    }
+    if (isRedirectToNodeModule(redirect.to)) {
+      return {
+        target: resolveNodeModules ? RedirectsResolver.resolveNodeModuleFile(redirect.to,
+            redirect.pathToFile) : pathRelativeToRoot,
+        insideNodeModules: resolveNodeModules
+      };
+    }
+    if (isRedirectToDir(redirect.to)) {
+      let newDir = redirect.to.dir;
+      if (!newDir.endsWith('/')) {
+        newDir = newDir + '/';
+      }
+      return {target: `${newDir}${redirect.pathToFile}`, insideNodeModules: false}
+    }
+    throw new Error(`Invalid redirect for path: ${pathRelativeToRoot}`);
+  }
+
+  private static resolveNodeModuleFile(npmRedirect: RedirectToNodeModule, pathToFile: string): string {
+    if(npmRedirect.files && npmRedirect.files[pathToFile]) {
+      pathToFile = npmRedirect.files[pathToFile];
+    }
+    return `${npmRedirect.npm_module}/${pathToFile}`;
+  }
+
+  private findRedirect(relativePathToRoot: string): RedirectForFile | undefined {
+    if(!relativePathToRoot.startsWith('/')) {
+      relativePathToRoot = '/' + relativePathToRoot;
+    }
+    for(const redirect of this.redirects) {
+      const normalizedFrom = redirect.from + (redirect.from.endsWith('/') ? '' : '/');
+      if(relativePathToRoot.startsWith(normalizedFrom)) {
+        return {
+          to: redirect.to,
+          pathToFile: relativePathToRoot.substring(normalizedFrom.length)
+        };
+      }
+    }
+    return undefined;
+  }
+}
diff --git a/tools/node_tools/rollup-runner.js b/tools/node_tools/rollup-runner.js
new file mode 100644
index 0000000..a8a09f9
--- /dev/null
+++ b/tools/node_tools/rollup-runner.js
@@ -0,0 +1,51 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file is a part of workaround for
+// https://github.com/bazelbuild/rules_nodejs/issues/1575
+// rollup_bundle doesn't run when it is placed
+// in nested node_modules folder and bazel runs with
+// --spawn_strategy local flag. The error happens
+// because npm_package_bin generates incorrect path to
+// rollup bin.
+// But npm_package_bin works correctly if entry point
+// is an ordinary .js file which depends on some node module.
+// This script is a proxy script, which run rollup bin from
+// node_modules folder and pass all parameters to it.
+const {spawnSync} = require('child_process');
+const path = require('path');
+
+const nodePath = process.argv[0];
+const scriptArgs = process.argv.slice(2);
+const nodeArgs = process.execArgv;
+
+const pathToBin = require.resolve("rollup/dist/bin/rollup");
+
+const options = {
+  stdio: 'inherit'
+};
+
+const spawnResult = spawnSync(nodePath, [...nodeArgs, pathToBin, ...scriptArgs], options);
+
+if(spawnResult.status !== null) {
+  process.exit(spawnResult.status);
+}
+
+if(spawnResult.error) {
+  console.error(spawnResult.error);
+  process.exit(1);
+}
diff --git a/tools/node_tools/utils/BUILD b/tools/node_tools/utils/BUILD
new file mode 100644
index 0000000..fca3c12
--- /dev/null
+++ b/tools/node_tools/utils/BUILD
@@ -0,0 +1,13 @@
+load("@npm_bazel_typescript//:index.bzl", "ts_library")
+
+package(default_visibility = ["//visibility:public"])
+
+ts_library(
+    name = "utils",
+    srcs = glob(["*.ts"]),
+    node_modules = "@tools_npm//:node_modules",
+    tsconfig = "tsconfig.json",
+    deps = [
+        "@tools_npm//:node_modules",
+    ],
+)
diff --git a/tools/node_tools/utils/command-line.ts b/tools/node_tools/utils/command-line.ts
new file mode 100644
index 0000000..48e3c87
--- /dev/null
+++ b/tools/node_tools/utils/command-line.ts
@@ -0,0 +1,22 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as fs from "fs";
+
+export function readMultilineParamFile(path: string): string[] {
+  return fs.readFileSync(path, {encoding: 'utf-8'}).split(/\r?\n/).filter(f => f.length > 0);
+}
diff --git a/tools/node_tools/utils/common.ts b/tools/node_tools/utils/common.ts
new file mode 100644
index 0000000..9b976ba
--- /dev/null
+++ b/tools/node_tools/utils/common.ts
@@ -0,0 +1,25 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export function fail(message: string): never {
+  console.error(message);
+  process.exit(1);
+}
+
+export function unexpectedSwitchValue(_: never): never {
+  fail(`Internal error - unexpected switch value`);
+}
diff --git a/tools/node_tools/utils/file-utils.ts b/tools/node_tools/utils/file-utils.ts
new file mode 100644
index 0000000..d8e1581
--- /dev/null
+++ b/tools/node_tools/utils/file-utils.ts
@@ -0,0 +1,56 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as path from "path";
+import * as fs from "fs";
+
+export type FilePath = string & {__filePath: undefined};
+export type TypedFilePath<T> = FilePath & { __type?: T, __typedFilePath: undefined };
+
+export enum FileType{
+  HtmlSrc,
+  HtmlTarget,
+  JsSrc,
+  JsTarget
+}
+
+export type HtmlSrcFilePath = TypedFilePath<FileType.HtmlSrc>;
+export type HtmlTargetFilePath = TypedFilePath<FileType.HtmlTarget>;
+export type JsSrcFilePath = TypedFilePath<FileType.JsSrc>;
+export type JsTargetFilePath = TypedFilePath<FileType.JsTarget>;
+
+export class FileUtils {
+  public static ensureDirExistsForFile(filePath: string) {
+    const dirName = path.dirname(filePath);
+    if (!fs.existsSync(dirName)) {
+      fs.mkdirSync(dirName, {recursive: true, mode: 0o744});
+    }
+  }
+
+  public static writeContent(file: string, content: string) {
+    if(fs.existsSync(file) && fs.lstatSync(file).isSymbolicLink()) {
+      throw new Error(`Output file '${file}' is a symbolic link. Inplace update for links are not supported.`);
+    }
+    FileUtils.ensureDirExistsForFile(file);
+    fs.writeFileSync(file, content);
+  }
+
+  public static copyFile(src: string, dst: string) {
+    FileUtils.ensureDirExistsForFile(dst);
+    fs.copyFileSync(src, dst);
+  }
+}
diff --git a/tools/node_tools/utils/tsconfig.json b/tools/node_tools/utils/tsconfig.json
new file mode 100644
index 0000000..34ffb2f
--- /dev/null
+++ b/tools/node_tools/utils/tsconfig.json
@@ -0,0 +1,12 @@
+{
+  "compilerOptions": {
+    "target": "es6",
+    "module": "commonjs",
+    "allowSyntheticDefaultImports": true,
+    "esModuleInterop": true,
+    "strict": true,
+    "moduleResolution": "node",
+    "outDir": "out"
+  },
+  "include": ["*.ts"]
+}
diff --git a/tools/node_tools/utils/web-site-utils.ts b/tools/node_tools/utils/web-site-utils.ts
new file mode 100644
index 0000000..eb30ce4
--- /dev/null
+++ b/tools/node_tools/utils/web-site-utils.ts
@@ -0,0 +1,102 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as path from "path";
+import {fail} from "./common";
+import {FilePath, HtmlSrcFilePath, JsSrcFilePath} from "./file-utils";
+
+export type AbsoluteWebPath = string & { __absoluteWebPath: undefined };
+export type RelativeWebPath = string & { __relativeWebPath: undefined };
+export type WebPath = AbsoluteWebPath | RelativeWebPath;
+
+export type NodeModuleImportPath = string & {__nodeModuleImportPath: undefined};
+
+export type AbsoluteTypedWebPath<T> = AbsoluteWebPath & { __type?: T, __absoluteTypedFilePath: undefined };
+export type RelativeTypedWebPath<T> = RelativeWebPath & { __type?: T, __relativeTypedFilePath: undefined };
+
+export type TypedWebPath<T> = AbsoluteTypedWebPath<T> | RelativeTypedWebPath<T>;
+
+export function isAbsoluteWebPath(path: WebPath): path is AbsoluteWebPath {
+  return path.startsWith("/");
+}
+
+export function isRelativeWebPath(path: WebPath): path is RelativeWebPath {
+  return !isAbsoluteWebPath(path);
+}
+const node_modules_path_prefix = "/node_modules/";
+
+/** Contains method to resolve absolute and relative paths */
+export class SrcWebSite {
+  public constructor(private readonly webSiteRoot: FilePath) {
+  }
+
+  public getFilePath(webPath: AbsoluteWebPath): FilePath {
+    return path.resolve(this.webSiteRoot, webPath.substr(1)) as FilePath;
+  }
+
+  public getAbsoluteWebPathToFile(file: FilePath): AbsoluteWebPath {
+    const relativePath = path.relative(this.webSiteRoot, file);
+    if(relativePath.startsWith("..")) {
+      fail(`The file ${file} is not under webSiteRoot`);
+    }
+    return ("/" + relativePath) as AbsoluteWebPath;
+  }
+
+  public static resolveReference(from: AbsoluteWebPath, to: WebPath): AbsoluteWebPath {
+    return isAbsoluteWebPath(to) ? to : path.resolve(from, to) as AbsoluteWebPath;
+  }
+
+  public static getRelativePath(from: AbsoluteWebPath, to: AbsoluteWebPath): RelativeWebPath {
+    return path.relative(from, to) as RelativeWebPath;
+  }
+
+  public resolveHtmlImport(from: HtmlSrcFilePath, href: string): HtmlSrcFilePath {
+    return this.resolveReferenceToAbsPath(from, href) as HtmlSrcFilePath;
+
+  }
+  public resolveScriptSrc(from: HtmlSrcFilePath, src: string): JsSrcFilePath {
+    return this.resolveReferenceToAbsPath(from, src) as JsSrcFilePath;
+  }
+
+  public isNodeModuleReference(ref: string): boolean {
+    return ref.startsWith(node_modules_path_prefix);
+  }
+
+  public getNodeModuleImport(ref: string): NodeModuleImportPath {
+    if(!this.isNodeModuleReference(ref)) {
+      fail(`Internal error! ${ref} must be inside node modules`);
+    }
+    return ref.substr(node_modules_path_prefix.length) as NodeModuleImportPath;
+  }
+
+  private resolveReferenceToAbsPath(from: string, ref: string): string {
+    if(ref.startsWith("/")) {
+      const relativeToRootPath = ref.substr(1);
+      return path.resolve(this.webSiteRoot, relativeToRootPath);
+    }
+    return path.resolve(path.dirname(from), ref);
+  }
+}
+
+export function getRelativeImport(from: FilePath, ref: FilePath) {
+  const relativePath = path.relative(path.dirname(from), ref);
+  if(relativePath.startsWith("../")) {
+    return relativePath
+  } else {
+    return "./" + relativePath;
+  }
+}
diff --git a/tools/node_tools/yarn.lock b/tools/node_tools/yarn.lock
new file mode 100644
index 0000000..eedea4a
--- /dev/null
+++ b/tools/node_tools/yarn.lock
@@ -0,0 +1,8508 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@babel/code-frame@^7.5.5", "@babel/code-frame@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e"
+  integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==
+  dependencies:
+    "@babel/highlight" "^7.8.3"
+
+"@babel/core@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.3.tgz#30b0ebb4dd1585de6923a0b4d179e0b9f5d82941"
+  integrity sha512-4XFkf8AwyrEG7Ziu3L2L0Cv+WyY47Tcsp70JFmpftbAA1K7YL/sgE9jh9HyNj08Y/U50ItUchpN0w6HxAoX1rA==
+  dependencies:
+    "@babel/code-frame" "^7.8.3"
+    "@babel/generator" "^7.8.3"
+    "@babel/helpers" "^7.8.3"
+    "@babel/parser" "^7.8.3"
+    "@babel/template" "^7.8.3"
+    "@babel/traverse" "^7.8.3"
+    "@babel/types" "^7.8.3"
+    convert-source-map "^1.7.0"
+    debug "^4.1.0"
+    gensync "^1.0.0-beta.1"
+    json5 "^2.1.0"
+    lodash "^4.17.13"
+    resolve "^1.3.2"
+    semver "^5.4.1"
+    source-map "^0.5.0"
+
+"@babel/generator@^7.0.0-beta.42", "@babel/generator@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.3.tgz#0e22c005b0a94c1c74eafe19ef78ce53a4d45c03"
+  integrity sha512-WjoPk8hRpDRqqzRpvaR8/gDUPkrnOOeuT2m8cNICJtZH6mwaCo3v0OKMI7Y6SM1pBtyijnLtAL0HDi41pf41ug==
+  dependencies:
+    "@babel/types" "^7.8.3"
+    jsesc "^2.5.1"
+    lodash "^4.17.13"
+    source-map "^0.5.0"
+
+"@babel/helper-annotate-as-pure@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz#60bc0bc657f63a0924ff9a4b4a0b24a13cf4deee"
+  integrity sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw==
+  dependencies:
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-builder-binary-assignment-operator-visitor@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.8.3.tgz#c84097a427a061ac56a1c30ebf54b7b22d241503"
+  integrity sha512-5eFOm2SyFPK4Rh3XMMRDjN7lBH0orh3ss0g3rTYZnBQ+r6YPj7lgDyCvPphynHvUrobJmeMignBr6Acw9mAPlw==
+  dependencies:
+    "@babel/helper-explode-assignable-expression" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-call-delegate@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.8.3.tgz#de82619898aa605d409c42be6ffb8d7204579692"
+  integrity sha512-6Q05px0Eb+N4/GTyKPPvnkig7Lylw+QzihMpws9iiZQv7ZImf84ZsZpQH7QoWN4n4tm81SnSzPgHw2qtO0Zf3A==
+  dependencies:
+    "@babel/helper-hoist-variables" "^7.8.3"
+    "@babel/traverse" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-create-regexp-features-plugin@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.3.tgz#c774268c95ec07ee92476a3862b75cc2839beb79"
+  integrity sha512-Gcsm1OHCUr9o9TcJln57xhWHtdXbA2pgQ58S0Lxlks0WMGNXuki4+GLfX0p+L2ZkINUGZvfkz8rzoqJQSthI+Q==
+  dependencies:
+    "@babel/helper-regex" "^7.8.3"
+    regexpu-core "^4.6.0"
+
+"@babel/helper-define-map@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz#a0655cad5451c3760b726eba875f1cd8faa02c15"
+  integrity sha512-PoeBYtxoZGtct3md6xZOCWPcKuMuk3IHhgxsRRNtnNShebf4C8YonTSblsK4tvDbm+eJAw2HAPOfCr+Q/YRG/g==
+  dependencies:
+    "@babel/helper-function-name" "^7.8.3"
+    "@babel/types" "^7.8.3"
+    lodash "^4.17.13"
+
+"@babel/helper-explode-assignable-expression@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.8.3.tgz#a728dc5b4e89e30fc2dfc7d04fa28a930653f982"
+  integrity sha512-N+8eW86/Kj147bO9G2uclsg5pwfs/fqqY5rwgIL7eTBklgXjcOJ3btzS5iM6AitJcftnY7pm2lGsrJVYLGjzIw==
+  dependencies:
+    "@babel/traverse" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-function-name@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz#eeeb665a01b1f11068e9fb86ad56a1cb1a824cca"
+  integrity sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==
+  dependencies:
+    "@babel/helper-get-function-arity" "^7.8.3"
+    "@babel/template" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-get-function-arity@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5"
+  integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==
+  dependencies:
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-hoist-variables@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.8.3.tgz#1dbe9b6b55d78c9b4183fc8cdc6e30ceb83b7134"
+  integrity sha512-ky1JLOjcDUtSc+xkt0xhYff7Z6ILTAHKmZLHPxAhOP0Nd77O+3nCsd6uSVYur6nJnCI029CrNbYlc0LoPfAPQg==
+  dependencies:
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-member-expression-to-functions@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz#659b710498ea6c1d9907e0c73f206eee7dadc24c"
+  integrity sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA==
+  dependencies:
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-module-imports@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz#7fe39589b39c016331b6b8c3f441e8f0b1419498"
+  integrity sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg==
+  dependencies:
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-module-transforms@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.8.3.tgz#d305e35d02bee720fbc2c3c3623aa0c316c01590"
+  integrity sha512-C7NG6B7vfBa/pwCOshpMbOYUmrYQDfCpVL/JCRu0ek8B5p8kue1+BCXpg2vOYs7w5ACB9GTOBYQ5U6NwrMg+3Q==
+  dependencies:
+    "@babel/helper-module-imports" "^7.8.3"
+    "@babel/helper-simple-access" "^7.8.3"
+    "@babel/helper-split-export-declaration" "^7.8.3"
+    "@babel/template" "^7.8.3"
+    "@babel/types" "^7.8.3"
+    lodash "^4.17.13"
+
+"@babel/helper-optimise-call-expression@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9"
+  integrity sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ==
+  dependencies:
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz#9ea293be19babc0f52ff8ca88b34c3611b208670"
+  integrity sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==
+
+"@babel/helper-regex@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.8.3.tgz#139772607d51b93f23effe72105b319d2a4c6965"
+  integrity sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ==
+  dependencies:
+    lodash "^4.17.13"
+
+"@babel/helper-remap-async-to-generator@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.8.3.tgz#273c600d8b9bf5006142c1e35887d555c12edd86"
+  integrity sha512-kgwDmw4fCg7AVgS4DukQR/roGp+jP+XluJE5hsRZwxCYGg+Rv9wSGErDWhlI90FODdYfd4xG4AQRiMDjjN0GzA==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.8.3"
+    "@babel/helper-wrap-function" "^7.8.3"
+    "@babel/template" "^7.8.3"
+    "@babel/traverse" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-replace-supers@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.3.tgz#91192d25f6abbcd41da8a989d4492574fb1530bc"
+  integrity sha512-xOUssL6ho41U81etpLoT2RTdvdus4VfHamCuAm4AHxGr+0it5fnwoVdwUJ7GFEqCsQYzJUhcbsN9wB9apcYKFA==
+  dependencies:
+    "@babel/helper-member-expression-to-functions" "^7.8.3"
+    "@babel/helper-optimise-call-expression" "^7.8.3"
+    "@babel/traverse" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-simple-access@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz#7f8109928b4dab4654076986af575231deb639ae"
+  integrity sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw==
+  dependencies:
+    "@babel/template" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-split-export-declaration@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9"
+  integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==
+  dependencies:
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-wrap-function@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz#9dbdb2bb55ef14aaa01fe8c99b629bd5352d8610"
+  integrity sha512-LACJrbUET9cQDzb6kG7EeD7+7doC3JNvUgTEQOx2qaO1fKlzE/Bf05qs9w1oXQMmXlPO65lC3Tq9S6gZpTErEQ==
+  dependencies:
+    "@babel/helper-function-name" "^7.8.3"
+    "@babel/template" "^7.8.3"
+    "@babel/traverse" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/helpers@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.8.3.tgz#382fbb0382ce7c4ce905945ab9641d688336ce85"
+  integrity sha512-LmU3q9Pah/XyZU89QvBgGt+BCsTPoQa+73RxAQh8fb8qkDyIfeQnmgs+hvzhTCKTzqOyk7JTkS3MS1S8Mq5yrQ==
+  dependencies:
+    "@babel/template" "^7.8.3"
+    "@babel/traverse" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/highlight@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.8.3.tgz#28f173d04223eaaa59bc1d439a3836e6d1265797"
+  integrity sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==
+  dependencies:
+    chalk "^2.0.0"
+    esutils "^2.0.2"
+    js-tokens "^4.0.0"
+
+"@babel/parser@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.3.tgz#790874091d2001c9be6ec426c2eed47bc7679081"
+  integrity sha512-/V72F4Yp/qmHaTALizEm9Gf2eQHV3QyTL3K0cNfijwnMnb1L+LDlAubb/ZnSdGAVzVSWakujHYs1I26x66sMeQ==
+
+"@babel/plugin-external-helpers@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-external-helpers/-/plugin-external-helpers-7.8.3.tgz#5a94164d9af393b2820a3cdc407e28ebf237de4b"
+  integrity sha512-mx0WXDDiIl5DwzMtzWGRSPugXi9BxROS05GQrhLNbEamhBiicgn994ibwkyiBH+6png7bm/yA7AUsvHyCXi4Vw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-proposal-async-generator-functions@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz#bad329c670b382589721b27540c7d288601c6e6f"
+  integrity sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+    "@babel/helper-remap-async-to-generator" "^7.8.3"
+    "@babel/plugin-syntax-async-generators" "^7.8.0"
+
+"@babel/plugin-proposal-object-rest-spread@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.8.3.tgz#eb5ae366118ddca67bed583b53d7554cad9951bb"
+  integrity sha512-8qvuPwU/xxUCt78HocNlv0mXXo0wdh9VT1R04WU8HGOfaOob26pF+9P5/lYjN/q7DHOX1bvX60hnhOvuQUJdbA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+    "@babel/plugin-syntax-object-rest-spread" "^7.8.0"
+
+"@babel/plugin-syntax-async-generators@^7.0.0", "@babel/plugin-syntax-async-generators@^7.8.0":
+  version "7.8.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
+  integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-dynamic-import@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3"
+  integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-import-meta@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.8.3.tgz#230afff79d3ccc215b5944b438e4e266daf3d84d"
+  integrity sha512-vYiGd4wQ9gx0Lngb7+bPCwQXGK/PR6FeTIJ+TIOlq+OfOKG/kCAOO2+IBac3oMM9qV7/fU76hfcqxUaLKZf1hQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.8.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871"
+  integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-transform-arrow-functions@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz#82776c2ed0cd9e1a49956daeb896024c9473b8b6"
+  integrity sha512-0MRF+KC8EqH4dbuITCWwPSzsyO3HIWWlm30v8BbbpOrS1B++isGxPnnuq/IZvOX5J2D/p7DQalQm+/2PnlKGxg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-async-to-generator@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz#4308fad0d9409d71eafb9b1a6ee35f9d64b64086"
+  integrity sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ==
+  dependencies:
+    "@babel/helper-module-imports" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+    "@babel/helper-remap-async-to-generator" "^7.8.3"
+
+"@babel/plugin-transform-block-scoped-functions@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz#437eec5b799b5852072084b3ae5ef66e8349e8a3"
+  integrity sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-block-scoping@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz#97d35dab66857a437c166358b91d09050c868f3a"
+  integrity sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+    lodash "^4.17.13"
+
+"@babel/plugin-transform-classes@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.3.tgz#46fd7a9d2bb9ea89ce88720477979fe0d71b21b8"
+  integrity sha512-SjT0cwFJ+7Rbr1vQsvphAHwUHvSUPmMjMU/0P59G8U2HLFqSa082JO7zkbDNWs9kH/IUqpHI6xWNesGf8haF1w==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.8.3"
+    "@babel/helper-define-map" "^7.8.3"
+    "@babel/helper-function-name" "^7.8.3"
+    "@babel/helper-optimise-call-expression" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+    "@babel/helper-replace-supers" "^7.8.3"
+    "@babel/helper-split-export-declaration" "^7.8.3"
+    globals "^11.1.0"
+
+"@babel/plugin-transform-computed-properties@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz#96d0d28b7f7ce4eb5b120bb2e0e943343c86f81b"
+  integrity sha512-O5hiIpSyOGdrQZRQ2ccwtTVkgUDBBiCuK//4RJ6UfePllUTCENOzKxfh6ulckXKc0DixTFLCfb2HVkNA7aDpzA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-destructuring@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.3.tgz#20ddfbd9e4676906b1056ee60af88590cc7aaa0b"
+  integrity sha512-H4X646nCkiEcHZUZaRkhE2XVsoz0J/1x3VVujnn96pSoGCtKPA99ZZA+va+gK+92Zycd6OBKCD8tDb/731bhgQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-duplicate-keys@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.8.3.tgz#8d12df309aa537f272899c565ea1768e286e21f1"
+  integrity sha512-s8dHiBUbcbSgipS4SMFuWGqCvyge5V2ZeAWzR6INTVC3Ltjig/Vw1G2Gztv0vU/hRG9X8IvKvYdoksnUfgXOEQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-exponentiation-operator@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.8.3.tgz#581a6d7f56970e06bf51560cd64f5e947b70d7b7"
+  integrity sha512-zwIpuIymb3ACcInbksHaNcR12S++0MDLKkiqXHl3AzpgdKlFNhog+z/K0+TGW+b0w5pgTq4H6IwV/WhxbGYSjQ==
+  dependencies:
+    "@babel/helper-builder-binary-assignment-operator-visitor" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-for-of@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.3.tgz#15f17bce2fc95c7d59a24b299e83e81cedc22e18"
+  integrity sha512-ZjXznLNTxhpf4Q5q3x1NsngzGA38t9naWH8Gt+0qYZEJAcvPI9waSStSh56u19Ofjr7QmD0wUsQ8hw8s/p1VnA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-function-name@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz#279373cb27322aaad67c2683e776dfc47196ed8b"
+  integrity sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ==
+  dependencies:
+    "@babel/helper-function-name" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-instanceof@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-instanceof/-/plugin-transform-instanceof-7.8.3.tgz#a44d7d71590da36be7429573300618aefd784c3d"
+  integrity sha512-c/jB6Ebe2u17hxo+rce6PDgbkuHyfcJOleqgHYttnvMrCsxVwUnYsMq7GhxXekzUQsv9IImhv6YICKihpen+Ag==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-literals@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz#aef239823d91994ec7b68e55193525d76dbd5dc1"
+  integrity sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-modules-amd@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.8.3.tgz#65606d44616b50225e76f5578f33c568a0b876a5"
+  integrity sha512-MadJiU3rLKclzT5kBH4yxdry96odTUwuqrZM+GllFI/VhxfPz+k9MshJM+MwhfkCdxxclSbSBbUGciBngR+kEQ==
+  dependencies:
+    "@babel/helper-module-transforms" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+    babel-plugin-dynamic-import-node "^2.3.0"
+
+"@babel/plugin-transform-object-super@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz#ebb6a1e7a86ffa96858bd6ac0102d65944261725"
+  integrity sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+    "@babel/helper-replace-supers" "^7.8.3"
+
+"@babel/plugin-transform-parameters@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.3.tgz#7890576a13b17325d8b7d44cb37f21dc3bbdda59"
+  integrity sha512-/pqngtGb54JwMBZ6S/D3XYylQDFtGjWrnoCF4gXZOUpFV/ujbxnoNGNvDGu6doFWRPBveE72qTx/RRU44j5I/Q==
+  dependencies:
+    "@babel/helper-call-delegate" "^7.8.3"
+    "@babel/helper-get-function-arity" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-regenerator@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.3.tgz#b31031e8059c07495bf23614c97f3d9698bc6ec8"
+  integrity sha512-qt/kcur/FxrQrzFR432FGZznkVAjiyFtCOANjkAKwCbt465L6ZCiUQh2oMYGU3Wo8LRFJxNDFwWn106S5wVUNA==
+  dependencies:
+    regenerator-transform "^0.14.0"
+
+"@babel/plugin-transform-shorthand-properties@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz#28545216e023a832d4d3a1185ed492bcfeac08c8"
+  integrity sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-spread@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.8.3.tgz#9c8ffe8170fdfb88b114ecb920b82fb6e95fe5e8"
+  integrity sha512-CkuTU9mbmAoFOI1tklFWYYbzX5qCIZVXPVy0jpXgGwkplCndQAa58s2jr66fTeQnA64bDox0HL4U56CFYoyC7g==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-sticky-regex@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz#be7a1290f81dae767475452199e1f76d6175b100"
+  integrity sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+    "@babel/helper-regex" "^7.8.3"
+
+"@babel/plugin-transform-template-literals@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.8.3.tgz#7bfa4732b455ea6a43130adc0ba767ec0e402a80"
+  integrity sha512-820QBtykIQOLFT8NZOcTRJ1UNuztIELe4p9DCgvj4NK+PwluSJ49we7s9FB1HIGNIYT7wFUJ0ar2QpCDj0escQ==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-typeof-symbol@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.3.tgz#5cffb216fb25c8c64ba6bf5f76ce49d3ab079f4d"
+  integrity sha512-3TrkKd4LPqm4jHs6nPtSDI/SV9Cm5PRJkHLUgTcqRQQTMAZ44ZaAdDZJtvWFSaRcvT0a1rTmJ5ZA5tDKjleF3g==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-unicode-regex@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz#0cef36e3ba73e5c57273effb182f46b91a1ecaad"
+  integrity sha512-+ufgJjYdmWfSQ+6NS9VGUR2ns8cjJjYbrbi11mZBTaWm+Fui/ncTLFF28Ei1okavY+xkojGr1eJxNsWYeA5aZw==
+  dependencies:
+    "@babel/helper-create-regexp-features-plugin" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/template@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.3.tgz#e02ad04fe262a657809327f578056ca15fd4d1b8"
+  integrity sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==
+  dependencies:
+    "@babel/code-frame" "^7.8.3"
+    "@babel/parser" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/traverse@^7.0.0", "@babel/traverse@^7.0.0-beta.42", "@babel/traverse@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.3.tgz#a826215b011c9b4f73f3a893afbc05151358bf9a"
+  integrity sha512-we+a2lti+eEImHmEXp7bM9cTxGzxPmBiVJlLVD+FuuQMeeO7RaDbutbgeheDkw+Xe3mCfJHnGOWLswT74m2IPg==
+  dependencies:
+    "@babel/code-frame" "^7.8.3"
+    "@babel/generator" "^7.8.3"
+    "@babel/helper-function-name" "^7.8.3"
+    "@babel/helper-split-export-declaration" "^7.8.3"
+    "@babel/parser" "^7.8.3"
+    "@babel/types" "^7.8.3"
+    debug "^4.1.0"
+    globals "^11.1.0"
+    lodash "^4.17.13"
+
+"@babel/types@^7.0.0-beta.42", "@babel/types@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.3.tgz#5a383dffa5416db1b73dedffd311ffd0788fb31c"
+  integrity sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==
+  dependencies:
+    esutils "^2.0.2"
+    lodash "^4.17.13"
+    to-fast-properties "^2.0.0"
+
+"@bazel/rollup@^0.41.0":
+  version "0.41.0"
+  resolved "https://registry.yarnpkg.com/@bazel/rollup/-/rollup-0.41.0.tgz#8dfaccc239f3efbae1c816b0ce2aeb6069d23582"
+  integrity sha512-M+ybGfcxTXnAS1QiaijLEfUznNYLA0cqeGXnYHSRrOhq2U7yesfavxbBtfLSKtg32ktmlHts5te8Zg82BS4DPQ==
+
+"@bazel/typescript@^1.0.1":
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-1.1.0.tgz#b57ac6c6d627577f394a60fb540fbbdf53bcff0d"
+  integrity sha512-QnTdb6rwZUR+KfUuAdyazpkA7BOvrWRe7tkPDdyIZHJdBPYdpJW+AapnFSfxvXEIP0Nwesl5KP6Saau0GPiBLg==
+  dependencies:
+    protobufjs "6.8.8"
+    semver "5.6.0"
+    source-map-support "0.5.9"
+    tsutils "2.27.2"
+
+"@mrmlnc/readdir-enhanced@^2.2.1":
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
+  integrity sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==
+  dependencies:
+    call-me-maybe "^1.0.1"
+    glob-to-regexp "^0.3.0"
+
+"@nodelib/fs.stat@^1.1.2":
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b"
+  integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==
+
+"@octokit/auth-token@^2.4.0":
+  version "2.4.0"
+  resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.4.0.tgz#b64178975218b99e4dfe948253f0673cbbb59d9f"
+  integrity sha512-eoOVMjILna7FVQf96iWc3+ZtE/ZT6y8ob8ZzcqKY1ibSQCnu4O/B7pJvzMx5cyZ/RjAff6DAdEb0O0Cjcxidkg==
+  dependencies:
+    "@octokit/types" "^2.0.0"
+
+"@octokit/endpoint@^5.5.0":
+  version "5.5.1"
+  resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-5.5.1.tgz#2eea81e110ca754ff2de11c79154ccab4ae16b3f"
+  integrity sha512-nBFhRUb5YzVTCX/iAK1MgQ4uWo89Gu0TH00qQHoYRCsE12dWcG1OiLd7v2EIo2+tpUKPMOQ62QFy9hy9Vg2ULg==
+  dependencies:
+    "@octokit/types" "^2.0.0"
+    is-plain-object "^3.0.0"
+    universal-user-agent "^4.0.0"
+
+"@octokit/request-error@^1.0.1", "@octokit/request-error@^1.0.2":
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-1.2.0.tgz#a64d2a9d7a13555570cd79722de4a4d76371baaa"
+  integrity sha512-DNBhROBYjjV/I9n7A8kVkmQNkqFAMem90dSxqvPq57e2hBr7mNTX98y3R2zDpqMQHVRpBDjsvsfIGgBzy+4PAg==
+  dependencies:
+    "@octokit/types" "^2.0.0"
+    deprecation "^2.0.0"
+    once "^1.4.0"
+
+"@octokit/request@^5.2.0":
+  version "5.3.1"
+  resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.3.1.tgz#3a1ace45e6f88b1be4749c5da963b3a3b4a2f120"
+  integrity sha512-5/X0AL1ZgoU32fAepTfEoggFinO3rxsMLtzhlUX+RctLrusn/CApJuGFCd0v7GMFhF+8UiCsTTfsu7Fh1HnEJg==
+  dependencies:
+    "@octokit/endpoint" "^5.5.0"
+    "@octokit/request-error" "^1.0.1"
+    "@octokit/types" "^2.0.0"
+    deprecation "^2.0.0"
+    is-plain-object "^3.0.0"
+    node-fetch "^2.3.0"
+    once "^1.4.0"
+    universal-user-agent "^4.0.0"
+
+"@octokit/rest@^16.2.0":
+  version "16.38.3"
+  resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-16.38.3.tgz#d5d200f88962392f71e048e12833ea36f4e0d192"
+  integrity sha512-Ui5W4Gzv0YHe9P3KDZAuU/BkRrT88PCuuATfWBMBf4fux4nB8th8LlyVAVnHKba1s/q4umci+sNHzoFYFujPEg==
+  dependencies:
+    "@octokit/auth-token" "^2.4.0"
+    "@octokit/request" "^5.2.0"
+    "@octokit/request-error" "^1.0.2"
+    atob-lite "^2.0.0"
+    before-after-hook "^2.0.0"
+    btoa-lite "^1.0.0"
+    deprecation "^2.0.0"
+    lodash.get "^4.4.2"
+    lodash.set "^4.3.2"
+    lodash.uniq "^4.5.0"
+    octokit-pagination-methods "^1.1.0"
+    once "^1.4.0"
+    universal-user-agent "^4.0.0"
+
+"@octokit/types@^2.0.0":
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/@octokit/types/-/types-2.1.1.tgz#77e80d1b663c5f1f829e5377b728fa3c4fe5a97d"
+  integrity sha512-89LOYH+d/vsbDX785NOfLxTW88GjNd0lWRz1DVPVsZgg9Yett5O+3MOvwo7iHgvUwbFz0mf/yPIjBkUbs4kxoQ==
+  dependencies:
+    "@types/node" ">= 8"
+
+"@polymer/esm-amd-loader@^1.0.0":
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/@polymer/esm-amd-loader/-/esm-amd-loader-1.0.4.tgz#4e77f2f59b29b01e0ad02aa83d33716cddc5f9f9"
+  integrity sha512-h+hqYkL+tQV/y2ESD5gFXMl5z4cC+XY1jTlBeGSBaTcj3VbB5OBEScbvRXm63NcEbBneQQYbHfBAXAkF9i9wIA==
+
+"@polymer/sinonjs@^1.14.1":
+  version "1.17.1"
+  resolved "https://registry.yarnpkg.com/@polymer/sinonjs/-/sinonjs-1.17.1.tgz#e47d3785b7d0e8c29feb97f7e924b0fc597e2e9b"
+  integrity sha512-/U8F/cOTrbF2iVVYgINYmvKbtbexs+89Q3v8AaHADRYabTg7aOZGOb0RyWpOI+sUJt04kj63U4FwMhzW5r4wZA==
+
+"@polymer/test-fixture@^0.0.3":
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/@polymer/test-fixture/-/test-fixture-0.0.3.tgz#4443752697d4d9293bbc412ea0b5e4d341f149d9"
+  integrity sha1-REN1JpfU2Sk7vEEuoLXk00HxSdk=
+
+"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf"
+  integrity sha1-m4sMxmPWaafY9vXQiToU00jzD78=
+
+"@protobufjs/base64@^1.1.2":
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735"
+  integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==
+
+"@protobufjs/codegen@^2.0.4":
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb"
+  integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==
+
+"@protobufjs/eventemitter@^1.1.0":
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70"
+  integrity sha1-NVy8mLr61ZePntCV85diHx0Ga3A=
+
+"@protobufjs/fetch@^1.1.0":
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45"
+  integrity sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=
+  dependencies:
+    "@protobufjs/aspromise" "^1.1.1"
+    "@protobufjs/inquire" "^1.1.0"
+
+"@protobufjs/float@^1.0.2":
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1"
+  integrity sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=
+
+"@protobufjs/inquire@^1.1.0":
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089"
+  integrity sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=
+
+"@protobufjs/path@^1.1.2":
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d"
+  integrity sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=
+
+"@protobufjs/pool@^1.1.0":
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54"
+  integrity sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=
+
+"@protobufjs/utf8@^1.1.0":
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
+  integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=
+
+"@types/babel-generator@^6.25.1":
+  version "6.25.3"
+  resolved "https://registry.yarnpkg.com/@types/babel-generator/-/babel-generator-6.25.3.tgz#8f06caa12d0595a0538560abe771966d77d29286"
+  integrity sha512-pGgnuxVddKcYIc+VJkRDop7gxLhqclNKBdlsm/5Vp8d+37pQkkDK7fef8d9YYImRzw9xcojEPc18pUYnbxmjqA==
+  dependencies:
+    "@types/babel-types" "*"
+
+"@types/babel-traverse@^6.25.2", "@types/babel-traverse@^6.25.3":
+  version "6.25.5"
+  resolved "https://registry.yarnpkg.com/@types/babel-traverse/-/babel-traverse-6.25.5.tgz#6d293cf7523e48b524faa7b86dc3c488191484e5"
+  integrity sha512-WrMbwmu+MWf8FiUMbmVOGkc7bHPzndUafn1CivMaBHthBBoo0VNIcYk1KV71UovYguhsNOwf3UF5oRmkkGOU3w==
+  dependencies:
+    "@types/babel-types" "*"
+
+"@types/babel-types@*":
+  version "7.0.7"
+  resolved "https://registry.yarnpkg.com/@types/babel-types/-/babel-types-7.0.7.tgz#667eb1640e8039436028055737d2b9986ee336e3"
+  integrity sha512-dBtBbrc+qTHy1WdfHYjBwRln4+LWqASWakLHsWHR2NWHIFkv4W3O070IGoGLEBrJBvct3r0L1BUPuvURi7kYUQ==
+
+"@types/babel-types@^6.25.1":
+  version "6.25.2"
+  resolved "https://registry.yarnpkg.com/@types/babel-types/-/babel-types-6.25.2.tgz#5c57f45973e4f13742dbc5273dd84cffe7373a9e"
+  integrity sha512-+3bMuktcY4a70a0KZc8aPJlEOArPuAKQYHU5ErjkOqGJdx8xuEEVK6nWogqigBOJ8nKPxRpyCUDTCPmZ3bUxGA==
+
+"@types/babylon@^6.16.2":
+  version "6.16.5"
+  resolved "https://registry.yarnpkg.com/@types/babylon/-/babylon-6.16.5.tgz#1c5641db69eb8cdf378edd25b4be7754beeb48b4"
+  integrity sha512-xH2e58elpj1X4ynnKp9qSnWlsRTIs6n3tgLGNfwAGHwePw0mulHQllV34n0T25uYSu1k0hRKkWXF890B1yS47w==
+  dependencies:
+    "@types/babel-types" "*"
+
+"@types/bluebird@*":
+  version "3.5.29"
+  resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.29.tgz#7cd933c902c4fc83046517a1bef973886d00bdb6"
+  integrity sha512-kmVtnxTuUuhCET669irqQmPAez4KFnFVKvpleVRyfC3g+SHD1hIkFZcWLim9BVcwUBLO59o8VZE4yGCmTif8Yw==
+
+"@types/body-parser@*":
+  version "1.17.1"
+  resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.17.1.tgz#18fcf61768fb5c30ccc508c21d6fd2e8b3bf7897"
+  integrity sha512-RoX2EZjMiFMjZh9lmYrwgoP9RTpAjSHiJxdp4oidAQVO02T7HER3xj9UKue5534ULWeqVEkujhWcyvUce+d68w==
+  dependencies:
+    "@types/connect" "*"
+    "@types/node" "*"
+
+"@types/chai-subset@^1.3.0":
+  version "1.3.3"
+  resolved "https://registry.yarnpkg.com/@types/chai-subset/-/chai-subset-1.3.3.tgz#97893814e92abd2c534de422cb377e0e0bdaac94"
+  integrity sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==
+  dependencies:
+    "@types/chai" "*"
+
+"@types/chai@*":
+  version "4.2.7"
+  resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.7.tgz#1c8c25cbf6e59ffa7d6b9652c78e547d9a41692d"
+  integrity sha512-luq8meHGYwvky0O7u0eQZdA7B4Wd9owUCqvbw2m3XCrCU8mplYOujMBbvyS547AxJkC+pGnd0Cm15eNxEUNU8g==
+
+"@types/chalk@^0.4.30":
+  version "0.4.31"
+  resolved "https://registry.yarnpkg.com/@types/chalk/-/chalk-0.4.31.tgz#a31d74241a6b1edbb973cf36d97a2896834a51f9"
+  integrity sha1-ox10JBprHtu5c8822XooloNKUfk=
+
+"@types/chalk@^2.2.0":
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/@types/chalk/-/chalk-2.2.0.tgz#b7f6e446f4511029ee8e3f43075fb5b73fbaa0ba"
+  integrity sha512-1zzPV9FDe1I/WHhRkf9SNgqtRJWZqrBWgu7JGveuHmmyR9CnAPCie2N/x+iHrgnpYBIcCJWHBoMRv2TRWktsvw==
+  dependencies:
+    chalk "*"
+
+"@types/clean-css@*":
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/@types/clean-css/-/clean-css-4.2.1.tgz#cb0134241ec5e6ede1b5344bc829668fd9871a8d"
+  integrity sha512-A1HQhQ0hkvqqByJMgg+Wiv9p9XdoYEzuwm11SVo1mX2/4PSdhjcrUlilJQoqLscIheC51t1D5g+EFWCXZ2VTQQ==
+  dependencies:
+    "@types/node" "*"
+
+"@types/clone@^0.1.29", "@types/clone@^0.1.30":
+  version "0.1.30"
+  resolved "https://registry.yarnpkg.com/@types/clone/-/clone-0.1.30.tgz#e7365648c1b42136a59c7d5040637b3b5c83b614"
+  integrity sha1-5zZWSMG0ITalnH1QQGN7O1yDthQ=
+
+"@types/color-name@^1.1.1":
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
+  integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==
+
+"@types/compression@^0.0.33":
+  version "0.0.33"
+  resolved "https://registry.yarnpkg.com/@types/compression/-/compression-0.0.33.tgz#95dc733a2339aa846381d7f1377792d2553dc27d"
+  integrity sha1-ldxzOiM5qoRjgdfxN3eS0lU9wn0=
+  dependencies:
+    "@types/express" "*"
+
+"@types/connect@*":
+  version "3.4.33"
+  resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.33.tgz#31610c901eca573b8713c3330abc6e6b9f588546"
+  integrity sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==
+  dependencies:
+    "@types/node" "*"
+
+"@types/content-type@^1.1.0":
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/@types/content-type/-/content-type-1.1.3.tgz#3688bd77fc12f935548eef102a4e34c512b03a07"
+  integrity sha512-pv8VcFrZ3fN93L4rTNIbbUzdkzjEyVMp5mPVjsFfOYTDOZMZiZ8P1dhu+kEv3faYyKzZgLlSvnyQNFg+p/v5ug==
+
+"@types/cssbeautify@^0.3.1":
+  version "0.3.1"
+  resolved "https://registry.yarnpkg.com/@types/cssbeautify/-/cssbeautify-0.3.1.tgz#8e0bee8f7decb952250da0caebe05e30591c17ef"
+  integrity sha1-jgvuj33suVIlDaDK6+BeMFkcF+8=
+
+"@types/del@^3.0.0":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@types/del/-/del-3.0.1.tgz#4712da8c119873cbbf533ad8dbf1baac5940ac5d"
+  integrity sha512-y6qRq6raBuu965clKgx6FHuiPu3oHdtmzMPXi8Uahsjdq1L6DL5fS/aY5/s71YwM7k6K1QIWvem5vNwlnNGIkQ==
+  dependencies:
+    "@types/glob" "*"
+
+"@types/doctrine@^0.0.1":
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/@types/doctrine/-/doctrine-0.0.1.tgz#b999f2d9f7b43cabe0a1a2f39bc203bc7dcada9d"
+  integrity sha1-uZny2fe0PKvgoaLzm8IDvH3K2p0=
+
+"@types/escape-html@0.0.20":
+  version "0.0.20"
+  resolved "https://registry.yarnpkg.com/@types/escape-html/-/escape-html-0.0.20.tgz#cae698714dd61ebee5ab3f2aeb9a34ba1011735a"
+  integrity sha512-6dhZJLbA7aOwkYB2GDGdIqJ20wmHnkDzaxV9PJXe7O02I2dSFTERzRB6JrX6cWKaS+VqhhY7cQUMCbO5kloFUw==
+
+"@types/estree@*":
+  version "0.0.42"
+  resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.42.tgz#8d0c1f480339efedb3e46070e22dd63e0430dd11"
+  integrity sha512-K1DPVvnBCPxzD+G51/cxVIoc2X8uUVl1zpJeE6iKcgHMj4+tbat5Xu4TjV7v2QSDbIeAfLi2hIk+u2+s0MlpUQ==
+
+"@types/events@*":
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
+  integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==
+
+"@types/expect@^1.20.4":
+  version "1.20.4"
+  resolved "https://registry.yarnpkg.com/@types/expect/-/expect-1.20.4.tgz#8288e51737bf7e3ab5d7c77bfa695883745264e5"
+  integrity sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg==
+
+"@types/express-serve-static-core@*":
+  version "4.17.2"
+  resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.2.tgz#f6f41fa35d42e79dbf6610eccbb2637e6008a0cf"
+  integrity sha512-El9yMpctM6tORDAiBwZVLMcxoTMcqqRO9dVyYcn7ycLWbvR8klrDn8CAOwRfZujZtWD7yS/mshTdz43jMOejbg==
+  dependencies:
+    "@types/node" "*"
+    "@types/range-parser" "*"
+
+"@types/express@*", "@types/express@^4.0.30", "@types/express@^4.0.36":
+  version "4.17.2"
+  resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.2.tgz#a0fb7a23d8855bac31bc01d5a58cadd9b2173e6c"
+  integrity sha512-5mHFNyavtLoJmnusB8OKJ5bshSzw+qkMIBAobLrIM48HJvunFva9mOa6aBwh64lBFyNwBbs0xiEFuj4eU/NjCA==
+  dependencies:
+    "@types/body-parser" "*"
+    "@types/express-serve-static-core" "*"
+    "@types/serve-static" "*"
+
+"@types/fast-levenshtein@0.0.1":
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/@types/fast-levenshtein/-/fast-levenshtein-0.0.1.tgz#3a3615cf173645c8fca58d051e4e32824e4bd286"
+  integrity sha1-OjYVzxc2Rcj8pY0FHk4ygk5L0oY=
+
+"@types/findup-sync@^0.3.29":
+  version "0.3.30"
+  resolved "https://registry.yarnpkg.com/@types/findup-sync/-/findup-sync-0.3.30.tgz#8ab7bdbd6ba7cbf4f33b6596fde6fff1129c738d"
+  integrity sha512-Dpt1x3rhz6t8BMTS4vziTVos8VLkF4RngIxMBCSE6w0STmnVEEaoe3w+BG5xHyZXshye9lyZE99lpBDoLGY8eA==
+  dependencies:
+    "@types/minimatch" "*"
+
+"@types/form-data@*":
+  version "2.5.0"
+  resolved "https://registry.yarnpkg.com/@types/form-data/-/form-data-2.5.0.tgz#5025f7433016f923348434c40006d9a797c1b0e8"
+  integrity sha512-23/wYiuckYYtFpL+4RPWiWmRQH2BjFuqCUi2+N3amB1a1Drv+i/byTrGvlLwRVLFNAZbwpbQ7JvTK+VCAPMbcg==
+  dependencies:
+    form-data "*"
+
+"@types/freeport@^1.0.19":
+  version "1.0.21"
+  resolved "https://registry.yarnpkg.com/@types/freeport/-/freeport-1.0.21.tgz#73f6543ed67d3ca3fff97b985591598b7092066f"
+  integrity sha1-c/ZUPtZ9PKP/+XuYVZFZi3CSBm8=
+
+"@types/glob-stream@*":
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/@types/glob-stream/-/glob-stream-6.1.0.tgz#7ede8a33e59140534f8d8adfb8ac9edfb31897bc"
+  integrity sha512-RHv6ZQjcTncXo3thYZrsbAVwoy4vSKosSWhuhuQxLOTv74OJuFQxXkmUuZCr3q9uNBEVCvIzmZL/FeRNbHZGUg==
+  dependencies:
+    "@types/glob" "*"
+    "@types/node" "*"
+
+"@types/glob@*":
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575"
+  integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==
+  dependencies:
+    "@types/events" "*"
+    "@types/minimatch" "*"
+    "@types/node" "*"
+
+"@types/globby@^6.1.0":
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/@types/globby/-/globby-6.1.0.tgz#7c25b975512a89effea2a656ca8cf6db7fb29d11"
+  integrity sha512-j3XSDNoK4LO5T+ZviQD6PqfEjm07QFEacOTbJR3hnLWuWX0ZMLJl9oRPgj1PyrfGbXhfHFkksC9QZ9HFltJyrw==
+  dependencies:
+    "@types/glob" "*"
+
+"@types/gulp-if@0.0.33":
+  version "0.0.33"
+  resolved "https://registry.yarnpkg.com/@types/gulp-if/-/gulp-if-0.0.33.tgz#edece22b7925d9a6db5f9c8c0d7882aa776fb678"
+  integrity sha512-J5lzff21X7r1x/4hSzn02GgIUEyjCqYIXZ9GgGBLhbsD3RiBdqwnkFWgF16/0jO5rcVZ52Zp+6MQMQdvIsWuKg==
+  dependencies:
+    "@types/node" "*"
+    "@types/vinyl" "*"
+
+"@types/html-minifier@^3.5.1":
+  version "3.5.3"
+  resolved "https://registry.yarnpkg.com/@types/html-minifier/-/html-minifier-3.5.3.tgz#5276845138db2cebc54c789e0aaf87621a21e84f"
+  integrity sha512-j1P/4PcWVVCPEy5lofcHnQ6BtXz9tHGiFPWzqm7TtGuWZEfCHEP446HlkSNc9fQgNJaJZ6ewPtp2aaFla/Uerg==
+  dependencies:
+    "@types/clean-css" "*"
+    "@types/relateurl" "*"
+    "@types/uglify-js" "*"
+
+"@types/inquirer@*":
+  version "6.5.0"
+  resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-6.5.0.tgz#b83b0bf30b88b8be7246d40e51d32fe9d10e09be"
+  integrity sha512-rjaYQ9b9y/VFGOpqBEXRavc3jh0a+e6evAbI31tMda8VlPaSy0AZJfXsvmIe3wklc7W6C3zCSfleuMXR7NOyXw==
+  dependencies:
+    "@types/through" "*"
+    rxjs "^6.4.0"
+
+"@types/inquirer@0.0.32":
+  version "0.0.32"
+  resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-0.0.32.tgz#a4a08e83741c500a7c3c8e7776014f7f8a65870d"
+  integrity sha1-pKCOg3QcUAp8PI53dgFPf4plhw0=
+  dependencies:
+    "@types/rx" "*"
+    "@types/through" "*"
+
+"@types/is-windows@^0.2.0":
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/@types/is-windows/-/is-windows-0.2.0.tgz#6f24ee48731d31168ea510610d6dd15e5fc9c6ff"
+  integrity sha1-byTuSHMdMRaOpRBhDW3RXl/Jxv8=
+
+"@types/launchpad@^0.6.0":
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/@types/launchpad/-/launchpad-0.6.0.tgz#37296109b7f277f6e6c5fd7e0c0706bc918fbb51"
+  integrity sha1-NylhCbfyd/bmxf1+DAcGvJGPu1E=
+
+"@types/long@^4.0.0":
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9"
+  integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==
+
+"@types/merge-stream@^1.0.28":
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/@types/merge-stream/-/merge-stream-1.1.2.tgz#a880ff66b1fbbb5eef4958d015c5947a9334dbb1"
+  integrity sha512-7faLmaE99g/yX0Y9pF1neh2IUqOf/fXMOWCVzsXjqI1EJ91lrgXmaBKf6bRWM164lLyiHxHt6t/ZO/cIzq61XA==
+  dependencies:
+    "@types/node" "*"
+
+"@types/mime@*", "@types/mime@^2.0.0":
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d"
+  integrity sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==
+
+"@types/minimatch@*", "@types/minimatch@^3.0.1":
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
+  integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
+
+"@types/mz@0.0.29":
+  version "0.0.29"
+  resolved "https://registry.yarnpkg.com/@types/mz/-/mz-0.0.29.tgz#bc24728c649973f1c7851e9033f9ce525668c27b"
+  integrity sha1-vCRyjGSZc/HHhR6QM/nOUlZowns=
+  dependencies:
+    "@types/bluebird" "*"
+    "@types/node" "*"
+
+"@types/mz@0.0.31", "@types/mz@^0.0.31":
+  version "0.0.31"
+  resolved "https://registry.yarnpkg.com/@types/mz/-/mz-0.0.31.tgz#a4d80c082fefe71e40a7c0f07d1e6555bbbc7b52"
+  integrity sha1-pNgMCC/v5x5Ap8DwfR5lVbu8e1I=
+  dependencies:
+    "@types/node" "*"
+
+"@types/node@*", "@types/node@>= 8":
+  version "13.5.0"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-13.5.0.tgz#4e498dbf355795a611a87ae5ef811a8660d42662"
+  integrity sha512-Onhn+z72D2O2Pb2ql2xukJ55rglumsVo1H6Fmyi8mlU9SvKdBk/pUSUAiBY/d9bAOF7VVWajX3sths/+g6ZiAQ==
+
+"@types/node@6.0.*":
+  version "6.0.118"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.118.tgz#8014a9b1dee0b72b4d7cd142563f1af21241c3a2"
+  integrity sha512-N33cKXGSqhOYaPiT4xUGsYlPPDwFtQM/6QxJxuMXA/7BcySW+lkn2yigWP7vfs4daiL/7NJNU6DMCqg5N4B+xQ==
+
+"@types/node@^10.1.0", "@types/node@^10.17.12":
+  version "10.17.13"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.13.tgz#ccebcdb990bd6139cd16e84c39dc2fb1023ca90c"
+  integrity sha512-pMCcqU2zT4TjqYFrWtYHKal7Sl30Ims6ulZ4UFXxI4xbtQqK/qqKwkDoBFCfooRqqmRu9vY3xaJRwxSh673aYg==
+
+"@types/node@^4.0.30":
+  version "4.9.4"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-4.9.4.tgz#75ef91733afaa856b01e12da6ecf48aa9d5e221f"
+  integrity sha512-nKoiCZ87x6+fs26bNHjy07AQt6f46nFEitGH0P9JmWbY6tEyum6LLfLf7SIsKFh4DnBWsyUM2gYhaQAt+aA0Sw==
+
+"@types/opn@^3.0.28":
+  version "3.0.28"
+  resolved "https://registry.yarnpkg.com/@types/opn/-/opn-3.0.28.tgz#097d0d1c9b5749573a5d96df132387bb6d02118a"
+  integrity sha1-CX0NHJtXSVc6XZbfEyOHu20CEYo=
+  dependencies:
+    "@types/node" "*"
+
+"@types/parse5@^0.0.31":
+  version "0.0.31"
+  resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-0.0.31.tgz#e827a493a443b156e1b582a2e4c3bdc0040f2ee7"
+  integrity sha1-6Cekk6RDsVbhtYKi5MO9wAQPLuc=
+  dependencies:
+    "@types/node" "6.0.*"
+
+"@types/parse5@^2.2.34":
+  version "2.2.34"
+  resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-2.2.34.tgz#e3870a10e82735a720f62d71dcd183ba78ef3a9d"
+  integrity sha1-44cKEOgnNacg9i1x3NGDunjvOp0=
+  dependencies:
+    "@types/node" "*"
+
+"@types/parse5@^4.0.0":
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-4.0.0.tgz#26dd73df171a69be517395d294c7af2ae0cd2579"
+  integrity sha512-OaBwNFk6dO8gbdfWut41VYiD5Fmj3Yi24cr/oGCXFXCjT2fteSQx2l3kx/phuQvBte/F54ajN2uDQF5MRwupGw==
+  dependencies:
+    "@types/node" "*"
+
+"@types/path-is-inside@^1.0.0":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@types/path-is-inside/-/path-is-inside-1.0.0.tgz#02d6ff38975d684bdec96204494baf9f29f0e17f"
+  integrity sha512-hfnXRGugz+McgX2jxyy5qz9sB21LRzlGn24zlwN2KEgoPtEvjzNRrLtUkOOebPDPZl3Rq7ywKxYvylVcEZDnEw==
+
+"@types/pem@^1.8.1":
+  version "1.9.5"
+  resolved "https://registry.yarnpkg.com/@types/pem/-/pem-1.9.5.tgz#cd5548b5e0acb4b41a9e21067e9fcd8c57089c99"
+  integrity sha512-C0txxEw8B7DCoD85Ko7SEvzUogNd5VDJ5/YBG8XUcacsOGqxr5Oo4g3OUAfdEDUbhXanwUoVh/ZkMFw77FGPQQ==
+  dependencies:
+    "@types/node" "*"
+
+"@types/range-parser@*":
+  version "1.2.3"
+  resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c"
+  integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==
+
+"@types/relateurl@*":
+  version "0.2.28"
+  resolved "https://registry.yarnpkg.com/@types/relateurl/-/relateurl-0.2.28.tgz#6bda7db8653fa62643f5ee69e9f69c11a392e3a6"
+  integrity sha1-a9p9uGU/piZD9e5p6facEaOS46Y=
+
+"@types/request@2.0.3":
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/@types/request/-/request-2.0.3.tgz#bdf0fba9488c822f77e97de3dd8fe357b2fb8c06"
+  integrity sha512-cIvnyFRARxwE4OHpCyYue7H+SxaKFPpeleRCHJicft8QhyTNbVYsMwjvEzEPqG06D2LGHZ+sN5lXc8+bTu6D8A==
+  dependencies:
+    "@types/form-data" "*"
+    "@types/node" "*"
+
+"@types/resolve@0.0.4":
+  version "0.0.4"
+  resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.4.tgz#9b586d65a947dea88c4bc24da0b905fe9520a0d5"
+  integrity sha1-m1htZalH3qiMS8JNoLkF/pUgoNU=
+  dependencies:
+    "@types/node" "*"
+
+"@types/resolve@0.0.6":
+  version "0.0.6"
+  resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.6.tgz#0bd2f236c2e1cebb98b79885df57edd71a8d770e"
+  integrity sha512-g+Rg8uMWY76oYTyaL+m7ZcblqF/oj7pE6uEUyACluJx4zcop1Lk14qQiocdEkEVMDFm6DmKpxJhsER+ZuTwG3g==
+  dependencies:
+    "@types/node" "*"
+
+"@types/resolve@0.0.7":
+  version "0.0.7"
+  resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.7.tgz#b299c13be8d712b1b502fb14a084252acef84f4d"
+  integrity sha512-GPewdjkb0Q76o459qgp6pBLzJj/bD3oveS2kfLhIkZ9U3t3AFKtl5DlFB6lGTw0iZmcmxoGC8lpLW3NNJKrN9A==
+  dependencies:
+    "@types/node" "*"
+
+"@types/resolve@0.0.8":
+  version "0.0.8"
+  resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194"
+  integrity sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==
+  dependencies:
+    "@types/node" "*"
+
+"@types/rimraf@^0.0.28":
+  version "0.0.28"
+  resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-0.0.28.tgz#5562519bc7963caca8abf7f128cae3b594d41d06"
+  integrity sha1-VWJRm8eWPKyoq/fxKMrjtZTUHQY=
+
+"@types/rx-core-binding@*":
+  version "4.0.4"
+  resolved "https://registry.yarnpkg.com/@types/rx-core-binding/-/rx-core-binding-4.0.4.tgz#d969d32f15a62b89e2862c17b3ee78fe329818d3"
+  integrity sha512-5pkfxnC4w810LqBPUwP5bg7SFR/USwhMSaAeZQQbEHeBp57pjKXRlXmqpMrLJB4y1oglR/c2502853uN0I+DAQ==
+  dependencies:
+    "@types/rx-core" "*"
+
+"@types/rx-core@*":
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/@types/rx-core/-/rx-core-4.0.3.tgz#0b3354b1238cedbe2b74f6326f139dbc7a591d60"
+  integrity sha1-CzNUsSOM7b4rdPYybxOdvHpZHWA=
+
+"@types/rx-lite-aggregates@*":
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/@types/rx-lite-aggregates/-/rx-lite-aggregates-4.0.3.tgz#6efb2b7f3d5f07183a1cb2bd4b1371d7073384c2"
+  integrity sha512-MAGDAHy8cRatm94FDduhJF+iNS5//jrZ/PIfm+QYw9OCeDgbymFHChM8YVIvN2zArwsRftKgE33QfRWvQk4DPg==
+  dependencies:
+    "@types/rx-lite" "*"
+
+"@types/rx-lite-async@*":
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/@types/rx-lite-async/-/rx-lite-async-4.0.2.tgz#27fbf0caeff029f41e2d2aae638b05e91ceb600c"
+  integrity sha512-vTEv5o8l6702ZwfAM5aOeVDfUwBSDOs+ARoGmWAKQ6LOInQ8J4/zjM7ov12fuTpktUKdMQjkeCp07Vd73mPkxw==
+  dependencies:
+    "@types/rx-lite" "*"
+
+"@types/rx-lite-backpressure@*":
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/@types/rx-lite-backpressure/-/rx-lite-backpressure-4.0.3.tgz#05abb19bdf87cc740196c355e5d0b37bb50b5d56"
+  integrity sha512-Y6aIeQCtNban5XSAF4B8dffhIKu6aAy/TXFlScHzSxh6ivfQBQw6UjxyEJxIOt3IT49YkS+siuayM2H/Q0cmgA==
+  dependencies:
+    "@types/rx-lite" "*"
+
+"@types/rx-lite-coincidence@*":
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/@types/rx-lite-coincidence/-/rx-lite-coincidence-4.0.3.tgz#80bd69acc4054a15cdc1638e2dc8843498cd85c0"
+  integrity sha512-1VNJqzE9gALUyMGypDXZZXzR0Tt7LC9DdAZQ3Ou/Q0MubNU35agVUNXKGHKpNTba+fr8GdIdkC26bRDqtCQBeQ==
+  dependencies:
+    "@types/rx-lite" "*"
+
+"@types/rx-lite-experimental@*":
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/@types/rx-lite-experimental/-/rx-lite-experimental-4.0.1.tgz#c532f5cbdf3f2c15da16ded8930d1b2984023cbd"
+  integrity sha1-xTL1y98/LBXaFt7Ykw0bKYQCPL0=
+  dependencies:
+    "@types/rx-lite" "*"
+
+"@types/rx-lite-joinpatterns@*":
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/@types/rx-lite-joinpatterns/-/rx-lite-joinpatterns-4.0.1.tgz#f70fe370518a8432f29158cc92ffb56b4e4afc3e"
+  integrity sha1-9w/jcFGKhDLykVjMkv+1a05K/D4=
+  dependencies:
+    "@types/rx-lite" "*"
+
+"@types/rx-lite-testing@*":
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/@types/rx-lite-testing/-/rx-lite-testing-4.0.1.tgz#21b19d11f4dfd6ffef5a9d1648e9c8879bfe21e9"
+  integrity sha1-IbGdEfTf1v/vWp0WSOnIh5v+Iek=
+  dependencies:
+    "@types/rx-lite-virtualtime" "*"
+
+"@types/rx-lite-time@*":
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/@types/rx-lite-time/-/rx-lite-time-4.0.3.tgz#0eda65474570237598f3448b845d2696f2dbb1c4"
+  integrity sha512-ukO5sPKDRwCGWRZRqPlaAU0SKVxmWwSjiOrLhoQDoWxZWg6vyB9XLEZViKOzIO6LnTIQBlk4UylYV0rnhJLxQw==
+  dependencies:
+    "@types/rx-lite" "*"
+
+"@types/rx-lite-virtualtime@*":
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/@types/rx-lite-virtualtime/-/rx-lite-virtualtime-4.0.3.tgz#4b30cacd0fe2e53af29f04f7438584c7d3959537"
+  integrity sha512-3uC6sGmjpOKatZSVHI2xB1+dedgml669ZRvqxy+WqmGJDVusOdyxcKfyzjW0P3/GrCiN4nmRkLVMhPwHCc5QLg==
+  dependencies:
+    "@types/rx-lite" "*"
+
+"@types/rx-lite@*":
+  version "4.0.6"
+  resolved "https://registry.yarnpkg.com/@types/rx-lite/-/rx-lite-4.0.6.tgz#3c02921c4244074234f26b772241bcc20c18c253"
+  integrity sha512-oYiDrFIcor9zDm0VDUca1UbROiMYBxMLMaM6qzz4ADAfOmA9r1dYEcAFH+2fsPI5BCCjPvV9pWC3X3flbrvs7w==
+  dependencies:
+    "@types/rx-core" "*"
+    "@types/rx-core-binding" "*"
+
+"@types/rx@*":
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/@types/rx/-/rx-4.1.1.tgz#598fc94a56baed975f194574e0f572fd8e627a48"
+  integrity sha1-WY/JSla67ZdfGUV04PVy/Y5iekg=
+  dependencies:
+    "@types/rx-core" "*"
+    "@types/rx-core-binding" "*"
+    "@types/rx-lite" "*"
+    "@types/rx-lite-aggregates" "*"
+    "@types/rx-lite-async" "*"
+    "@types/rx-lite-backpressure" "*"
+    "@types/rx-lite-coincidence" "*"
+    "@types/rx-lite-experimental" "*"
+    "@types/rx-lite-joinpatterns" "*"
+    "@types/rx-lite-testing" "*"
+    "@types/rx-lite-time" "*"
+    "@types/rx-lite-virtualtime" "*"
+
+"@types/semver@^5.3.30":
+  version "5.5.0"
+  resolved "https://registry.yarnpkg.com/@types/semver/-/semver-5.5.0.tgz#146c2a29ee7d3bae4bf2fcb274636e264c813c45"
+  integrity sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ==
+
+"@types/serve-static@*", "@types/serve-static@^1.7.31":
+  version "1.13.3"
+  resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.3.tgz#eb7e1c41c4468272557e897e9171ded5e2ded9d1"
+  integrity sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g==
+  dependencies:
+    "@types/express-serve-static-core" "*"
+    "@types/mime" "*"
+
+"@types/spdy@^3.4.1":
+  version "3.4.4"
+  resolved "https://registry.yarnpkg.com/@types/spdy/-/spdy-3.4.4.tgz#3282fd4ad8c4603aa49f7017dd520a08a345b2bc"
+  integrity sha512-N9LBlbVRRYq6HgYpPkqQc3a9HJ/iEtVZToW6xlTtJiMhmRJ7jJdV7TaZQJw/Ve/1ePUsQiCTDc4JMuzzag94GA==
+  dependencies:
+    "@types/node" "*"
+
+"@types/temp@^0.8.28":
+  version "0.8.34"
+  resolved "https://registry.yarnpkg.com/@types/temp/-/temp-0.8.34.tgz#03e4b3cb67cbb48c425bbf54b12230fef85540ac"
+  integrity sha512-oLa9c5LHXgS6UimpEVp08De7QvZ+Dfu5bMQuWyMhf92Z26Q10ubEMOWy9OEfUdzW7Y/sDWVHmUaLFtmnX/2j0w==
+  dependencies:
+    "@types/node" "*"
+
+"@types/through@*":
+  version "0.0.30"
+  resolved "https://registry.yarnpkg.com/@types/through/-/through-0.0.30.tgz#e0e42ce77e897bd6aead6f6ea62aeb135b8a3895"
+  integrity sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg==
+  dependencies:
+    "@types/node" "*"
+
+"@types/ua-parser-js@^0.7.31":
+  version "0.7.33"
+  resolved "https://registry.yarnpkg.com/@types/ua-parser-js/-/ua-parser-js-0.7.33.tgz#4a92089511574e12928a7cb6b99a01831acd1dd7"
+  integrity sha512-ngUKcHnytUodUCL7C6EZ+lVXUjTMQb+9p/e1JjV5tN9TVzS98lHozWEFRPY1QcCdwFeMsmVWfZ3DPPT/udCyIw==
+
+"@types/uglify-js@*":
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.0.4.tgz#96beae23df6f561862a830b4288a49e86baac082"
+  integrity sha512-SudIN9TRJ+v8g5pTG8RRCqfqTMNqgWCKKd3vtynhGzkIIjxaicNAMuY5TRadJ6tzDu3Dotf3ngaMILtmOdmWEQ==
+  dependencies:
+    source-map "^0.6.1"
+
+"@types/update-notifier@^1.0.0":
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/@types/update-notifier/-/update-notifier-1.0.3.tgz#3c7ee1921af6f16149cdcaef356baf57d7a0b806"
+  integrity sha512-BLStNhP2DFF7funARwTcoD6tetRte8NK3Sc59mn7GNALCN975jOlKX3dGvsFxXr/HwQMxxCuRn9IWB3WQ7odHQ==
+
+"@types/uuid@^3.4.3":
+  version "3.4.6"
+  resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-3.4.6.tgz#d2c4c48eb85a757bf2927f75f939942d521e3016"
+  integrity sha512-cCdlC/1kGEZdEglzOieLDYBxHsvEOIg7kp/2FYyVR9Pxakq+Qf/inL3RKQ+PA8gOlI/NnL+fXmQH12nwcGzsHw==
+  dependencies:
+    "@types/node" "*"
+
+"@types/vinyl-fs@0.0.28":
+  version "0.0.28"
+  resolved "https://registry.yarnpkg.com/@types/vinyl-fs/-/vinyl-fs-0.0.28.tgz#4663017bc802c6570eae4f3409fd5cabf97cbfde"
+  integrity sha1-RmMBe8gCxlcOrk80Cf1cq/l8v94=
+  dependencies:
+    "@types/glob-stream" "*"
+    "@types/node" "*"
+    "@types/vinyl" "*"
+
+"@types/vinyl-fs@^2.4.8":
+  version "2.4.11"
+  resolved "https://registry.yarnpkg.com/@types/vinyl-fs/-/vinyl-fs-2.4.11.tgz#b98119b8bb2494141eaf649b09fbfeb311161206"
+  integrity sha512-2OzQSfIr9CqqWMGqmcERE6Hnd2KY3eBVtFaulVo3sJghplUcaeMdL9ZjEiljcQQeHjheWY9RlNmumjIAvsBNaA==
+  dependencies:
+    "@types/glob-stream" "*"
+    "@types/node" "*"
+    "@types/vinyl" "*"
+
+"@types/vinyl@*", "@types/vinyl@^2.0.0":
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/@types/vinyl/-/vinyl-2.0.4.tgz#9a7a8071c8d14d3a95d41ebe7135babe4ad5995a"
+  integrity sha512-2o6a2ixaVI2EbwBPg1QYLGQoHK56p/8X/sGfKbFC8N6sY9lfjsMf/GprtkQkSya0D4uRiutRZ2BWj7k3JvLsAQ==
+  dependencies:
+    "@types/expect" "^1.20.4"
+    "@types/node" "*"
+
+"@types/whatwg-url@^6.4.0":
+  version "6.4.0"
+  resolved "https://registry.yarnpkg.com/@types/whatwg-url/-/whatwg-url-6.4.0.tgz#1e59b8c64bc0dbdf66d037cf8449d1c3d5270237"
+  integrity sha512-tonhlcbQ2eho09am6RHnHOgvtDfDYINd5rgxD+2YSkKENooVCFsWizJz139MQW/PV8FfClyKrNe9ZbdHrSCxGg==
+  dependencies:
+    "@types/node" "*"
+
+"@types/which@^1.3.1":
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/@types/which/-/which-1.3.2.tgz#9c246fc0c93ded311c8512df2891fb41f6227fdf"
+  integrity sha512-8oDqyLC7eD4HM307boe2QWKyuzdzWBj56xI/imSl2cpL+U3tCMaTAkMJ4ee5JBZ/FsOJlvRGeIShiZDAl1qERA==
+
+"@types/yeoman-generator@^2.0.3":
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/@types/yeoman-generator/-/yeoman-generator-2.0.3.tgz#f4b161ee354078b526e0901a5a5f87d4f8e085f6"
+  integrity sha512-vch2UFd6k7DdfWEv/alRwZIRXQoxZNUDpfLOK24+005dzE1HVnwSWfETF3WxJnWlsOcH87wU4uzldAE/7F/6Lw==
+  dependencies:
+    "@types/events" "*"
+    "@types/inquirer" "*"
+
+"@webcomponents/webcomponentsjs@^1.0.7":
+  version "1.3.3"
+  resolved "https://registry.yarnpkg.com/@webcomponents/webcomponentsjs/-/webcomponentsjs-1.3.3.tgz#5bb82a0d3210c836bd4623e13a4a93145cb9dc27"
+  integrity sha512-eLH04VBMpuZGzBIhOnUjECcQPEPcmfhWEijW9u1B5I+2PPYdWf3vWUExdDxu4Y3GljRSTCOlWnGtS9tpzmXMyQ==
+
+accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7:
+  version "1.3.7"
+  resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
+  integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
+  dependencies:
+    mime-types "~2.1.24"
+    negotiator "0.6.2"
+
+accessibility-developer-tools@^2.12.0:
+  version "2.12.0"
+  resolved "https://registry.yarnpkg.com/accessibility-developer-tools/-/accessibility-developer-tools-2.12.0.tgz#3da0cce9d6ec6373964b84f35db7cfc3df7ab514"
+  integrity sha1-PaDM6dbsY3OWS4TzXbfPw996tRQ=
+
+acorn-jsx@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b"
+  integrity sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=
+  dependencies:
+    acorn "^3.0.4"
+
+acorn@^3.0.4:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
+  integrity sha1-ReN/s56No/JbruP/U2niu18iAXo=
+
+acorn@^5.5.0:
+  version "5.7.3"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279"
+  integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==
+
+acorn@^7.1.0:
+  version "7.1.0"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.0.tgz#949d36f2c292535da602283586c2477c57eb2d6c"
+  integrity sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==
+
+adm-zip@~0.4.3:
+  version "0.4.13"
+  resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.13.tgz#597e2f8cc3672151e1307d3e95cddbc75672314a"
+  integrity sha512-fERNJX8sOXfel6qCBCMPvZLzENBEhZTzKqg6vrOW5pvoEaQuJhRU4ndTAh6lHOxn1I6jnz2NHra56ZODM751uw==
+
+after@0.8.2:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
+  integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=
+
+agent-base@^4.3.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee"
+  integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==
+  dependencies:
+    es6-promisify "^5.0.0"
+
+ajv@^6.5.5:
+  version "6.11.0"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.11.0.tgz#c3607cbc8ae392d8a5a536f25b21f8e5f3f87fe9"
+  integrity sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA==
+  dependencies:
+    fast-deep-equal "^3.1.1"
+    fast-json-stable-stringify "^2.0.0"
+    json-schema-traverse "^0.4.1"
+    uri-js "^4.2.2"
+
+ansi-align@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-1.1.0.tgz#2f0c1658829739add5ebb15e6b0c6e3423f016ba"
+  integrity sha1-LwwWWIKXOa3V67FeawxuNCPwFro=
+  dependencies:
+    string-width "^1.0.1"
+
+ansi-align@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f"
+  integrity sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=
+  dependencies:
+    string-width "^2.0.0"
+
+ansi-escape-sequences@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/ansi-escape-sequences/-/ansi-escape-sequences-3.0.0.tgz#1c18394b6af9b76ff9a63509fa497669fd2ce53e"
+  integrity sha1-HBg5S2r5t2/5pjUJ+kl2af0s5T4=
+  dependencies:
+    array-back "^1.0.3"
+
+ansi-escapes@^1.1.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
+  integrity sha1-06ioOzGapneTZisT52HHkRQiMG4=
+
+ansi-escapes@^3.2.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b"
+  integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==
+
+ansi-regex@^2.0.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+  integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
+
+ansi-regex@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
+  integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
+
+ansi-regex@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
+  integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
+
+ansi-styles@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
+  integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=
+
+ansi-styles@^3.2.1:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+  integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
+  dependencies:
+    color-convert "^1.9.0"
+
+ansi-styles@^4.1.0:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359"
+  integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==
+  dependencies:
+    "@types/color-name" "^1.1.1"
+    color-convert "^2.0.1"
+
+ansi-styles@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178"
+  integrity sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=
+
+any-promise@^1.0.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
+  integrity sha1-q8av7tzqUugJzcA3au0845Y10X8=
+
+anymatch@^1.3.0:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a"
+  integrity sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==
+  dependencies:
+    micromatch "^2.1.5"
+    normalize-path "^2.0.0"
+
+append-field@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56"
+  integrity sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=
+
+archiver-utils@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2"
+  integrity sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==
+  dependencies:
+    glob "^7.1.4"
+    graceful-fs "^4.2.0"
+    lazystream "^1.0.0"
+    lodash.defaults "^4.2.0"
+    lodash.difference "^4.5.0"
+    lodash.flatten "^4.4.0"
+    lodash.isplainobject "^4.0.6"
+    lodash.union "^4.6.0"
+    normalize-path "^3.0.0"
+    readable-stream "^2.0.0"
+
+archiver@^3.0.0:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/archiver/-/archiver-3.1.1.tgz#9db7819d4daf60aec10fe86b16cb9258ced66ea0"
+  integrity sha512-5Hxxcig7gw5Jod/8Gq0OneVgLYET+oNHcxgWItq4TbhOzRLKNAFUb9edAftiMKXvXfCB0vbGrJdZDNq0dWMsxg==
+  dependencies:
+    archiver-utils "^2.1.0"
+    async "^2.6.3"
+    buffer-crc32 "^0.2.1"
+    glob "^7.1.4"
+    readable-stream "^3.4.0"
+    tar-stream "^2.1.0"
+    zip-stream "^2.1.2"
+
+arr-diff@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
+  integrity sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=
+  dependencies:
+    arr-flatten "^1.0.1"
+
+arr-diff@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
+  integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=
+
+arr-flatten@^1.0.1, arr-flatten@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1"
+  integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==
+
+arr-union@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
+  integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=
+
+array-back@^1.0.3, array-back@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/array-back/-/array-back-1.0.4.tgz#644ba7f095f7ffcf7c43b5f0dc39d3c1f03c063b"
+  integrity sha1-ZEun8JX3/898Q7Xw3DnTwfA8Bjs=
+  dependencies:
+    typical "^2.6.0"
+
+array-back@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/array-back/-/array-back-2.0.0.tgz#6877471d51ecc9c9bfa6136fb6c7d5fe69748022"
+  integrity sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==
+  dependencies:
+    typical "^2.6.1"
+
+array-back@^3.0.1:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0"
+  integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==
+
+array-differ@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031"
+  integrity sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=
+
+array-find-index@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
+  integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=
+
+array-flatten@1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
+  integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
+
+array-union@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
+  integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=
+  dependencies:
+    array-uniq "^1.0.1"
+
+array-uniq@^1.0.1:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
+  integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=
+
+array-unique@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
+  integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=
+
+array-unique@^0.3.2:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
+  integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=
+
+arraybuffer.slice@~0.0.7:
+  version "0.0.7"
+  resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675"
+  integrity sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==
+
+arrify@^1.0.0, arrify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
+  integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=
+
+asn1@~0.2.3:
+  version "0.2.4"
+  resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
+  integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
+  dependencies:
+    safer-buffer "~2.1.0"
+
+assert-plus@1.0.0, assert-plus@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
+  integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=
+
+assign-symbols@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
+  integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=
+
+async-each@^1.0.0:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf"
+  integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==
+
+async-limiter@~1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
+  integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
+
+async@^2.0.0, async@^2.0.1, async@^2.1.2, async@^2.4.1, async@^2.6.0, async@^2.6.1, async@^2.6.2, async@^2.6.3:
+  version "2.6.3"
+  resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
+  integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==
+  dependencies:
+    lodash "^4.17.14"
+
+async@~0.2.9:
+  version "0.2.10"
+  resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1"
+  integrity sha1-trvgsGdLnXGXCMo43owjfLUmw9E=
+
+asynckit@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+  integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
+
+atob-lite@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/atob-lite/-/atob-lite-2.0.0.tgz#0fef5ad46f1bd7a8502c65727f0367d5ee43d696"
+  integrity sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY=
+
+atob@^2.1.2:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
+  integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
+
+aws-sign2@~0.7.0:
+  version "0.7.0"
+  resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
+  integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
+
+aws4@^1.8.0:
+  version "1.9.1"
+  resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e"
+  integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==
+
+babel-code-frame@^6.26.0:
+  version "6.26.0"
+  resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
+  integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=
+  dependencies:
+    chalk "^1.1.3"
+    esutils "^2.0.2"
+    js-tokens "^3.0.2"
+
+babel-generator@^6.26.1:
+  version "6.26.1"
+  resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90"
+  integrity sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==
+  dependencies:
+    babel-messages "^6.23.0"
+    babel-runtime "^6.26.0"
+    babel-types "^6.26.0"
+    detect-indent "^4.0.0"
+    jsesc "^1.3.0"
+    lodash "^4.17.4"
+    source-map "^0.5.7"
+    trim-right "^1.0.1"
+
+babel-helper-evaluate-path@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.5.0.tgz#a62fa9c4e64ff7ea5cea9353174ef023a900a67c"
+  integrity sha512-mUh0UhS607bGh5wUMAQfOpt2JX2ThXMtppHRdRU1kL7ZLRWIXxoV2UIV1r2cAeeNeU1M5SB5/RSUgUxrK8yOkA==
+
+babel-helper-flip-expressions@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.4.3.tgz#3696736a128ac18bc25254b5f40a22ceb3c1d3fd"
+  integrity sha1-NpZzahKKwYvCUlS19AoizrPB0/0=
+
+babel-helper-is-nodes-equiv@^0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz#34e9b300b1479ddd98ec77ea0bbe9342dfe39684"
+  integrity sha1-NOmzALFHnd2Y7HfqC76TQt/jloQ=
+
+babel-helper-is-void-0@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-helper-is-void-0/-/babel-helper-is-void-0-0.4.3.tgz#7d9c01b4561e7b95dbda0f6eee48f5b60e67313e"
+  integrity sha1-fZwBtFYee5Xb2g9u7kj1tg5nMT4=
+
+babel-helper-mark-eval-scopes@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.4.3.tgz#d244a3bef9844872603ffb46e22ce8acdf551562"
+  integrity sha1-0kSjvvmESHJgP/tG4izorN9VFWI=
+
+babel-helper-remove-or-void@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.4.3.tgz#a4f03b40077a0ffe88e45d07010dee241ff5ae60"
+  integrity sha1-pPA7QAd6D/6I5F0HAQ3uJB/1rmA=
+
+babel-helper-to-multiple-sequence-expressions@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.5.0.tgz#a3f924e3561882d42fcf48907aa98f7979a4588d"
+  integrity sha512-m2CvfDW4+1qfDdsrtf4dwOslQC3yhbgyBFptncp4wvtdrDHqueW7slsYv4gArie056phvQFhT2nRcGS4bnm6mA==
+
+babel-messages@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e"
+  integrity sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-dynamic-import-node@^2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f"
+  integrity sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==
+  dependencies:
+    object.assign "^4.1.0"
+
+babel-plugin-minify-builtins@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.5.0.tgz#31eb82ed1a0d0efdc31312f93b6e4741ce82c36b"
+  integrity sha512-wpqbN7Ov5hsNwGdzuzvFcjgRlzbIeVv1gMIlICbPj0xkexnfoIDe7q+AZHMkQmAE/F9R5jkrB6TLfTegImlXag==
+
+babel-plugin-minify-constant-folding@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.5.0.tgz#f84bc8dbf6a561e5e350ff95ae216b0ad5515b6e"
+  integrity sha512-Vj97CTn/lE9hR1D+jKUeHfNy+m1baNiJ1wJvoGyOBUx7F7kJqDZxr9nCHjO/Ad+irbR3HzR6jABpSSA29QsrXQ==
+  dependencies:
+    babel-helper-evaluate-path "^0.5.0"
+
+babel-plugin-minify-dead-code-elimination@^0.5.1:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.5.1.tgz#1a0c68e44be30de4976ca69ffc535e08be13683f"
+  integrity sha512-x8OJOZIrRmQBcSqxBcLbMIK8uPmTvNWPXH2bh5MDCW1latEqYiRMuUkPImKcfpo59pTUB2FT7HfcgtG8ZlR5Qg==
+  dependencies:
+    babel-helper-evaluate-path "^0.5.0"
+    babel-helper-mark-eval-scopes "^0.4.3"
+    babel-helper-remove-or-void "^0.4.3"
+    lodash "^4.17.11"
+
+babel-plugin-minify-flip-comparisons@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.4.3.tgz#00ca870cb8f13b45c038b3c1ebc0f227293c965a"
+  integrity sha1-AMqHDLjxO0XAOLPB68DyJyk8llo=
+  dependencies:
+    babel-helper-is-void-0 "^0.4.3"
+
+babel-plugin-minify-guarded-expressions@^0.4.3, babel-plugin-minify-guarded-expressions@^0.4.4:
+  version "0.4.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.4.4.tgz#818960f64cc08aee9d6c75bec6da974c4d621135"
+  integrity sha512-RMv0tM72YuPPfLT9QLr3ix9nwUIq+sHT6z8Iu3sLbqldzC1Dls8DPCywzUIzkTx9Zh1hWX4q/m9BPoPed9GOfA==
+  dependencies:
+    babel-helper-evaluate-path "^0.5.0"
+    babel-helper-flip-expressions "^0.4.3"
+
+babel-plugin-minify-infinity@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.4.3.tgz#dfb876a1b08a06576384ef3f92e653ba607b39ca"
+  integrity sha1-37h2obCKBldjhO8/kuZTumB7Oco=
+
+babel-plugin-minify-mangle-names@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.5.0.tgz#bcddb507c91d2c99e138bd6b17a19c3c271e3fd3"
+  integrity sha512-3jdNv6hCAw6fsX1p2wBGPfWuK69sfOjfd3zjUXkbq8McbohWy23tpXfy5RnToYWggvqzuMOwlId1PhyHOfgnGw==
+  dependencies:
+    babel-helper-mark-eval-scopes "^0.4.3"
+
+babel-plugin-minify-numeric-literals@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.4.3.tgz#8e4fd561c79f7801286ff60e8c5fd9deee93c0bc"
+  integrity sha1-jk/VYcefeAEob/YOjF/Z3u6TwLw=
+
+babel-plugin-minify-replace@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.5.0.tgz#d3e2c9946c9096c070efc96761ce288ec5c3f71c"
+  integrity sha512-aXZiaqWDNUbyNNNpWs/8NyST+oU7QTpK7J9zFEFSA0eOmtUNMU3fczlTTTlnCxHmq/jYNFEmkkSG3DDBtW3Y4Q==
+
+babel-plugin-minify-simplify@^0.5.1:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.5.1.tgz#f21613c8b95af3450a2ca71502fdbd91793c8d6a"
+  integrity sha512-OSYDSnoCxP2cYDMk9gxNAed6uJDiDz65zgL6h8d3tm8qXIagWGMLWhqysT6DY3Vs7Fgq7YUDcjOomhVUb+xX6A==
+  dependencies:
+    babel-helper-evaluate-path "^0.5.0"
+    babel-helper-flip-expressions "^0.4.3"
+    babel-helper-is-nodes-equiv "^0.0.1"
+    babel-helper-to-multiple-sequence-expressions "^0.5.0"
+
+babel-plugin-minify-type-constructors@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.4.3.tgz#1bc6f15b87f7ab1085d42b330b717657a2156500"
+  integrity sha1-G8bxW4f3qxCF1CszC3F2V6IVZQA=
+  dependencies:
+    babel-helper-is-void-0 "^0.4.3"
+
+babel-plugin-transform-inline-consecutive-adds@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.4.3.tgz#323d47a3ea63a83a7ac3c811ae8e6941faf2b0d1"
+  integrity sha1-Mj1Ho+pjqDp6w8gRro5pQfrysNE=
+
+babel-plugin-transform-member-expression-literals@^6.9.4:
+  version "6.9.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.9.4.tgz#37039c9a0c3313a39495faac2ff3a6b5b9d038bf"
+  integrity sha1-NwOcmgwzE6OUlfqsL/OmtbnQOL8=
+
+babel-plugin-transform-merge-sibling-variables@^6.9.4:
+  version "6.9.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.9.4.tgz#85b422fc3377b449c9d1cde44087203532401dae"
+  integrity sha1-hbQi/DN3tEnJ0c3kQIcgNTJAHa4=
+
+babel-plugin-transform-minify-booleans@^6.9.4:
+  version "6.9.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.4.tgz#acbb3e56a3555dd23928e4b582d285162dd2b198"
+  integrity sha1-rLs+VqNVXdI5KOS1gtKFFi3SsZg=
+
+babel-plugin-transform-property-literals@^6.9.4:
+  version "6.9.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.9.4.tgz#98c1d21e255736573f93ece54459f6ce24985d39"
+  integrity sha1-mMHSHiVXNlc/k+zlRFn2ziSYXTk=
+  dependencies:
+    esutils "^2.0.2"
+
+babel-plugin-transform-regexp-constructors@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.4.3.tgz#58b7775b63afcf33328fae9a5f88fbd4fb0b4965"
+  integrity sha1-WLd3W2OvzzMyj66aX4j71PsLSWU=
+
+babel-plugin-transform-remove-console@^6.9.4:
+  version "6.9.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.4.tgz#b980360c067384e24b357a588d807d3c83527780"
+  integrity sha1-uYA2DAZzhOJLNXpYjYB9PINSd4A=
+
+babel-plugin-transform-remove-debugger@^6.9.4:
+  version "6.9.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.9.4.tgz#42b727631c97978e1eb2d199a7aec84a18339ef2"
+  integrity sha1-QrcnYxyXl44estGZp67IShgznvI=
+
+babel-plugin-transform-remove-undefined@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.5.0.tgz#80208b31225766c630c97fa2d288952056ea22dd"
+  integrity sha512-+M7fJYFaEE/M9CXa0/IRkDbiV3wRELzA1kKQFCJ4ifhrzLKn/9VCCgj9OFmYWwBd8IB48YdgPkHYtbYq+4vtHQ==
+  dependencies:
+    babel-helper-evaluate-path "^0.5.0"
+
+babel-plugin-transform-simplify-comparison-operators@^6.9.4:
+  version "6.9.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.9.4.tgz#f62afe096cab0e1f68a2d753fdf283888471ceb9"
+  integrity sha1-9ir+CWyrDh9ootdT/fKDiIRxzrk=
+
+babel-plugin-transform-undefined-to-void@^6.9.4:
+  version "6.9.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.4.tgz#be241ca81404030678b748717322b89d0c8fe280"
+  integrity sha1-viQcqBQEAwZ4t0hxcyK4nQyP4oA=
+
+babel-preset-minify@^0.5.0:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/babel-preset-minify/-/babel-preset-minify-0.5.1.tgz#25f5d0bce36ec818be80338d0e594106e21eaa9f"
+  integrity sha512-1IajDumYOAPYImkHbrKeiN5AKKP9iOmRoO2IPbIuVp0j2iuCcj0n7P260z38siKMZZ+85d3mJZdtW8IgOv+Tzg==
+  dependencies:
+    babel-plugin-minify-builtins "^0.5.0"
+    babel-plugin-minify-constant-folding "^0.5.0"
+    babel-plugin-minify-dead-code-elimination "^0.5.1"
+    babel-plugin-minify-flip-comparisons "^0.4.3"
+    babel-plugin-minify-guarded-expressions "^0.4.4"
+    babel-plugin-minify-infinity "^0.4.3"
+    babel-plugin-minify-mangle-names "^0.5.0"
+    babel-plugin-minify-numeric-literals "^0.4.3"
+    babel-plugin-minify-replace "^0.5.0"
+    babel-plugin-minify-simplify "^0.5.1"
+    babel-plugin-minify-type-constructors "^0.4.3"
+    babel-plugin-transform-inline-consecutive-adds "^0.4.3"
+    babel-plugin-transform-member-expression-literals "^6.9.4"
+    babel-plugin-transform-merge-sibling-variables "^6.9.4"
+    babel-plugin-transform-minify-booleans "^6.9.4"
+    babel-plugin-transform-property-literals "^6.9.4"
+    babel-plugin-transform-regexp-constructors "^0.4.3"
+    babel-plugin-transform-remove-console "^6.9.4"
+    babel-plugin-transform-remove-debugger "^6.9.4"
+    babel-plugin-transform-remove-undefined "^0.5.0"
+    babel-plugin-transform-simplify-comparison-operators "^6.9.4"
+    babel-plugin-transform-undefined-to-void "^6.9.4"
+    lodash "^4.17.11"
+
+babel-runtime@^6.22.0, babel-runtime@^6.26.0:
+  version "6.26.0"
+  resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
+  integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4=
+  dependencies:
+    core-js "^2.4.0"
+    regenerator-runtime "^0.11.0"
+
+babel-traverse@^6.26.0:
+  version "6.26.0"
+  resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee"
+  integrity sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=
+  dependencies:
+    babel-code-frame "^6.26.0"
+    babel-messages "^6.23.0"
+    babel-runtime "^6.26.0"
+    babel-types "^6.26.0"
+    babylon "^6.18.0"
+    debug "^2.6.8"
+    globals "^9.18.0"
+    invariant "^2.2.2"
+    lodash "^4.17.4"
+
+babel-types@^6.26.0:
+  version "6.26.0"
+  resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497"
+  integrity sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=
+  dependencies:
+    babel-runtime "^6.26.0"
+    esutils "^2.0.2"
+    lodash "^4.17.4"
+    to-fast-properties "^1.0.3"
+
+babylon@^6.18.0:
+  version "6.18.0"
+  resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3"
+  integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==
+
+babylon@^7.0.0-beta.42:
+  version "7.0.0-beta.47"
+  resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.47.tgz#6d1fa44f0abec41ab7c780481e62fd9aafbdea80"
+  integrity sha512-+rq2cr4GDhtToEzKFD6KZZMDBXhjFAr9JjPw9pAppZACeEWqNM294j+NdBzkSHYXwzzBmVjZ3nEVJlOhbR2gOQ==
+
+backo2@1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
+  integrity sha1-MasayLEpNjRj41s+u2n038+6eUc=
+
+balanced-match@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
+  integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
+
+base64-arraybuffer@0.1.5:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8"
+  integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg=
+
+base64-js@1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
+  integrity sha1-o5mS1yNYSBGYK+XikLtqU9hnAPE=
+
+base64-js@^1.0.2:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1"
+  integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==
+
+base64id@2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6"
+  integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==
+
+base@^0.11.1:
+  version "0.11.2"
+  resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
+  integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==
+  dependencies:
+    cache-base "^1.0.1"
+    class-utils "^0.3.5"
+    component-emitter "^1.2.1"
+    define-property "^1.0.0"
+    isobject "^3.0.1"
+    mixin-deep "^1.2.0"
+    pascalcase "^0.1.1"
+
+bcrypt-pbkdf@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
+  integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=
+  dependencies:
+    tweetnacl "^0.14.3"
+
+before-after-hook@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.1.0.tgz#b6c03487f44e24200dd30ca5e6a1979c5d2fb635"
+  integrity sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A==
+
+better-assert@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522"
+  integrity sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=
+  dependencies:
+    callsite "1.0.0"
+
+binary-extensions@^1.0.0:
+  version "1.13.1"
+  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65"
+  integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==
+
+binaryextensions@^2.1.2:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.2.0.tgz#e7c6ba82d4f5f5758c26078fe8eea28881233311"
+  integrity sha512-bHhs98rj/7i/RZpCSJ3uk55pLXOItjIrh2sRQZSM6OoktScX+LxJzvlU+FELp9j3TdcddTmmYArLSGptCTwjuw==
+
+bindings@^1.5.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df"
+  integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==
+  dependencies:
+    file-uri-to-path "1.0.0"
+
+bl@^1.0.0:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c"
+  integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==
+  dependencies:
+    readable-stream "^2.3.5"
+    safe-buffer "^5.1.1"
+
+bl@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/bl/-/bl-2.2.0.tgz#e1a574cdf528e4053019bb800b041c0ac88da493"
+  integrity sha512-wbgvOpqopSr7uq6fJrLH8EsvYMJf9gzfo2jCsL2eTy75qXPukA4pCgHamOQkZtY5vmfVtjB+P3LNlMHW5CEZXA==
+  dependencies:
+    readable-stream "^2.3.5"
+    safe-buffer "^5.1.1"
+
+bl@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/bl/-/bl-3.0.0.tgz#3611ec00579fd18561754360b21e9f784500ff88"
+  integrity sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A==
+  dependencies:
+    readable-stream "^3.0.1"
+
+blob@0.0.5:
+  version "0.0.5"
+  resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683"
+  integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==
+
+body-parser@1.19.0, body-parser@^1.17.2:
+  version "1.19.0"
+  resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
+  integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==
+  dependencies:
+    bytes "3.1.0"
+    content-type "~1.0.4"
+    debug "2.6.9"
+    depd "~1.1.2"
+    http-errors "1.7.2"
+    iconv-lite "0.4.24"
+    on-finished "~2.3.0"
+    qs "6.7.0"
+    raw-body "2.4.0"
+    type-is "~1.6.17"
+
+bower-config@^1.4.0, bower-config@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/bower-config/-/bower-config-1.4.1.tgz#85fd9df367c2b8dbbd0caa4c5f2bad40cd84c2cc"
+  integrity sha1-hf2d82fCuNu9DKpMXyutQM2Ewsw=
+  dependencies:
+    graceful-fs "^4.1.3"
+    mout "^1.0.0"
+    optimist "^0.6.1"
+    osenv "^0.1.3"
+    untildify "^2.1.0"
+
+bower-json@^0.8.1:
+  version "0.8.1"
+  resolved "https://registry.yarnpkg.com/bower-json/-/bower-json-0.8.1.tgz#96c14723241ae6466a9c52e16caa32623a883843"
+  integrity sha1-lsFHIyQa5kZqnFLhbKoyYjqIOEM=
+  dependencies:
+    deep-extend "^0.4.0"
+    ext-name "^3.0.0"
+    graceful-fs "^4.1.3"
+    intersect "^1.0.1"
+
+bower-logger@^0.2.2:
+  version "0.2.2"
+  resolved "https://registry.yarnpkg.com/bower-logger/-/bower-logger-0.2.2.tgz#39be07e979b2fc8e03a94634205ed9422373d381"
+  integrity sha1-Ob4H6Xmy/I4DqUY0IF7ZQiNz04E=
+
+bower@^1.8.8:
+  version "1.8.8"
+  resolved "https://registry.yarnpkg.com/bower/-/bower-1.8.8.tgz#82544be34a33aeae7efb8bdf9905247b2cffa985"
+  integrity sha512-1SrJnXnkP9soITHptSO+ahx3QKp3cVzn8poI6ujqc5SeOkg5iqM1pK9H+DSc2OQ8SnO0jC/NG4Ur/UIwy7574A==
+
+boxen@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/boxen/-/boxen-0.6.0.tgz#8364d4248ac34ff0ef1b2f2bf49a6c60ce0d81b6"
+  integrity sha1-g2TUJIrDT/DvGy8r9JpsYM4NgbY=
+  dependencies:
+    ansi-align "^1.1.0"
+    camelcase "^2.1.0"
+    chalk "^1.1.1"
+    cli-boxes "^1.0.0"
+    filled-array "^1.0.0"
+    object-assign "^4.0.1"
+    repeating "^2.0.0"
+    string-width "^1.0.1"
+    widest-line "^1.0.0"
+
+boxen@^1.2.1:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b"
+  integrity sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==
+  dependencies:
+    ansi-align "^2.0.0"
+    camelcase "^4.0.0"
+    chalk "^2.0.1"
+    cli-boxes "^1.0.0"
+    string-width "^2.0.0"
+    term-size "^1.2.0"
+    widest-line "^2.0.0"
+
+brace-expansion@^1.1.7:
+  version "1.1.11"
+  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+  integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+  dependencies:
+    balanced-match "^1.0.0"
+    concat-map "0.0.1"
+
+braces@^1.8.2:
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
+  integrity sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=
+  dependencies:
+    expand-range "^1.8.1"
+    preserve "^0.2.0"
+    repeat-element "^1.1.2"
+
+braces@^2.3.1:
+  version "2.3.2"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
+  integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==
+  dependencies:
+    arr-flatten "^1.1.0"
+    array-unique "^0.3.2"
+    extend-shallow "^2.0.1"
+    fill-range "^4.0.0"
+    isobject "^3.0.1"
+    repeat-element "^1.1.2"
+    snapdragon "^0.8.1"
+    snapdragon-node "^2.0.1"
+    split-string "^3.0.2"
+    to-regex "^3.0.1"
+
+browser-capabilities@^1.0.0:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/browser-capabilities/-/browser-capabilities-1.1.4.tgz#a6bd657a07a134532ad66c722b8949904478b973"
+  integrity sha512-BezMQhbQklxjRQpZZQ8tnbzEo6AldUwMh8/PeWt5/CTBSwByQRXZEAK2fbnEahQ4poeeaI0suAYRq25A1YGOmw==
+  dependencies:
+    "@types/ua-parser-js" "^0.7.31"
+    ua-parser-js "^0.7.15"
+
+browserify-zlib@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d"
+  integrity sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=
+  dependencies:
+    pako "~0.2.0"
+
+browserstack@^1.2.0:
+  version "1.5.3"
+  resolved "https://registry.yarnpkg.com/browserstack/-/browserstack-1.5.3.tgz#93ab48799a12ef99dbd074dd595410ddb196a7ac"
+  integrity sha512-AO+mECXsW4QcqC9bxwM29O7qWa7bJT94uBFzeb5brylIQwawuEziwq20dPYbins95GlWzOawgyDNdjYAo32EKg==
+  dependencies:
+    https-proxy-agent "^2.2.1"
+
+btoa-lite@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337"
+  integrity sha1-M3dm2hWAEhD92VbCLpxokaudAzc=
+
+buffer-alloc-unsafe@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
+  integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==
+
+buffer-alloc@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec"
+  integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==
+  dependencies:
+    buffer-alloc-unsafe "^1.1.0"
+    buffer-fill "^1.0.0"
+
+buffer-crc32@^0.2.1, buffer-crc32@^0.2.13, buffer-crc32@~0.2.3:
+  version "0.2.13"
+  resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
+  integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=
+
+buffer-fill@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c"
+  integrity sha1-+PeLdniYiO858gXNY39o5wISKyw=
+
+buffer-from@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
+  integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
+
+buffer@^5.1.0:
+  version "5.4.3"
+  resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.4.3.tgz#3fbc9c69eb713d323e3fc1a895eee0710c072115"
+  integrity sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==
+  dependencies:
+    base64-js "^1.0.2"
+    ieee754 "^1.1.4"
+
+builtin-modules@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.1.0.tgz#aad97c15131eb76b65b50ef208e7584cd76a7484"
+  integrity sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==
+
+busboy@^0.2.11:
+  version "0.2.14"
+  resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453"
+  integrity sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=
+  dependencies:
+    dicer "0.2.5"
+    readable-stream "1.1.x"
+
+bytes@3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
+  integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=
+
+bytes@3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
+  integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
+
+cache-base@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
+  integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==
+  dependencies:
+    collection-visit "^1.0.0"
+    component-emitter "^1.2.1"
+    get-value "^2.0.6"
+    has-value "^1.0.0"
+    isobject "^3.0.1"
+    set-value "^2.0.0"
+    to-object-path "^0.3.0"
+    union-value "^1.0.0"
+    unset-value "^1.0.0"
+
+call-me-maybe@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b"
+  integrity sha1-JtII6onje1y95gJQoV8DHBak1ms=
+
+callsite@1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20"
+  integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA=
+
+camel-case@3.0.x:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73"
+  integrity sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=
+  dependencies:
+    no-case "^2.2.0"
+    upper-case "^1.1.1"
+
+camelcase-keys@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7"
+  integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc=
+  dependencies:
+    camelcase "^2.0.0"
+    map-obj "^1.0.0"
+
+camelcase@^2.0.0, camelcase@^2.1.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
+  integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=
+
+camelcase@^4.0.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
+  integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=
+
+cancel-token@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/cancel-token/-/cancel-token-0.1.1.tgz#c18197674bb1c84c1d6933ebf15d8d5a5ce79b4f"
+  integrity sha1-wYGXZ0uxyEwdaTPr8V2NWlznm08=
+  dependencies:
+    "@types/node" "^4.0.30"
+
+capture-stack-trace@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz#a6c0bbe1f38f3aa0b92238ecb6ff42c344d4135d"
+  integrity sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==
+
+caseless@~0.12.0:
+  version "0.12.0"
+  resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
+  integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
+
+chalk@*:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4"
+  integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==
+  dependencies:
+    ansi-styles "^4.1.0"
+    supports-color "^7.1.0"
+
+chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
+  integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=
+  dependencies:
+    ansi-styles "^2.2.1"
+    escape-string-regexp "^1.0.2"
+    has-ansi "^2.0.0"
+    strip-ansi "^3.0.0"
+    supports-color "^2.0.0"
+
+chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4.2:
+  version "2.4.2"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
+  integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
+  dependencies:
+    ansi-styles "^3.2.1"
+    escape-string-regexp "^1.0.5"
+    supports-color "^5.3.0"
+
+chalk@~0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f"
+  integrity sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=
+  dependencies:
+    ansi-styles "~1.0.0"
+    has-color "~0.1.0"
+    strip-ansi "~0.1.0"
+
+chardet@^0.7.0:
+  version "0.7.0"
+  resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
+  integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
+
+charenc@~0.0.1:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
+  integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=
+
+chokidar@^1.7.0:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
+  integrity sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=
+  dependencies:
+    anymatch "^1.3.0"
+    async-each "^1.0.0"
+    glob-parent "^2.0.0"
+    inherits "^2.0.1"
+    is-binary-path "^1.0.0"
+    is-glob "^2.0.0"
+    path-is-absolute "^1.0.0"
+    readdirp "^2.0.0"
+  optionalDependencies:
+    fsevents "^1.0.0"
+
+chownr@^1.0.1:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.3.tgz#42d837d5239688d55f303003a508230fa6727142"
+  integrity sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==
+
+ci-info@^1.5.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497"
+  integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==
+
+class-utils@^0.3.5:
+  version "0.3.6"
+  resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
+  integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==
+  dependencies:
+    arr-union "^3.1.0"
+    define-property "^0.2.5"
+    isobject "^3.0.0"
+    static-extend "^0.1.1"
+
+clean-css@4.2.x:
+  version "4.2.2"
+  resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.2.tgz#8519abda724b3e759bc79d196369906925d81a3f"
+  integrity sha512-yKycArwReQXbOD/3pmsPmt6p7oUBww8MisDabL2pCUWkbVONvCJoBdCjgY4ZVQmKX5juz/JB9oDcP6XzGUpjwQ==
+  dependencies:
+    source-map "~0.6.0"
+
+cleankill@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/cleankill/-/cleankill-2.0.0.tgz#59830dfc8b411d53dc72ad09d45a78ea33161a91"
+  integrity sha1-WYMN/ItBHVPccq0J1Fp46jMWGpE=
+
+cli-boxes@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143"
+  integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM=
+
+cli-cursor@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987"
+  integrity sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=
+  dependencies:
+    restore-cursor "^1.0.1"
+
+cli-cursor@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5"
+  integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=
+  dependencies:
+    restore-cursor "^2.0.0"
+
+cli-table@^0.3.1:
+  version "0.3.1"
+  resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23"
+  integrity sha1-9TsFJmqLGguTSz0IIebi3FkUriM=
+  dependencies:
+    colors "1.0.3"
+
+cli-width@^2.0.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639"
+  integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=
+
+clone-buffer@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58"
+  integrity sha1-4+JbIHrE5wGvch4staFnksrD3Fg=
+
+clone-stats@^0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1"
+  integrity sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=
+
+clone-stats@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680"
+  integrity sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=
+
+clone@^1.0.0, clone@^1.0.2:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
+  integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
+
+clone@^2.0.0, clone@^2.1.0, clone@^2.1.1:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
+  integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=
+
+cloneable-readable@^1.0.0:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.1.3.tgz#120a00cb053bfb63a222e709f9683ea2e11d8cec"
+  integrity sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==
+  dependencies:
+    inherits "^2.0.1"
+    process-nextick-args "^2.0.0"
+    readable-stream "^2.3.5"
+
+code-point-at@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
+  integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
+
+collection-visit@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
+  integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=
+  dependencies:
+    map-visit "^1.0.0"
+    object-visit "^1.0.0"
+
+color-convert@^1.9.0, color-convert@^1.9.1:
+  version "1.9.3"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
+  integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
+  dependencies:
+    color-name "1.1.3"
+
+color-convert@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
+  integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
+  dependencies:
+    color-name "~1.1.4"
+
+color-name@1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+  integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
+
+color-name@^1.0.0, color-name@~1.1.4:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
+  integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+
+color-string@^1.5.2:
+  version "1.5.3"
+  resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.3.tgz#c9bbc5f01b58b5492f3d6857459cb6590ce204cc"
+  integrity sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==
+  dependencies:
+    color-name "^1.0.0"
+    simple-swizzle "^0.2.2"
+
+color@3.0.x:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/color/-/color-3.0.0.tgz#d920b4328d534a3ac8295d68f7bd4ba6c427be9a"
+  integrity sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==
+  dependencies:
+    color-convert "^1.9.1"
+    color-string "^1.5.2"
+
+colornames@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/colornames/-/colornames-1.1.1.tgz#f8889030685c7c4ff9e2a559f5077eb76a816f96"
+  integrity sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=
+
+colors@1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b"
+  integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=
+
+colors@^1.2.1:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
+  integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==
+
+colorspace@1.1.x:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.2.tgz#e0128950d082b86a2168580796a0aa5d6c68d8c5"
+  integrity sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==
+  dependencies:
+    color "3.0.x"
+    text-hex "1.0.x"
+
+combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
+  version "1.0.8"
+  resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
+  integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
+  dependencies:
+    delayed-stream "~1.0.0"
+
+command-line-args@^3.0.1:
+  version "3.0.5"
+  resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-3.0.5.tgz#5bd4ad45e7983e5c1344918e40280ee2693c5ac0"
+  integrity sha1-W9StReeYPlwTRJGOQCgO4mk8WsA=
+  dependencies:
+    array-back "^1.0.4"
+    feature-detect-es6 "^1.3.1"
+    find-replace "^1.0.2"
+    typical "^2.6.0"
+
+command-line-args@^5.0.2:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.1.1.tgz#88e793e5bb3ceb30754a86863f0401ac92fd369a"
+  integrity sha512-hL/eG8lrll1Qy1ezvkant+trihbGnaKaeEjj6Scyr3DN+RC7iQ5Rz84IeLERfAWDGo0HBSNAakczwgCilDXnWg==
+  dependencies:
+    array-back "^3.0.1"
+    find-replace "^3.0.0"
+    lodash.camelcase "^4.3.0"
+    typical "^4.0.0"
+
+command-line-commands@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/command-line-commands/-/command-line-commands-2.0.1.tgz#c58aa13dc78c06038ed67077e57ad09a6f858f46"
+  integrity sha512-m8c2p1DrNd2ruIAggxd/y6DgygQayf6r8RHwchhXryaLF8I6koYjoYroVP+emeROE9DXN5b9sP1Gh+WtvTTdtQ==
+  dependencies:
+    array-back "^2.0.0"
+
+command-line-usage@^3.0.8:
+  version "3.0.8"
+  resolved "https://registry.yarnpkg.com/command-line-usage/-/command-line-usage-3.0.8.tgz#b6a20978c1b383477f5c11a529428b880bfe0f4d"
+  integrity sha1-tqIJeMGzg0d/XBGlKUKLiAv+D00=
+  dependencies:
+    ansi-escape-sequences "^3.0.0"
+    array-back "^1.0.3"
+    feature-detect-es6 "^1.3.1"
+    table-layout "^0.3.0"
+    typical "^2.6.0"
+
+command-line-usage@^5.0.5:
+  version "5.0.5"
+  resolved "https://registry.yarnpkg.com/command-line-usage/-/command-line-usage-5.0.5.tgz#5f25933ffe6dedd983c635d38a21d7e623fda357"
+  integrity sha512-d8NrGylA5oCXSbGoKz05FkehDAzSmIm4K03S5VDh4d5lZAtTWfc3D1RuETtuQCn8129nYfJfDdF7P/lwcz1BlA==
+  dependencies:
+    array-back "^2.0.0"
+    chalk "^2.4.1"
+    table-layout "^0.4.3"
+    typical "^2.6.1"
+
+commander@2.17.x:
+  version "2.17.1"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
+  integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==
+
+commander@^2.19.0, commander@^2.20.0:
+  version "2.20.3"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
+  integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
+
+commander@~2.19.0:
+  version "2.19.0"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
+  integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==
+
+commondir@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
+  integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=
+
+component-bind@1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1"
+  integrity sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=
+
+component-emitter@1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
+  integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=
+
+component-emitter@^1.2.1:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
+  integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
+
+component-inherit@0.0.3:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143"
+  integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=
+
+compress-commons@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-2.1.1.tgz#9410d9a534cf8435e3fbbb7c6ce48de2dc2f0610"
+  integrity sha512-eVw6n7CnEMFzc3duyFVrQEuY1BlHR3rYsSztyG32ibGMW722i3C6IizEGMFmfMU+A+fALvBIwxN3czffTcdA+Q==
+  dependencies:
+    buffer-crc32 "^0.2.13"
+    crc32-stream "^3.0.1"
+    normalize-path "^3.0.0"
+    readable-stream "^2.3.6"
+
+compressible@~2.0.16:
+  version "2.0.18"
+  resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba"
+  integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==
+  dependencies:
+    mime-db ">= 1.43.0 < 2"
+
+compression@^1.6.2:
+  version "1.7.4"
+  resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f"
+  integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==
+  dependencies:
+    accepts "~1.3.5"
+    bytes "3.0.0"
+    compressible "~2.0.16"
+    debug "2.6.9"
+    on-headers "~1.0.2"
+    safe-buffer "5.1.2"
+    vary "~1.1.2"
+
+concat-map@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+  integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
+
+concat-stream@^1.4.7, concat-stream@^1.5.2:
+  version "1.6.2"
+  resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
+  integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
+  dependencies:
+    buffer-from "^1.0.0"
+    inherits "^2.0.3"
+    readable-stream "^2.2.2"
+    typedarray "^0.0.6"
+
+configstore@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/configstore/-/configstore-2.1.0.tgz#737a3a7036e9886102aa6099e47bb33ab1aba1a1"
+  integrity sha1-c3o6cDbpiGECqmCZ5HuzOrGroaE=
+  dependencies:
+    dot-prop "^3.0.0"
+    graceful-fs "^4.1.2"
+    mkdirp "^0.5.0"
+    object-assign "^4.0.1"
+    os-tmpdir "^1.0.0"
+    osenv "^0.1.0"
+    uuid "^2.0.1"
+    write-file-atomic "^1.1.2"
+    xdg-basedir "^2.0.0"
+
+configstore@^3.0.0:
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.2.tgz#c6f25defaeef26df12dd33414b001fe81a543f8f"
+  integrity sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==
+  dependencies:
+    dot-prop "^4.1.0"
+    graceful-fs "^4.1.2"
+    make-dir "^1.0.0"
+    unique-string "^1.0.0"
+    write-file-atomic "^2.0.0"
+    xdg-basedir "^3.0.0"
+
+content-disposition@0.5.3:
+  version "0.5.3"
+  resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
+  integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==
+  dependencies:
+    safe-buffer "5.1.2"
+
+content-type@^1.0.2, content-type@~1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
+  integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
+
+convert-source-map@^1.1.1, convert-source-map@^1.7.0:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442"
+  integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==
+  dependencies:
+    safe-buffer "~5.1.1"
+
+cookie-signature@1.0.6:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
+  integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
+
+cookie@0.3.1:
+  version "0.3.1"
+  resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
+  integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=
+
+cookie@0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
+  integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
+
+copy-descriptor@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
+  integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
+
+core-js@^2.4.0, core-js@^2.4.1:
+  version "2.6.11"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c"
+  integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==
+
+core-util-is@1.0.2, core-util-is@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
+  integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
+
+cors@^2.8.4:
+  version "2.8.5"
+  resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
+  integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
+  dependencies:
+    object-assign "^4"
+    vary "^1"
+
+crc32-stream@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-3.0.1.tgz#cae6eeed003b0e44d739d279de5ae63b171b4e85"
+  integrity sha512-mctvpXlbzsvK+6z8kJwSJ5crm7yBwrQMTybJzMw1O4lLGJqjlDCXY2Zw7KheiA6XBEcBmfLx1D88mjRGVJtY9w==
+  dependencies:
+    crc "^3.4.4"
+    readable-stream "^3.4.0"
+
+crc@^3.4.4:
+  version "3.8.0"
+  resolved "https://registry.yarnpkg.com/crc/-/crc-3.8.0.tgz#ad60269c2c856f8c299e2c4cc0de4556914056c6"
+  integrity sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==
+  dependencies:
+    buffer "^5.1.0"
+
+create-error-class@^3.0.0, create-error-class@^3.0.1:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6"
+  integrity sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=
+  dependencies:
+    capture-stack-trace "^1.0.0"
+
+crisper@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/crisper/-/crisper-2.1.1.tgz#4cc7321c3e90f3c5cbdc3503217f118fd7d5c51c"
+  integrity sha512-yxfj9nTbFunDASztAxVF8hCPwaZBvTjayNzG3YL/VVQfQaKBXX2+TM3p1xB1Pxd8RYeDQJkJIQRwM3FQSIa+pw==
+  dependencies:
+    command-line-args "^3.0.1"
+    command-line-usage "^3.0.8"
+    dom5 "^1.0.1"
+
+cross-spawn@^5.0.1:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
+  integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=
+  dependencies:
+    lru-cache "^4.0.1"
+    shebang-command "^1.2.0"
+    which "^1.2.9"
+
+cross-spawn@^6.0.0, cross-spawn@^6.0.5:
+  version "6.0.5"
+  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
+  integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
+  dependencies:
+    nice-try "^1.0.4"
+    path-key "^2.0.1"
+    semver "^5.5.0"
+    shebang-command "^1.2.0"
+    which "^1.2.9"
+
+crypt@~0.0.1:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
+  integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=
+
+crypto-random-string@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
+  integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=
+
+css-slam@^2.1.2:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/css-slam/-/css-slam-2.1.2.tgz#3d35b1922cb3e0002a45c89ab189492508c493e5"
+  integrity sha512-cObrY+mhFEmepWpua6EpMrgRNTQ0eeym+kvR0lukI6hDEzK7F8himEDS4cJ9+fPHCoArTzVrrR0d+oAUbTR1NA==
+  dependencies:
+    command-line-args "^5.0.2"
+    command-line-usage "^5.0.5"
+    dom5 "^3.0.0"
+    parse5 "^4.0.0"
+    shady-css-parser "^0.1.0"
+
+css-what@^2.1.0:
+  version "2.1.3"
+  resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2"
+  integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==
+
+cssbeautify@^0.3.1:
+  version "0.3.1"
+  resolved "https://registry.yarnpkg.com/cssbeautify/-/cssbeautify-0.3.1.tgz#12dd1f734035c2e6faca67dcbdcef74e42811397"
+  integrity sha1-Et0fc0A1wub6ymfcvc73TkKBE5c=
+
+currently-unhandled@^0.4.1:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
+  integrity sha1-mI3zP+qxke95mmE2nddsF635V+o=
+  dependencies:
+    array-find-index "^1.0.1"
+
+dargs@^6.0.0:
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/dargs/-/dargs-6.1.0.tgz#1f3b9b56393ecf8caa7cbfd6c31496ffcfb9b272"
+  integrity sha512-5dVBvpBLBnPwSsYXqfybFyehMmC/EenKEcf23AhCTgTf48JFBbmJKqoZBsERDnjL0FyiVTYWdFsRfTLHxLyKdQ==
+
+dashdash@^1.12.0:
+  version "1.14.1"
+  resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
+  integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=
+  dependencies:
+    assert-plus "^1.0.0"
+
+dateformat@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
+  integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==
+
+debug@2.6.9, debug@^2.0.0, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8:
+  version "2.6.9"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
+  integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
+  dependencies:
+    ms "2.0.0"
+
+debug@^3.0.0, debug@^3.1.0:
+  version "3.2.6"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
+  integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
+  dependencies:
+    ms "^2.1.1"
+
+debug@^4.1.0, debug@^4.1.1, debug@~4.1.0:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
+  integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
+  dependencies:
+    ms "^2.1.1"
+
+debug@~3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
+  integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
+  dependencies:
+    ms "2.0.0"
+
+decamelize@^1.1.2:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+  integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
+
+decode-uri-component@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
+  integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
+
+decompress-response@^3.2.0:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3"
+  integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=
+  dependencies:
+    mimic-response "^1.0.0"
+
+deep-extend@^0.4.0, deep-extend@~0.4.1:
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f"
+  integrity sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=
+
+deep-extend@^0.6.0, deep-extend@~0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
+  integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
+
+define-properties@^1.1.2:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
+  integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
+  dependencies:
+    object-keys "^1.0.12"
+
+define-property@^0.2.5:
+  version "0.2.5"
+  resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116"
+  integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=
+  dependencies:
+    is-descriptor "^0.1.0"
+
+define-property@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6"
+  integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY=
+  dependencies:
+    is-descriptor "^1.0.0"
+
+define-property@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d"
+  integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==
+  dependencies:
+    is-descriptor "^1.0.2"
+    isobject "^3.0.1"
+
+del@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/del/-/del-3.0.0.tgz#53ecf699ffcbcb39637691ab13baf160819766e5"
+  integrity sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=
+  dependencies:
+    globby "^6.1.0"
+    is-path-cwd "^1.0.0"
+    is-path-in-cwd "^1.0.0"
+    p-map "^1.1.1"
+    pify "^3.0.0"
+    rimraf "^2.2.8"
+
+delayed-stream@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+  integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
+
+depd@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
+  integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
+
+deprecation@^2.0.0:
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919"
+  integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==
+
+destroy@~1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
+  integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
+
+detect-conflict@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/detect-conflict/-/detect-conflict-1.0.1.tgz#088657a66a961c05019db7c4230883b1c6b4176e"
+  integrity sha1-CIZXpmqWHAUBnbfEIwiDsca0F24=
+
+detect-file@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63"
+  integrity sha1-STXe39lIhkjgBrASlWbpOGcR6mM=
+  dependencies:
+    fs-exists-sync "^0.1.0"
+
+detect-file@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7"
+  integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=
+
+detect-indent@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208"
+  integrity sha1-920GQ1LN9Docts5hnE7jqUdd4gg=
+  dependencies:
+    repeating "^2.0.0"
+
+detect-node@^2.0.3:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
+  integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==
+
+diagnostics@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/diagnostics/-/diagnostics-1.1.1.tgz#cab6ac33df70c9d9a727490ae43ac995a769b22a"
+  integrity sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==
+  dependencies:
+    colorspace "1.1.x"
+    enabled "1.0.x"
+    kuler "1.0.x"
+
+dicer@0.2.5:
+  version "0.2.5"
+  resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.2.5.tgz#5996c086bb33218c812c090bddc09cd12facb70f"
+  integrity sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=
+  dependencies:
+    readable-stream "1.1.x"
+    streamsearch "0.1.2"
+
+diff@^2.1.2:
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/diff/-/diff-2.2.3.tgz#60eafd0d28ee906e4e8ff0a52c1229521033bf99"
+  integrity sha1-YOr9DSjukG5Oj/ClLBIpUhAzv5k=
+
+diff@^3.1.0, diff@^3.5.0:
+  version "3.5.0"
+  resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
+  integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
+
+dir-glob@2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.0.0.tgz#0b205d2b6aef98238ca286598a8204d29d0a0034"
+  integrity sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==
+  dependencies:
+    arrify "^1.0.1"
+    path-type "^3.0.0"
+
+doctrine@^2.0.2:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
+  integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==
+  dependencies:
+    esutils "^2.0.2"
+
+dom-urls@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/dom-urls/-/dom-urls-1.1.0.tgz#001ddf81628cd1e706125c7176f53ccec55d918e"
+  integrity sha1-AB3fgWKM0ecGElxxdvU8zsVdkY4=
+  dependencies:
+    urijs "^1.16.1"
+
+dom5@^1.0.1:
+  version "1.3.6"
+  resolved "https://registry.yarnpkg.com/dom5/-/dom5-1.3.6.tgz#a7088a9fc5f3b08dc9f6eda4c7abaeb241945e0d"
+  integrity sha1-pwiKn8XzsI3J9u2kx6uuskGUXg0=
+  dependencies:
+    "@types/clone" "^0.1.29"
+    "@types/node" "^4.0.30"
+    "@types/parse5" "^0.0.31"
+    clone "^1.0.2"
+    parse5 "^1.4.1"
+
+dom5@^3.0.0, dom5@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/dom5/-/dom5-3.0.1.tgz#cdfc7331f376e284bf379e6ea054afc136702944"
+  integrity sha512-JPFiouQIr16VQ4dX6i0+Hpbg3H2bMKPmZ+WZgBOSSvOPx9QHwwY8sPzeM2baUtViESYto6wC2nuZOMC/6gulcA==
+  dependencies:
+    "@types/parse5" "^2.2.34"
+    clone "^2.1.0"
+    parse5 "^4.0.0"
+
+dot-prop@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177"
+  integrity sha1-G3CK8JSknJoOfbyteQq6U52sEXc=
+  dependencies:
+    is-obj "^1.0.0"
+
+dot-prop@^4.1.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57"
+  integrity sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==
+  dependencies:
+    is-obj "^1.0.0"
+
+duplexer2@^0.1.2, duplexer2@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1"
+  integrity sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=
+  dependencies:
+    readable-stream "^2.0.2"
+
+duplexer3@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
+  integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=
+
+duplexify@^3.2.0, duplexify@^3.5.0, duplexify@^3.6.0:
+  version "3.7.1"
+  resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309"
+  integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==
+  dependencies:
+    end-of-stream "^1.0.0"
+    inherits "^2.0.1"
+    readable-stream "^2.0.0"
+    stream-shift "^1.0.0"
+
+ecc-jsbn@~0.1.1:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
+  integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=
+  dependencies:
+    jsbn "~0.1.0"
+    safer-buffer "^2.1.0"
+
+editions@^2.2.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/editions/-/editions-2.3.0.tgz#47f2d5309340bce93ab5eb6ad755b9e90ff825e4"
+  integrity sha512-jeXYwHPKbitU1l14dWlsl5Nm+b1Hsm7VX73BsrQ4RVwEcAQQIPFHTZAbVtuIGxZBrpdT2FXd8lbtrNBrzZxIsA==
+  dependencies:
+    errlop "^2.0.0"
+    semver "^6.3.0"
+
+ee-first@1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
+  integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
+
+ejs@^2.5.9:
+  version "2.7.4"
+  resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba"
+  integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==
+
+emitter-component@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/emitter-component/-/emitter-component-1.1.1.tgz#065e2dbed6959bf470679edabeaf7981d1003ab6"
+  integrity sha1-Bl4tvtaVm/RwZ57avq95gdEAOrY=
+
+enabled@1.0.x:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/enabled/-/enabled-1.0.2.tgz#965f6513d2c2d1c5f4652b64a2e3396467fc2f93"
+  integrity sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=
+  dependencies:
+    env-variable "0.0.x"
+
+encodeurl@~1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
+  integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
+
+end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1:
+  version "1.4.4"
+  resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
+  integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
+  dependencies:
+    once "^1.4.0"
+
+ends-with@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/ends-with/-/ends-with-0.2.0.tgz#2f9da98d57a50cfda4571ce4339000500f4e6b8a"
+  integrity sha1-L52pjVelDP2kVxzkM5AAUA9Oa4o=
+
+engine.io-client@~3.4.0:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.4.0.tgz#82a642b42862a9b3f7a188f41776b2deab643700"
+  integrity sha512-a4J5QO2k99CM2a0b12IznnyQndoEvtA4UAldhGzKqnHf42I3Qs2W5SPnDvatZRcMaNZs4IevVicBPayxYt6FwA==
+  dependencies:
+    component-emitter "1.2.1"
+    component-inherit "0.0.3"
+    debug "~4.1.0"
+    engine.io-parser "~2.2.0"
+    has-cors "1.1.0"
+    indexof "0.0.1"
+    parseqs "0.0.5"
+    parseuri "0.0.5"
+    ws "~6.1.0"
+    xmlhttprequest-ssl "~1.5.4"
+    yeast "0.1.2"
+
+engine.io-parser@~2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.2.0.tgz#312c4894f57d52a02b420868da7b5c1c84af80ed"
+  integrity sha512-6I3qD9iUxotsC5HEMuuGsKA0cXerGz+4uGcXQEkfBidgKf0amsjrrtwcbwK/nzpZBxclXlV7gGl9dgWvu4LF6w==
+  dependencies:
+    after "0.8.2"
+    arraybuffer.slice "~0.0.7"
+    base64-arraybuffer "0.1.5"
+    blob "0.0.5"
+    has-binary2 "~1.0.2"
+
+engine.io@~3.4.0:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.4.0.tgz#3a962cc4535928c252759a00f98519cb46c53ff3"
+  integrity sha512-XCyYVWzcHnK5cMz7G4VTu2W7zJS7SM1QkcelghyIk/FmobWBtXE7fwhBusEKvCSqc3bMh8fNFMlUkCKTFRxH2w==
+  dependencies:
+    accepts "~1.3.4"
+    base64id "2.0.0"
+    cookie "0.3.1"
+    debug "~4.1.0"
+    engine.io-parser "~2.2.0"
+    ws "^7.1.2"
+
+env-variable@0.0.x:
+  version "0.0.5"
+  resolved "https://registry.yarnpkg.com/env-variable/-/env-variable-0.0.5.tgz#913dd830bef11e96a039c038d4130604eba37f88"
+  integrity sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==
+
+errlop@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/errlop/-/errlop-2.0.0.tgz#52b97d35da1b0795e2647b5d2d3a46d17776f55a"
+  integrity sha512-z00WIrQhtOMUnjdTG0O4f6hMG64EVccVDBy2WwgjcF8S4UB1exGYuc2OFwmdQmsJwLQVEIHWHPCz/omXXgAZHw==
+
+error-ex@^1.2.0, error-ex@^1.3.1:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
+  integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
+  dependencies:
+    is-arrayish "^0.2.1"
+
+error@^7.0.2:
+  version "7.2.1"
+  resolved "https://registry.yarnpkg.com/error/-/error-7.2.1.tgz#eab21a4689b5f684fc83da84a0e390de82d94894"
+  integrity sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA==
+  dependencies:
+    string-template "~0.2.1"
+
+es6-promise@^4.0.3, es6-promise@^4.0.5:
+  version "4.2.8"
+  resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
+  integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==
+
+es6-promisify@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
+  integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=
+  dependencies:
+    es6-promise "^4.0.3"
+
+es6-promisify@^6.0.0:
+  version "6.0.2"
+  resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-6.0.2.tgz#525c23725b8510f5f1f2feb5a1fbad93a93e29b4"
+  integrity sha512-eO6vFm0JvqGzjWIQA6QVKjxpmELfhWbDUWHm1rPfIbn55mhKPiAa5xpLmQWJrNa629ZIeQ8ZvMAi13kvrjK6Mg==
+
+escape-html@^1.0.3, escape-html@~1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
+  integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
+
+escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.4, escape-string-regexp@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+  integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
+
+espree@^3.5.2:
+  version "3.5.4"
+  resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7"
+  integrity sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==
+  dependencies:
+    acorn "^5.5.0"
+    acorn-jsx "^3.0.0"
+
+estree-walker@^0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362"
+  integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==
+
+esutils@^2.0.2:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
+  integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
+
+etag@~1.8.1:
+  version "1.8.1"
+  resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
+  integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
+
+eventemitter3@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb"
+  integrity sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==
+
+execa@^0.7.0:
+  version "0.7.0"
+  resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
+  integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=
+  dependencies:
+    cross-spawn "^5.0.1"
+    get-stream "^3.0.0"
+    is-stream "^1.1.0"
+    npm-run-path "^2.0.0"
+    p-finally "^1.0.0"
+    signal-exit "^3.0.0"
+    strip-eof "^1.0.0"
+
+execa@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8"
+  integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==
+  dependencies:
+    cross-spawn "^6.0.0"
+    get-stream "^4.0.0"
+    is-stream "^1.1.0"
+    npm-run-path "^2.0.0"
+    p-finally "^1.0.0"
+    signal-exit "^3.0.0"
+    strip-eof "^1.0.0"
+
+exit-hook@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8"
+  integrity sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=
+
+expand-brackets@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
+  integrity sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=
+  dependencies:
+    is-posix-bracket "^0.1.0"
+
+expand-brackets@^2.1.4:
+  version "2.1.4"
+  resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622"
+  integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI=
+  dependencies:
+    debug "^2.3.3"
+    define-property "^0.2.5"
+    extend-shallow "^2.0.1"
+    posix-character-classes "^0.1.0"
+    regex-not "^1.0.0"
+    snapdragon "^0.8.1"
+    to-regex "^3.0.1"
+
+expand-range@^1.8.1:
+  version "1.8.2"
+  resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337"
+  integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=
+  dependencies:
+    fill-range "^2.1.0"
+
+expand-tilde@^1.2.2:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449"
+  integrity sha1-C4HrqJflo9MdHD0QL48BRB5VlEk=
+  dependencies:
+    os-homedir "^1.0.1"
+
+expand-tilde@^2.0.0, expand-tilde@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502"
+  integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=
+  dependencies:
+    homedir-polyfill "^1.0.1"
+
+express@^4.15.3, express@^4.8.5:
+  version "4.17.1"
+  resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
+  integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==
+  dependencies:
+    accepts "~1.3.7"
+    array-flatten "1.1.1"
+    body-parser "1.19.0"
+    content-disposition "0.5.3"
+    content-type "~1.0.4"
+    cookie "0.4.0"
+    cookie-signature "1.0.6"
+    debug "2.6.9"
+    depd "~1.1.2"
+    encodeurl "~1.0.2"
+    escape-html "~1.0.3"
+    etag "~1.8.1"
+    finalhandler "~1.1.2"
+    fresh "0.5.2"
+    merge-descriptors "1.0.1"
+    methods "~1.1.2"
+    on-finished "~2.3.0"
+    parseurl "~1.3.3"
+    path-to-regexp "0.1.7"
+    proxy-addr "~2.0.5"
+    qs "6.7.0"
+    range-parser "~1.2.1"
+    safe-buffer "5.1.2"
+    send "0.17.1"
+    serve-static "1.14.1"
+    setprototypeof "1.1.1"
+    statuses "~1.5.0"
+    type-is "~1.6.18"
+    utils-merge "1.0.1"
+    vary "~1.1.2"
+
+ext-list@^2.0.0:
+  version "2.2.2"
+  resolved "https://registry.yarnpkg.com/ext-list/-/ext-list-2.2.2.tgz#0b98e64ed82f5acf0f2931babf69212ef52ddd37"
+  integrity sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==
+  dependencies:
+    mime-db "^1.28.0"
+
+ext-name@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/ext-name/-/ext-name-3.0.0.tgz#07e4418737cb1f513c32c6ea48d8b8c8e0471abb"
+  integrity sha1-B+RBhzfLH1E8MsbqSNi4yOBHGrs=
+  dependencies:
+    ends-with "^0.2.0"
+    ext-list "^2.0.0"
+    meow "^3.1.0"
+    sort-keys-length "^1.0.0"
+
+extend-shallow@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
+  integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=
+  dependencies:
+    is-extendable "^0.1.0"
+
+extend-shallow@^3.0.0, extend-shallow@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8"
+  integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=
+  dependencies:
+    assign-symbols "^1.0.0"
+    is-extendable "^1.0.1"
+
+extend@^3.0.0, extend@~3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
+  integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
+
+external-editor@^1.1.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b"
+  integrity sha1-Etew24UPf/fnCBuvQAVwAGDEYAs=
+  dependencies:
+    extend "^3.0.0"
+    spawn-sync "^1.0.15"
+    tmp "^0.0.29"
+
+external-editor@^3.0.3:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
+  integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==
+  dependencies:
+    chardet "^0.7.0"
+    iconv-lite "^0.4.24"
+    tmp "^0.0.33"
+
+extglob@^0.3.1:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
+  integrity sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=
+  dependencies:
+    is-extglob "^1.0.0"
+
+extglob@^2.0.4:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543"
+  integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==
+  dependencies:
+    array-unique "^0.3.2"
+    define-property "^1.0.0"
+    expand-brackets "^2.1.4"
+    extend-shallow "^2.0.1"
+    fragment-cache "^0.2.1"
+    regex-not "^1.0.0"
+    snapdragon "^0.8.1"
+    to-regex "^3.0.1"
+
+extsprintf@1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
+  integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=
+
+extsprintf@^1.2.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
+  integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
+
+fast-deep-equal@^3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4"
+  integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==
+
+fast-glob@^2.0.2:
+  version "2.2.7"
+  resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d"
+  integrity sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==
+  dependencies:
+    "@mrmlnc/readdir-enhanced" "^2.2.1"
+    "@nodelib/fs.stat" "^1.1.2"
+    glob-parent "^3.1.0"
+    is-glob "^4.0.0"
+    merge2 "^1.2.3"
+    micromatch "^3.1.10"
+
+fast-json-stable-stringify@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
+  integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
+
+fast-levenshtein@^2.0.6:
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+  integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
+
+fast-safe-stringify@^2.0.4:
+  version "2.0.7"
+  resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743"
+  integrity sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==
+
+fd-slicer@~1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e"
+  integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=
+  dependencies:
+    pend "~1.2.0"
+
+feature-detect-es6@^1.3.1:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/feature-detect-es6/-/feature-detect-es6-1.5.0.tgz#a69bb7662c65f64f89f07eac5a461b649a1e0a00"
+  integrity sha512-DzWPIGzTnfp3/KK1d/YPfmgLqeDju9F2DQYBL35VusgSApcA7XGqVtXfR4ETOOFEzdFJ3J7zh0Gkk011TiA4uQ==
+  dependencies:
+    array-back "^1.0.4"
+
+fecha@^2.3.3:
+  version "2.3.3"
+  resolved "https://registry.yarnpkg.com/fecha/-/fecha-2.3.3.tgz#948e74157df1a32fd1b12c3a3c3cdcb6ec9d96cd"
+  integrity sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==
+
+figures@^1.3.5:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e"
+  integrity sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=
+  dependencies:
+    escape-string-regexp "^1.0.5"
+    object-assign "^4.1.0"
+
+figures@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962"
+  integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=
+  dependencies:
+    escape-string-regexp "^1.0.5"
+
+file-uri-to-path@1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
+  integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
+
+filename-regex@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
+  integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=
+
+fill-range@^2.1.0:
+  version "2.2.4"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565"
+  integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==
+  dependencies:
+    is-number "^2.1.0"
+    isobject "^2.0.0"
+    randomatic "^3.0.0"
+    repeat-element "^1.1.2"
+    repeat-string "^1.5.2"
+
+fill-range@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"
+  integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=
+  dependencies:
+    extend-shallow "^2.0.1"
+    is-number "^3.0.0"
+    repeat-string "^1.6.1"
+    to-regex-range "^2.1.0"
+
+filled-array@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/filled-array/-/filled-array-1.1.0.tgz#c3c4f6c663b923459a9aa29912d2d031f1507f84"
+  integrity sha1-w8T2xmO5I0WamqKZEtLQMfFQf4Q=
+
+finalhandler@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
+  integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
+  dependencies:
+    debug "2.6.9"
+    encodeurl "~1.0.2"
+    escape-html "~1.0.3"
+    on-finished "~2.3.0"
+    parseurl "~1.3.3"
+    statuses "~1.5.0"
+    unpipe "~1.0.0"
+
+find-port@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/find-port/-/find-port-1.0.1.tgz#db084a6cbf99564d99869ae79fbdecf66e8a185c"
+  integrity sha1-2whKbL+ZVk2Zhprnn73s9m6KGFw=
+  dependencies:
+    async "~0.2.9"
+
+find-replace@^1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-1.0.3.tgz#b88e7364d2d9c959559f388c66670d6130441fa0"
+  integrity sha1-uI5zZNLZyVlVnziMZmcNYTBEH6A=
+  dependencies:
+    array-back "^1.0.4"
+    test-value "^2.1.0"
+
+find-replace@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-3.0.0.tgz#3e7e23d3b05167a76f770c9fbd5258b0def68c38"
+  integrity sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==
+  dependencies:
+    array-back "^3.0.1"
+
+find-up@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
+  integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=
+  dependencies:
+    path-exists "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+find-up@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
+  integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==
+  dependencies:
+    locate-path "^3.0.0"
+
+findup-sync@^0.4.2:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12"
+  integrity sha1-QAQ5Kee8YK3wt/SCfExudaDeyhI=
+  dependencies:
+    detect-file "^0.1.0"
+    is-glob "^2.0.1"
+    micromatch "^2.3.7"
+    resolve-dir "^0.1.0"
+
+findup-sync@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc"
+  integrity sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=
+  dependencies:
+    detect-file "^1.0.0"
+    is-glob "^3.1.0"
+    micromatch "^3.0.4"
+    resolve-dir "^1.0.1"
+
+first-chunk-stream@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz#59bfb50cd905f60d7c394cd3d9acaab4e6ad934e"
+  integrity sha1-Wb+1DNkF9g18OUzT2ayqtOatk04=
+
+first-chunk-stream@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz#1bdecdb8e083c0664b91945581577a43a9f31d70"
+  integrity sha1-G97NuOCDwGZLkZRVgVd6Q6nzHXA=
+  dependencies:
+    readable-stream "^2.0.2"
+
+follow-redirects@^1.0.0:
+  version "1.10.0"
+  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.10.0.tgz#01f5263aee921c6a54fb91667f08f4155ce169eb"
+  integrity sha512-4eyLK6s6lH32nOvLLwlIOnr9zrL8Sm+OvW4pVTJNoXeGzYIkHVf+pADQi+OJ0E67hiuSLezPVPyBcIZO50TmmQ==
+  dependencies:
+    debug "^3.0.0"
+
+for-in@^1.0.1, for-in@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
+  integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=
+
+for-own@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce"
+  integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=
+  dependencies:
+    for-in "^1.0.1"
+
+forever-agent@~0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
+  integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
+
+fork-stream@^0.0.4:
+  version "0.0.4"
+  resolved "https://registry.yarnpkg.com/fork-stream/-/fork-stream-0.0.4.tgz#db849fce77f6708a5f8f386ae533a0907b54ae70"
+  integrity sha1-24Sfznf2cIpfjzhq5TOgkHtUrnA=
+
+form-data@*:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682"
+  integrity sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==
+  dependencies:
+    asynckit "^0.4.0"
+    combined-stream "^1.0.8"
+    mime-types "^2.1.12"
+
+form-data@~2.3.2:
+  version "2.3.3"
+  resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
+  integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==
+  dependencies:
+    asynckit "^0.4.0"
+    combined-stream "^1.0.6"
+    mime-types "^2.1.12"
+
+formatio@1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/formatio/-/formatio-1.2.0.tgz#f3b2167d9068c4698a8d51f4f760a39a54d818eb"
+  integrity sha1-87IWfZBoxGmKjVH092CjmlTYGOs=
+  dependencies:
+    samsam "1.x"
+
+forwarded@~0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
+  integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=
+
+fragment-cache@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
+  integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=
+  dependencies:
+    map-cache "^0.2.2"
+
+freeport@^1.0.4:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/freeport/-/freeport-1.0.5.tgz#255e8ab84170c33ba85d990e821ae5f4a1a9bc5d"
+  integrity sha1-JV6KuEFwwzuoXZkOghrl9KGpvF0=
+
+fresh@0.5.2:
+  version "0.5.2"
+  resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
+  integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
+
+fs-constants@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
+  integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
+
+fs-exists-sync@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add"
+  integrity sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=
+
+fs.realpath@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+  integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
+
+fsevents@^1.0.0:
+  version "1.2.11"
+  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.11.tgz#67bf57f4758f02ede88fb2a1712fef4d15358be3"
+  integrity sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw==
+  dependencies:
+    bindings "^1.5.0"
+    nan "^2.12.1"
+
+function-bind@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
+  integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
+
+gensync@^1.0.0-beta.1:
+  version "1.0.0-beta.1"
+  resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269"
+  integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==
+
+get-stdin@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
+  integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=
+
+get-stream@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
+  integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
+
+get-stream@^4.0.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
+  integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==
+  dependencies:
+    pump "^3.0.0"
+
+get-value@^2.0.3, get-value@^2.0.6:
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
+  integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=
+
+getpass@^0.1.1:
+  version "0.1.7"
+  resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
+  integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=
+  dependencies:
+    assert-plus "^1.0.0"
+
+gh-got@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/gh-got/-/gh-got-6.0.0.tgz#d74353004c6ec466647520a10bd46f7299d268d0"
+  integrity sha512-F/mS+fsWQMo1zfgG9MD8KWvTWPPzzhuVwY++fhQ5Ggd+0P+CAMHtzMZhNxG+TqGfHDChJKsbh6otfMGqO2AKBw==
+  dependencies:
+    got "^7.0.0"
+    is-plain-obj "^1.1.0"
+
+github-username@^4.0.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/github-username/-/github-username-4.1.0.tgz#cbe280041883206da4212ae9e4b5f169c30bf417"
+  integrity sha1-y+KABBiDIG2kISrp5LXxacML9Bc=
+  dependencies:
+    gh-got "^6.0.0"
+
+glob-base@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
+  integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=
+  dependencies:
+    glob-parent "^2.0.0"
+    is-glob "^2.0.0"
+
+glob-parent@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28"
+  integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=
+  dependencies:
+    is-glob "^2.0.0"
+
+glob-parent@^3.0.0, glob-parent@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
+  integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=
+  dependencies:
+    is-glob "^3.1.0"
+    path-dirname "^1.0.0"
+
+glob-stream@^5.3.2:
+  version "5.3.5"
+  resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-5.3.5.tgz#a55665a9a8ccdc41915a87c701e32d4e016fad22"
+  integrity sha1-pVZlqajM3EGRWofHAeMtTgFvrSI=
+  dependencies:
+    extend "^3.0.0"
+    glob "^5.0.3"
+    glob-parent "^3.0.0"
+    micromatch "^2.3.7"
+    ordered-read-streams "^0.3.0"
+    through2 "^0.6.0"
+    to-absolute-glob "^0.1.1"
+    unique-stream "^2.0.2"
+
+glob-to-regexp@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
+  integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=
+
+glob@^5.0.3:
+  version "5.0.15"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1"
+  integrity sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=
+  dependencies:
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "2 || 3"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+glob@^6.0.1:
+  version "6.0.4"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22"
+  integrity sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=
+  dependencies:
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "2 || 3"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4:
+  version "7.1.6"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
+  integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
+  dependencies:
+    fs.realpath "^1.0.0"
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "^3.0.4"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+global-dirs@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445"
+  integrity sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=
+  dependencies:
+    ini "^1.3.4"
+
+global-modules@^0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d"
+  integrity sha1-6lo77ULG1s6ZWk+KEmm12uIjgo0=
+  dependencies:
+    global-prefix "^0.1.4"
+    is-windows "^0.2.0"
+
+global-modules@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea"
+  integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==
+  dependencies:
+    global-prefix "^1.0.1"
+    is-windows "^1.0.1"
+    resolve-dir "^1.0.0"
+
+global-prefix@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f"
+  integrity sha1-jTvGuNo8qBEqFg2NSW/wRiv+948=
+  dependencies:
+    homedir-polyfill "^1.0.0"
+    ini "^1.3.4"
+    is-windows "^0.2.0"
+    which "^1.2.12"
+
+global-prefix@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe"
+  integrity sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=
+  dependencies:
+    expand-tilde "^2.0.2"
+    homedir-polyfill "^1.0.1"
+    ini "^1.3.4"
+    is-windows "^1.0.1"
+    which "^1.2.14"
+
+globals@^11.1.0:
+  version "11.12.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
+  integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
+
+globals@^9.18.0:
+  version "9.18.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a"
+  integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==
+
+globby@^4.0.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/globby/-/globby-4.1.0.tgz#080f54549ec1b82a6c60e631fc82e1211dbe95f8"
+  integrity sha1-CA9UVJ7BuCpsYOYx/ILhIR2+lfg=
+  dependencies:
+    array-union "^1.0.1"
+    arrify "^1.0.0"
+    glob "^6.0.1"
+    object-assign "^4.0.1"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+globby@^6.1.0:
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c"
+  integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=
+  dependencies:
+    array-union "^1.0.1"
+    glob "^7.0.3"
+    object-assign "^4.0.1"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+globby@^8.0.1:
+  version "8.0.2"
+  resolved "https://registry.yarnpkg.com/globby/-/globby-8.0.2.tgz#5697619ccd95c5275dbb2d6faa42087c1a941d8d"
+  integrity sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==
+  dependencies:
+    array-union "^1.0.1"
+    dir-glob "2.0.0"
+    fast-glob "^2.0.2"
+    glob "^7.1.2"
+    ignore "^3.3.5"
+    pify "^3.0.0"
+    slash "^1.0.0"
+
+got@^5.0.0:
+  version "5.7.1"
+  resolved "https://registry.yarnpkg.com/got/-/got-5.7.1.tgz#5f81635a61e4a6589f180569ea4e381680a51f35"
+  integrity sha1-X4FjWmHkplifGAVp6k44FoClHzU=
+  dependencies:
+    create-error-class "^3.0.1"
+    duplexer2 "^0.1.4"
+    is-redirect "^1.0.0"
+    is-retry-allowed "^1.0.0"
+    is-stream "^1.0.0"
+    lowercase-keys "^1.0.0"
+    node-status-codes "^1.0.0"
+    object-assign "^4.0.1"
+    parse-json "^2.1.0"
+    pinkie-promise "^2.0.0"
+    read-all-stream "^3.0.0"
+    readable-stream "^2.0.5"
+    timed-out "^3.0.0"
+    unzip-response "^1.0.2"
+    url-parse-lax "^1.0.0"
+
+got@^6.7.1:
+  version "6.7.1"
+  resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0"
+  integrity sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=
+  dependencies:
+    create-error-class "^3.0.0"
+    duplexer3 "^0.1.4"
+    get-stream "^3.0.0"
+    is-redirect "^1.0.0"
+    is-retry-allowed "^1.0.0"
+    is-stream "^1.0.0"
+    lowercase-keys "^1.0.0"
+    safe-buffer "^5.0.1"
+    timed-out "^4.0.0"
+    unzip-response "^2.0.1"
+    url-parse-lax "^1.0.0"
+
+got@^7.0.0:
+  version "7.1.0"
+  resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a"
+  integrity sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==
+  dependencies:
+    decompress-response "^3.2.0"
+    duplexer3 "^0.1.4"
+    get-stream "^3.0.0"
+    is-plain-obj "^1.1.0"
+    is-retry-allowed "^1.0.0"
+    is-stream "^1.0.0"
+    isurl "^1.0.0-alpha5"
+    lowercase-keys "^1.0.0"
+    p-cancelable "^0.3.0"
+    p-timeout "^1.1.1"
+    safe-buffer "^5.0.1"
+    timed-out "^4.0.0"
+    url-parse-lax "^1.0.0"
+    url-to-options "^1.0.1"
+
+graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.2.0:
+  version "4.2.3"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423"
+  integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==
+
+grouped-queue@^0.3.0, grouped-queue@^0.3.3:
+  version "0.3.3"
+  resolved "https://registry.yarnpkg.com/grouped-queue/-/grouped-queue-0.3.3.tgz#c167d2a5319c5a0e0964ef6a25b7c2df8996c85c"
+  integrity sha1-wWfSpTGcWg4JZO9qJbfC34mWyFw=
+  dependencies:
+    lodash "^4.17.2"
+
+gulp-if@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/gulp-if/-/gulp-if-2.0.2.tgz#a497b7e7573005041caa2bc8b7dda3c80444d629"
+  integrity sha1-pJe351cwBQQcqivIt92jyARE1ik=
+  dependencies:
+    gulp-match "^1.0.3"
+    ternary-stream "^2.0.1"
+    through2 "^2.0.1"
+
+gulp-match@^1.0.3:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/gulp-match/-/gulp-match-1.1.0.tgz#552b7080fc006ee752c90563f9fec9d61aafdf4f"
+  integrity sha512-DlyVxa1Gj24DitY2OjEsS+X6tDpretuxD6wTfhXE/Rw2hweqc1f6D/XtsJmoiCwLWfXgR87W9ozEityPCVzGtQ==
+  dependencies:
+    minimatch "^3.0.3"
+
+gulp-sourcemaps@1.6.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/gulp-sourcemaps/-/gulp-sourcemaps-1.6.0.tgz#b86ff349d801ceb56e1d9e7dc7bbcb4b7dee600c"
+  integrity sha1-uG/zSdgBzrVuHZ59x7vLS33uYAw=
+  dependencies:
+    convert-source-map "^1.1.1"
+    graceful-fs "^4.1.2"
+    strip-bom "^2.0.0"
+    through2 "^2.0.0"
+    vinyl "^1.0.0"
+
+gunzip-maybe@^1.3.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/gunzip-maybe/-/gunzip-maybe-1.4.1.tgz#39c72ed89d1b49ba708e18776500488902a52027"
+  integrity sha512-qtutIKMthNJJgeHQS7kZ9FqDq59/Wn0G2HYCRNjpup7yKfVI6/eqwpmroyZGFoCYaG+sW6psNVb4zoLADHpp2g==
+  dependencies:
+    browserify-zlib "^0.1.4"
+    is-deflate "^1.0.0"
+    is-gzip "^1.0.0"
+    peek-stream "^1.1.0"
+    pumpify "^1.3.3"
+    through2 "^2.0.3"
+
+handle-thing@^1.2.5:
+  version "1.2.5"
+  resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4"
+  integrity sha1-/Xqtcmvxpf0W38KbL3pmAdJxOcQ=
+
+har-schema@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
+  integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
+
+har-validator@~5.1.0:
+  version "5.1.3"
+  resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080"
+  integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==
+  dependencies:
+    ajv "^6.5.5"
+    har-schema "^2.0.0"
+
+has-ansi@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
+  integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=
+  dependencies:
+    ansi-regex "^2.0.0"
+
+has-binary2@~1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d"
+  integrity sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==
+  dependencies:
+    isarray "2.0.1"
+
+has-color@~0.1.0:
+  version "0.1.7"
+  resolved "https://registry.yarnpkg.com/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f"
+  integrity sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=
+
+has-cors@1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39"
+  integrity sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=
+
+has-flag@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+  integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
+
+has-flag@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
+  integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
+
+has-symbol-support-x@^1.4.1:
+  version "1.4.2"
+  resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455"
+  integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==
+
+has-symbols@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
+  integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==
+
+has-to-string-tag-x@^1.2.0:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d"
+  integrity sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==
+  dependencies:
+    has-symbol-support-x "^1.4.1"
+
+has-value@^0.3.1:
+  version "0.3.1"
+  resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
+  integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=
+  dependencies:
+    get-value "^2.0.3"
+    has-values "^0.1.4"
+    isobject "^2.0.0"
+
+has-value@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177"
+  integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=
+  dependencies:
+    get-value "^2.0.6"
+    has-values "^1.0.0"
+    isobject "^3.0.0"
+
+has-values@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771"
+  integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E=
+
+has-values@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f"
+  integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=
+  dependencies:
+    is-number "^3.0.0"
+    kind-of "^4.0.0"
+
+he@1.2.x:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
+  integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
+
+homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8"
+  integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==
+  dependencies:
+    parse-passwd "^1.0.0"
+
+hosted-git-info@^2.1.4:
+  version "2.8.5"
+  resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.5.tgz#759cfcf2c4d156ade59b0b2dfabddc42a6b9c70c"
+  integrity sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==
+
+hpack.js@^2.1.6:
+  version "2.1.6"
+  resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2"
+  integrity sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=
+  dependencies:
+    inherits "^2.0.1"
+    obuf "^1.0.0"
+    readable-stream "^2.0.1"
+    wbuf "^1.1.0"
+
+html-minifier@^3.5.10:
+  version "3.5.21"
+  resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.21.tgz#d0040e054730e354db008463593194015212d20c"
+  integrity sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==
+  dependencies:
+    camel-case "3.0.x"
+    clean-css "4.2.x"
+    commander "2.17.x"
+    he "1.2.x"
+    param-case "2.1.x"
+    relateurl "0.2.x"
+    uglify-js "3.4.x"
+
+http-deceiver@^1.2.7:
+  version "1.2.7"
+  resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87"
+  integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=
+
+http-errors@1.7.2:
+  version "1.7.2"
+  resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f"
+  integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==
+  dependencies:
+    depd "~1.1.2"
+    inherits "2.0.3"
+    setprototypeof "1.1.1"
+    statuses ">= 1.5.0 < 2"
+    toidentifier "1.0.0"
+
+http-errors@~1.6.2:
+  version "1.6.3"
+  resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
+  integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=
+  dependencies:
+    depd "~1.1.2"
+    inherits "2.0.3"
+    setprototypeof "1.1.0"
+    statuses ">= 1.4.0 < 2"
+
+http-errors@~1.7.2:
+  version "1.7.3"
+  resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06"
+  integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==
+  dependencies:
+    depd "~1.1.2"
+    inherits "2.0.4"
+    setprototypeof "1.1.1"
+    statuses ">= 1.5.0 < 2"
+    toidentifier "1.0.0"
+
+http-proxy-middleware@^0.17.2:
+  version "0.17.4"
+  resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.17.4.tgz#642e8848851d66f09d4f124912846dbaeb41b833"
+  integrity sha1-ZC6ISIUdZvCdTxJJEoRtuutBuDM=
+  dependencies:
+    http-proxy "^1.16.2"
+    is-glob "^3.1.0"
+    lodash "^4.17.2"
+    micromatch "^2.3.11"
+
+http-proxy@^1.16.2:
+  version "1.18.0"
+  resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.0.tgz#dbe55f63e75a347db7f3d99974f2692a314a6a3a"
+  integrity sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==
+  dependencies:
+    eventemitter3 "^4.0.0"
+    follow-redirects "^1.0.0"
+    requires-port "^1.0.0"
+
+http-signature@~1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
+  integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=
+  dependencies:
+    assert-plus "^1.0.0"
+    jsprim "^1.2.2"
+    sshpk "^1.7.0"
+
+https-proxy-agent@^2.2.1:
+  version "2.2.4"
+  resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b"
+  integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==
+  dependencies:
+    agent-base "^4.3.0"
+    debug "^3.1.0"
+
+https-proxy-agent@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz#b8c286433e87602311b01c8ea34413d856a4af81"
+  integrity sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==
+  dependencies:
+    agent-base "^4.3.0"
+    debug "^3.1.0"
+
+iconv-lite@0.4.24, iconv-lite@^0.4.24:
+  version "0.4.24"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
+  integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
+  dependencies:
+    safer-buffer ">= 2.1.2 < 3"
+
+ieee754@^1.1.4:
+  version "1.1.13"
+  resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84"
+  integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==
+
+ignore@^3.3.5:
+  version "3.3.10"
+  resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043"
+  integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==
+
+import-lazy@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
+  integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=
+
+imurmurhash@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
+  integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
+
+indent-string@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80"
+  integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=
+  dependencies:
+    repeating "^2.0.0"
+
+indent@0.0.2:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/indent/-/indent-0.0.2.tgz#8c79f080190559b687034b84c7aefa97d5a911d9"
+  integrity sha1-jHnwgBkFWbaHA0uEx676l9WpEdk=
+
+indexof@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
+  integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=
+
+inflight@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+  integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
+  dependencies:
+    once "^1.3.0"
+    wrappy "1"
+
+inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+  integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+
+inherits@2.0.3:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+  integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
+
+ini@^1.3.4, ini@~1.3.0:
+  version "1.3.5"
+  resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
+  integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
+
+inquirer@^1.0.2:
+  version "1.2.3"
+  resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-1.2.3.tgz#4dec6f32f37ef7bb0b2ed3f1d1a5c3f545074918"
+  integrity sha1-TexvMvN+97sLLtPx0aXD9UUHSRg=
+  dependencies:
+    ansi-escapes "^1.1.0"
+    chalk "^1.0.0"
+    cli-cursor "^1.0.1"
+    cli-width "^2.0.0"
+    external-editor "^1.1.0"
+    figures "^1.3.5"
+    lodash "^4.3.0"
+    mute-stream "0.0.6"
+    pinkie-promise "^2.0.0"
+    run-async "^2.2.0"
+    rx "^4.1.0"
+    string-width "^1.0.1"
+    strip-ansi "^3.0.0"
+    through "^2.3.6"
+
+inquirer@^6.0.0:
+  version "6.5.2"
+  resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca"
+  integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==
+  dependencies:
+    ansi-escapes "^3.2.0"
+    chalk "^2.4.2"
+    cli-cursor "^2.1.0"
+    cli-width "^2.0.0"
+    external-editor "^3.0.3"
+    figures "^2.0.0"
+    lodash "^4.17.12"
+    mute-stream "0.0.7"
+    run-async "^2.2.0"
+    rxjs "^6.4.0"
+    string-width "^2.1.0"
+    strip-ansi "^5.1.0"
+    through "^2.3.6"
+
+interpret@^1.0.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296"
+  integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==
+
+intersect@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/intersect/-/intersect-1.0.1.tgz#332650e10854d8c0ac58c192bdc27a8bf7e7a30c"
+  integrity sha1-MyZQ4QhU2MCsWMGSvcJ6i/fnoww=
+
+invariant@^2.2.2:
+  version "2.2.4"
+  resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
+  integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
+  dependencies:
+    loose-envify "^1.0.0"
+
+ipaddr.js@1.9.0:
+  version "1.9.0"
+  resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65"
+  integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==
+
+is-accessor-descriptor@^0.1.6:
+  version "0.1.6"
+  resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"
+  integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=
+  dependencies:
+    kind-of "^3.0.2"
+
+is-accessor-descriptor@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656"
+  integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==
+  dependencies:
+    kind-of "^6.0.0"
+
+is-arrayish@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+  integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
+
+is-arrayish@^0.3.1:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
+  integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==
+
+is-binary-path@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
+  integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=
+  dependencies:
+    binary-extensions "^1.0.0"
+
+is-buffer@^1.1.5, is-buffer@~1.1.1:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
+  integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
+
+is-ci@^1.0.10:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c"
+  integrity sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==
+  dependencies:
+    ci-info "^1.5.0"
+
+is-data-descriptor@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
+  integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=
+  dependencies:
+    kind-of "^3.0.2"
+
+is-data-descriptor@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7"
+  integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==
+  dependencies:
+    kind-of "^6.0.0"
+
+is-deflate@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-deflate/-/is-deflate-1.0.0.tgz#c862901c3c161fb09dac7cdc7e784f80e98f2f14"
+  integrity sha1-yGKQHDwWH7CdrHzcfnhPgOmPLxQ=
+
+is-descriptor@^0.1.0:
+  version "0.1.6"
+  resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca"
+  integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==
+  dependencies:
+    is-accessor-descriptor "^0.1.6"
+    is-data-descriptor "^0.1.4"
+    kind-of "^5.0.0"
+
+is-descriptor@^1.0.0, is-descriptor@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec"
+  integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==
+  dependencies:
+    is-accessor-descriptor "^1.0.0"
+    is-data-descriptor "^1.0.0"
+    kind-of "^6.0.2"
+
+is-dotfile@^1.0.0:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1"
+  integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=
+
+is-equal-shallow@^0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534"
+  integrity sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=
+  dependencies:
+    is-primitive "^2.0.0"
+
+is-extendable@^0.1.0, is-extendable@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
+  integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=
+
+is-extendable@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4"
+  integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==
+  dependencies:
+    is-plain-object "^2.0.4"
+
+is-extglob@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
+  integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=
+
+is-extglob@^2.1.0, is-extglob@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+  integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
+
+is-finite@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
+  integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=
+  dependencies:
+    number-is-nan "^1.0.0"
+
+is-fullwidth-code-point@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
+  integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs=
+  dependencies:
+    number-is-nan "^1.0.0"
+
+is-fullwidth-code-point@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
+  integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
+
+is-glob@^2.0.0, is-glob@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
+  integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=
+  dependencies:
+    is-extglob "^1.0.0"
+
+is-glob@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
+  integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=
+  dependencies:
+    is-extglob "^2.1.0"
+
+is-glob@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
+  integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
+  dependencies:
+    is-extglob "^2.1.1"
+
+is-gzip@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-gzip/-/is-gzip-1.0.0.tgz#6ca8b07b99c77998025900e555ced8ed80879a83"
+  integrity sha1-bKiwe5nHeZgCWQDlVc7Y7YCHmoM=
+
+is-installed-globally@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80"
+  integrity sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=
+  dependencies:
+    global-dirs "^0.1.0"
+    is-path-inside "^1.0.0"
+
+is-module@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
+  integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=
+
+is-npm@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4"
+  integrity sha1-8vtjpl5JBbQGyGBydloaTceTufQ=
+
+is-number@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
+  integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=
+  dependencies:
+    kind-of "^3.0.2"
+
+is-number@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
+  integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=
+  dependencies:
+    kind-of "^3.0.2"
+
+is-number@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff"
+  integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==
+
+is-obj@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
+  integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8=
+
+is-object@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470"
+  integrity sha1-iVJojF7C/9awPsyF52ngKQMINHA=
+
+is-path-cwd@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d"
+  integrity sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=
+
+is-path-in-cwd@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52"
+  integrity sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==
+  dependencies:
+    is-path-inside "^1.0.0"
+
+is-path-inside@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036"
+  integrity sha1-jvW33lBDej/cprToZe96pVy0gDY=
+  dependencies:
+    path-is-inside "^1.0.1"
+
+is-plain-obj@^1.0.0, is-plain-obj@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
+  integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4=
+
+is-plain-object@^2.0.3, is-plain-object@^2.0.4:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
+  integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==
+  dependencies:
+    isobject "^3.0.1"
+
+is-plain-object@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-3.0.0.tgz#47bfc5da1b5d50d64110806c199359482e75a928"
+  integrity sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==
+  dependencies:
+    isobject "^4.0.0"
+
+is-posix-bracket@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
+  integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=
+
+is-potential-custom-element-name@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz#0c52e54bcca391bb2c494b21e8626d7336c6e397"
+  integrity sha1-DFLlS8yjkbssSUsh6GJtczbG45c=
+
+is-primitive@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
+  integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU=
+
+is-promise@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa"
+  integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=
+
+is-redirect@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24"
+  integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=
+
+is-retry-allowed@^1.0.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4"
+  integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==
+
+is-scoped@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-scoped/-/is-scoped-1.0.0.tgz#449ca98299e713038256289ecb2b540dc437cb30"
+  integrity sha1-RJypgpnnEwOCViieyytUDcQ3yzA=
+  dependencies:
+    scoped-regex "^1.0.0"
+
+is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
+  integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
+
+is-typedarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
+  integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
+
+is-utf8@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
+  integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=
+
+is-valid-glob@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-0.3.0.tgz#d4b55c69f51886f9b65c70d6c2622d37e29f48fe"
+  integrity sha1-1LVcafUYhvm2XHDWwmItN+KfSP4=
+
+is-windows@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c"
+  integrity sha1-3hqm1j6indJIc3tp8f+LgALSEIw=
+
+is-windows@^1.0.1, is-windows@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
+  integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
+
+isarray@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
+  integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
+
+isarray@1.0.0, isarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+  integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
+
+isarray@2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e"
+  integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=
+
+isbinaryfile@^3.0.2:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.3.tgz#5d6def3edebf6e8ca8cae9c30183a804b5f8be80"
+  integrity sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==
+  dependencies:
+    buffer-alloc "^1.2.0"
+
+isexe@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+  integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
+
+isobject@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
+  integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=
+  dependencies:
+    isarray "1.0.0"
+
+isobject@^3.0.0, isobject@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
+  integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
+
+isobject@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/isobject/-/isobject-4.0.0.tgz#3f1c9155e73b192022a80819bacd0343711697b0"
+  integrity sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==
+
+isstream@~0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
+  integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
+
+istextorbinary@^2.2.1:
+  version "2.6.0"
+  resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.6.0.tgz#60776315fb0fa3999add276c02c69557b9ca28ab"
+  integrity sha512-+XRlFseT8B3L9KyjxxLjfXSLMuErKDsd8DBNrsaxoViABMEZlOSCstwmw0qpoFX3+U6yWU1yhLudAe6/lETGGA==
+  dependencies:
+    binaryextensions "^2.1.2"
+    editions "^2.2.0"
+    textextensions "^2.5.0"
+
+isurl@^1.0.0-alpha5:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67"
+  integrity sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==
+  dependencies:
+    has-to-string-tag-x "^1.2.0"
+    is-object "^1.0.1"
+
+jest-worker@^24.9.0:
+  version "24.9.0"
+  resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5"
+  integrity sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==
+  dependencies:
+    merge-stream "^2.0.0"
+    supports-color "^6.1.0"
+
+"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+  integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
+
+js-tokens@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
+  integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls=
+
+jsbn@~0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
+  integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
+
+jsesc@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b"
+  integrity sha1-RsP+yMGJKxKwgz25vHYiF226s0s=
+
+jsesc@^2.5.1:
+  version "2.5.2"
+  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
+  integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
+
+jsesc@~0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
+  integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=
+
+json-parse-better-errors@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
+  integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
+
+json-schema-traverse@^0.4.1:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
+  integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
+
+json-schema@0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
+  integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
+
+json-stable-stringify-without-jsonify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
+  integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
+
+json-stringify-safe@~5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
+  integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
+
+json5@^2.1.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.1.tgz#81b6cb04e9ba496f1c7005d07b4368a2638f90b6"
+  integrity sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==
+  dependencies:
+    minimist "^1.2.0"
+
+jsonschema@^1.1.0, jsonschema@^1.1.1:
+  version "1.2.5"
+  resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.2.5.tgz#bab69d97fa28946aec0a56a9cc266d23fe80ae61"
+  integrity sha512-kVTF+08x25PQ0CjuVc0gRM9EUPb0Fe9Ln/utFOgcdxEIOHuU7ooBk/UPTd7t1M91pP35m0MU1T8M5P7vP1bRRw==
+
+jsprim@^1.2.2:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
+  integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=
+  dependencies:
+    assert-plus "1.0.0"
+    extsprintf "1.3.0"
+    json-schema "0.2.3"
+    verror "1.10.0"
+
+kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
+  version "3.2.2"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
+  integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=
+  dependencies:
+    is-buffer "^1.1.5"
+
+kind-of@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57"
+  integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc=
+  dependencies:
+    is-buffer "^1.1.5"
+
+kind-of@^5.0.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d"
+  integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==
+
+kind-of@^6.0.0, kind-of@^6.0.2:
+  version "6.0.3"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
+  integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
+
+kuler@1.0.x:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/kuler/-/kuler-1.0.1.tgz#ef7c784f36c9fb6e16dd3150d152677b2b0228a6"
+  integrity sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==
+  dependencies:
+    colornames "^1.1.1"
+
+latest-version@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-2.0.0.tgz#56f8d6139620847b8017f8f1f4d78e211324168b"
+  integrity sha1-VvjWE5YghHuAF/jx9NeOIRMkFos=
+  dependencies:
+    package-json "^2.0.0"
+
+latest-version@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15"
+  integrity sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=
+  dependencies:
+    package-json "^4.0.0"
+
+launchpad@^0.7.0:
+  version "0.7.5"
+  resolved "https://registry.yarnpkg.com/launchpad/-/launchpad-0.7.5.tgz#a16950c937572f10ef01c9be945a96f7aef8e427"
+  integrity sha512-gsYFgT8XKL3X2XZHPPPrgwM0JqeQwGpSWnzg7EYadBY3MirbQrTVq6L4fm6l7UE2T+7gnfuhiGkKr/xxuU/fdw==
+  dependencies:
+    async "^2.0.1"
+    browserstack "^1.2.0"
+    debug "^2.2.0"
+    mkdirp "^0.5.1"
+    plist "^2.0.1"
+    q "^1.4.1"
+    rimraf "^3.0.0"
+    underscore "^1.8.3"
+
+lazy-req@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/lazy-req/-/lazy-req-1.1.0.tgz#bdaebead30f8d824039ce0ce149d4daa07ba1fac"
+  integrity sha1-va6+rTD42CQDnODOFJ1Nqge6H6w=
+
+lazystream@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4"
+  integrity sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=
+  dependencies:
+    readable-stream "^2.0.5"
+
+load-json-file@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
+  integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=
+  dependencies:
+    graceful-fs "^4.1.2"
+    parse-json "^2.2.0"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+    strip-bom "^2.0.0"
+
+load-json-file@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b"
+  integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs=
+  dependencies:
+    graceful-fs "^4.1.2"
+    parse-json "^4.0.0"
+    pify "^3.0.0"
+    strip-bom "^3.0.0"
+
+locate-path@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
+  integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==
+  dependencies:
+    p-locate "^3.0.0"
+    path-exists "^3.0.0"
+
+lodash._reinterpolate@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
+  integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=
+
+lodash.camelcase@^4.3.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
+  integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY=
+
+lodash.defaults@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
+  integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=
+
+lodash.difference@^4.5.0:
+  version "4.5.0"
+  resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c"
+  integrity sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=
+
+lodash.flatten@^4.4.0:
+  version "4.4.0"
+  resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f"
+  integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=
+
+lodash.get@^4.4.2:
+  version "4.4.2"
+  resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
+  integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=
+
+lodash.isequal@^4.0.0:
+  version "4.5.0"
+  resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
+  integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
+
+lodash.isplainobject@^4.0.6:
+  version "4.0.6"
+  resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
+  integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=
+
+lodash.padend@^4.6.1:
+  version "4.6.1"
+  resolved "https://registry.yarnpkg.com/lodash.padend/-/lodash.padend-4.6.1.tgz#53ccba047d06e158d311f45da625f4e49e6f166e"
+  integrity sha1-U8y6BH0G4VjTEfRdpiX05J5vFm4=
+
+lodash.set@^4.3.2:
+  version "4.3.2"
+  resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23"
+  integrity sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=
+
+lodash.sortby@^4.7.0:
+  version "4.7.0"
+  resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
+  integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
+
+lodash.template@^4.4.0:
+  version "4.5.0"
+  resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab"
+  integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==
+  dependencies:
+    lodash._reinterpolate "^3.0.0"
+    lodash.templatesettings "^4.0.0"
+
+lodash.templatesettings@^4.0.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33"
+  integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==
+  dependencies:
+    lodash._reinterpolate "^3.0.0"
+
+lodash.union@^4.6.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88"
+  integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=
+
+lodash.uniq@^4.5.0:
+  version "4.5.0"
+  resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
+  integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
+
+lodash@^3.0.0, lodash@^3.10.1:
+  version "3.10.1"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
+  integrity sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=
+
+lodash@^4.0.0, lodash@^4.11.1, lodash@^4.16.6, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.3.0:
+  version "4.17.15"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
+  integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
+
+log-symbols@^1.0.0, log-symbols@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18"
+  integrity sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=
+  dependencies:
+    chalk "^1.0.0"
+
+log-symbols@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a"
+  integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==
+  dependencies:
+    chalk "^2.0.1"
+
+logform@^1.9.1:
+  version "1.10.0"
+  resolved "https://registry.yarnpkg.com/logform/-/logform-1.10.0.tgz#c9d5598714c92b546e23f4e78147c40f1e02012e"
+  integrity sha512-em5ojIhU18fIMOw/333mD+ZLE2fis0EzXl1ZwHx4iQzmpQi6odNiY/t+ITNr33JZhT9/KEaH+UPIipr6a9EjWg==
+  dependencies:
+    colors "^1.2.1"
+    fast-safe-stringify "^2.0.4"
+    fecha "^2.3.3"
+    ms "^2.1.1"
+    triple-beam "^1.2.0"
+
+logform@^2.1.1:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/logform/-/logform-2.1.2.tgz#957155ebeb67a13164069825ce67ddb5bb2dd360"
+  integrity sha512-+lZh4OpERDBLqjiwDLpAWNQu6KMjnlXH2ByZwCuSqVPJletw0kTWJf5CgSNAUKn1KUkv3m2cUz/LK8zyEy7wzQ==
+  dependencies:
+    colors "^1.2.1"
+    fast-safe-stringify "^2.0.4"
+    fecha "^2.3.3"
+    ms "^2.1.1"
+    triple-beam "^1.3.0"
+
+lolex@^1.6.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/lolex/-/lolex-1.6.0.tgz#3a9a0283452a47d7439e72731b9e07d7386e49f6"
+  integrity sha1-OpoCg0UqR9dDnnJzG54H1zhuSfY=
+
+long@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28"
+  integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==
+
+loose-envify@^1.0.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
+  integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
+  dependencies:
+    js-tokens "^3.0.0 || ^4.0.0"
+
+loud-rejection@^1.0.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
+  integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=
+  dependencies:
+    currently-unhandled "^0.4.1"
+    signal-exit "^3.0.0"
+
+lower-case@^1.1.1:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac"
+  integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw=
+
+lowercase-keys@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
+  integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==
+
+lru-cache@^4.0.1, lru-cache@^4.0.2:
+  version "4.1.5"
+  resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
+  integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
+  dependencies:
+    pseudomap "^1.0.2"
+    yallist "^2.1.2"
+
+macos-release@^2.2.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.3.0.tgz#eb1930b036c0800adebccd5f17bc4c12de8bb71f"
+  integrity sha512-OHhSbtcviqMPt7yfw5ef5aghS2jzFVKEFyCJndQt2YpSQ9qRVSEv2axSJI1paVThEu+FFGs584h/1YhxjVqajA==
+
+magic-string@^0.22.4:
+  version "0.22.5"
+  resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.22.5.tgz#8e9cf5afddf44385c1da5bc2a6a0dbd10b03657e"
+  integrity sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==
+  dependencies:
+    vlq "^0.2.2"
+
+make-dir@^1.0.0, make-dir@^1.1.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c"
+  integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==
+  dependencies:
+    pify "^3.0.0"
+
+map-cache@^0.2.2:
+  version "0.2.2"
+  resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
+  integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=
+
+map-obj@^1.0.0, map-obj@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
+  integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=
+
+map-visit@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f"
+  integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=
+  dependencies:
+    object-visit "^1.0.0"
+
+matcher@^1.1.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/matcher/-/matcher-1.1.1.tgz#51d8301e138f840982b338b116bb0c09af62c1c2"
+  integrity sha512-+BmqxWIubKTRKNWx/ahnCkk3mG8m7OturVlqq6HiojGJTd5hVYbgZm6WzcYPCoB+KBT4Vd6R7WSRG2OADNaCjg==
+  dependencies:
+    escape-string-regexp "^1.0.4"
+
+math-random@^1.0.1:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c"
+  integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==
+
+md5@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9"
+  integrity sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=
+  dependencies:
+    charenc "~0.0.1"
+    crypt "~0.0.1"
+    is-buffer "~1.1.1"
+
+media-typer@0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
+  integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
+
+mem-fs-editor@^5.0.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/mem-fs-editor/-/mem-fs-editor-5.1.0.tgz#51972241640be8567680a04f7adaffe5fc603667"
+  integrity sha512-2Yt2GCYEbcotYbIJagmow4gEtHDqzpq5XN94+yAx/NT5+bGqIjkXnm3KCUQfE6kRfScGp9IZknScoGRKu8L78w==
+  dependencies:
+    commondir "^1.0.1"
+    deep-extend "^0.6.0"
+    ejs "^2.5.9"
+    glob "^7.0.3"
+    globby "^8.0.1"
+    isbinaryfile "^3.0.2"
+    mkdirp "^0.5.0"
+    multimatch "^2.0.0"
+    rimraf "^2.2.8"
+    through2 "^2.0.0"
+    vinyl "^2.0.1"
+
+mem-fs@^1.1.0:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/mem-fs/-/mem-fs-1.1.3.tgz#b8ae8d2e3fcb6f5d3f9165c12d4551a065d989cc"
+  integrity sha1-uK6NLj/Lb10/kWXBLUVRoGXZicw=
+  dependencies:
+    through2 "^2.0.0"
+    vinyl "^1.1.0"
+    vinyl-file "^2.0.0"
+
+meow@^3.1.0, meow@^3.7.0:
+  version "3.7.0"
+  resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb"
+  integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=
+  dependencies:
+    camelcase-keys "^2.0.0"
+    decamelize "^1.1.2"
+    loud-rejection "^1.0.0"
+    map-obj "^1.0.1"
+    minimist "^1.1.3"
+    normalize-package-data "^2.3.4"
+    object-assign "^4.0.1"
+    read-pkg-up "^1.0.1"
+    redent "^1.0.0"
+    trim-newlines "^1.0.0"
+
+merge-descriptors@1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
+  integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
+
+merge-stream@^1.0.0, merge-stream@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1"
+  integrity sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=
+  dependencies:
+    readable-stream "^2.0.1"
+
+merge-stream@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
+  integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
+
+merge2@^1.2.3:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81"
+  integrity sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==
+
+methods@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
+  integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
+
+micromatch@^2.1.5, micromatch@^2.3.11, micromatch@^2.3.7:
+  version "2.3.11"
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
+  integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=
+  dependencies:
+    arr-diff "^2.0.0"
+    array-unique "^0.2.1"
+    braces "^1.8.2"
+    expand-brackets "^0.1.4"
+    extglob "^0.3.1"
+    filename-regex "^2.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.1"
+    kind-of "^3.0.2"
+    normalize-path "^2.0.1"
+    object.omit "^2.0.0"
+    parse-glob "^3.0.4"
+    regex-cache "^0.4.2"
+
+micromatch@^3.0.4, micromatch@^3.1.10:
+  version "3.1.10"
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
+  integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==
+  dependencies:
+    arr-diff "^4.0.0"
+    array-unique "^0.3.2"
+    braces "^2.3.1"
+    define-property "^2.0.2"
+    extend-shallow "^3.0.2"
+    extglob "^2.0.4"
+    fragment-cache "^0.2.1"
+    kind-of "^6.0.2"
+    nanomatch "^1.2.9"
+    object.pick "^1.3.0"
+    regex-not "^1.0.0"
+    snapdragon "^0.8.1"
+    to-regex "^3.0.2"
+
+mime-db@1.43.0, "mime-db@>= 1.43.0 < 2", mime-db@^1.28.0:
+  version "1.43.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58"
+  integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==
+
+mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24:
+  version "2.1.26"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06"
+  integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==
+  dependencies:
+    mime-db "1.43.0"
+
+mime@1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
+  integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==
+
+mime@1.6.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
+  integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
+
+mime@^2.3.1:
+  version "2.4.4"
+  resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5"
+  integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==
+
+mimic-fn@^1.0.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
+  integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
+
+mimic-response@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
+  integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
+
+minimalistic-assert@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
+  integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
+
+minimatch-all@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/minimatch-all/-/minimatch-all-1.1.0.tgz#40c496a27a2e128d19bf758e76bb01a0c7145787"
+  integrity sha1-QMSWonouEo0Zv3WOdrsBoMcUV4c=
+  dependencies:
+    minimatch "^3.0.2"
+
+"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
+  integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
+  dependencies:
+    brace-expansion "^1.1.7"
+
+minimist@0.0.8:
+  version "0.0.8"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
+  integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
+
+minimist@^1.1.3, minimist@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
+  integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
+
+minimist@~0.0.1:
+  version "0.0.10"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
+  integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=
+
+mixin-deep@^1.2.0:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
+  integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==
+  dependencies:
+    for-in "^1.0.2"
+    is-extendable "^1.0.1"
+
+mkdirp@^0.5.0, mkdirp@^0.5.1:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
+  integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
+  dependencies:
+    minimist "0.0.8"
+
+mout@^1.0.0:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/mout/-/mout-1.2.2.tgz#c9b718a499806a0632cede178e80f436259e777d"
+  integrity sha512-w0OUxFEla6z3d7sVpMZGBCpQvYh8PHS1wZ6Wu9GNKHMpAHWJ0if0LsQZh3DlOqw55HlhJEOMLpFnwtxp99Y5GA==
+
+ms@2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+  integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
+
+ms@2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
+  integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
+
+ms@^2.1.1:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
+  integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+
+multer@^1.3.0:
+  version "1.4.2"
+  resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.2.tgz#2f1f4d12dbaeeba74cb37e623f234bf4d3d2057a"
+  integrity sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg==
+  dependencies:
+    append-field "^1.0.0"
+    busboy "^0.2.11"
+    concat-stream "^1.5.2"
+    mkdirp "^0.5.1"
+    object-assign "^4.1.1"
+    on-finished "^2.3.0"
+    type-is "^1.6.4"
+    xtend "^4.0.0"
+
+multimatch@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-2.1.0.tgz#9c7906a22fb4c02919e2f5f75161b4cdbd4b2a2b"
+  integrity sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=
+  dependencies:
+    array-differ "^1.0.0"
+    array-union "^1.0.1"
+    arrify "^1.0.0"
+    minimatch "^3.0.0"
+
+multipipe@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-1.0.2.tgz#cc13efd833c9cda99f224f868461b8e1a3fd939d"
+  integrity sha1-zBPv2DPJzamfIk+GhGG44aP9k50=
+  dependencies:
+    duplexer2 "^0.1.2"
+    object-assign "^4.1.0"
+
+mute-stream@0.0.6:
+  version "0.0.6"
+  resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db"
+  integrity sha1-SJYrGeFp/R38JAs/HnMXYnu8R9s=
+
+mute-stream@0.0.7:
+  version "0.0.7"
+  resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
+  integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=
+
+mz@^2.4.0, mz@^2.6.0:
+  version "2.7.0"
+  resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32"
+  integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==
+  dependencies:
+    any-promise "^1.0.0"
+    object-assign "^4.0.1"
+    thenify-all "^1.0.0"
+
+nan@^2.12.1:
+  version "2.14.0"
+  resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
+  integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
+
+nanomatch@^1.2.9:
+  version "1.2.13"
+  resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
+  integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==
+  dependencies:
+    arr-diff "^4.0.0"
+    array-unique "^0.3.2"
+    define-property "^2.0.2"
+    extend-shallow "^3.0.2"
+    fragment-cache "^0.2.1"
+    is-windows "^1.0.2"
+    kind-of "^6.0.2"
+    object.pick "^1.3.0"
+    regex-not "^1.0.0"
+    snapdragon "^0.8.1"
+    to-regex "^3.0.1"
+
+native-promise-only@^0.8.1:
+  version "0.8.1"
+  resolved "https://registry.yarnpkg.com/native-promise-only/-/native-promise-only-0.8.1.tgz#20a318c30cb45f71fe7adfbf7b21c99c1472ef11"
+  integrity sha1-IKMYwwy0X3H+et+/eyHJnBRy7xE=
+
+negotiator@0.6.2:
+  version "0.6.2"
+  resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
+  integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
+
+nice-try@^1.0.4:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
+  integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
+
+no-case@^2.2.0:
+  version "2.3.2"
+  resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac"
+  integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==
+  dependencies:
+    lower-case "^1.1.1"
+
+node-fetch@^2.3.0:
+  version "2.6.0"
+  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
+  integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
+
+node-status-codes@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/node-status-codes/-/node-status-codes-1.0.0.tgz#5ae5541d024645d32a58fcddc9ceecea7ae3ac2f"
+  integrity sha1-WuVUHQJGRdMqWPzdyc7s6nrjrC8=
+
+nomnom@^1.8.1:
+  version "1.8.1"
+  resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.8.1.tgz#2151f722472ba79e50a76fc125bb8c8f2e4dc2a7"
+  integrity sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=
+  dependencies:
+    chalk "~0.4.0"
+    underscore "~1.6.0"
+
+normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
+  version "2.5.0"
+  resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
+  integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
+  dependencies:
+    hosted-git-info "^2.1.4"
+    resolve "^1.10.0"
+    semver "2 || 3 || 4 || 5"
+    validate-npm-package-license "^3.0.1"
+
+normalize-path@^2.0.0, normalize-path@^2.0.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
+  integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=
+  dependencies:
+    remove-trailing-separator "^1.0.1"
+
+normalize-path@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
+  integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
+
+npm-run-path@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
+  integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=
+  dependencies:
+    path-key "^2.0.0"
+
+number-is-nan@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
+  integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
+
+oauth-sign@~0.9.0:
+  version "0.9.0"
+  resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
+  integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
+
+object-assign@^4, object-assign@^4.0.0, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+  integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
+
+object-component@0.0.3:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291"
+  integrity sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=
+
+object-copy@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
+  integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw=
+  dependencies:
+    copy-descriptor "^0.1.0"
+    define-property "^0.2.5"
+    kind-of "^3.0.3"
+
+object-keys@^1.0.11, object-keys@^1.0.12:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
+  integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
+
+object-visit@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
+  integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=
+  dependencies:
+    isobject "^3.0.0"
+
+object.assign@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da"
+  integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==
+  dependencies:
+    define-properties "^1.1.2"
+    function-bind "^1.1.1"
+    has-symbols "^1.0.0"
+    object-keys "^1.0.11"
+
+object.omit@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
+  integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=
+  dependencies:
+    for-own "^0.1.4"
+    is-extendable "^0.1.1"
+
+object.pick@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
+  integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=
+  dependencies:
+    isobject "^3.0.1"
+
+obuf@^1.0.0, obuf@^1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e"
+  integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==
+
+octokit-pagination-methods@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz#cf472edc9d551055f9ef73f6e42b4dbb4c80bea4"
+  integrity sha512-fZ4qZdQ2nxJvtcasX7Ghl+WlWS/d9IgnBIwFZXVNNZUmzpno91SX5bc5vuxiuKoCtK78XxGGNuSCrDC7xYB3OQ==
+
+on-finished@^2.3.0, on-finished@~2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
+  integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=
+  dependencies:
+    ee-first "1.1.1"
+
+on-headers@~1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
+  integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
+
+once@^1.3.0, once@^1.3.1, once@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+  integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
+  dependencies:
+    wrappy "1"
+
+one-time@0.0.4:
+  version "0.0.4"
+  resolved "https://registry.yarnpkg.com/one-time/-/one-time-0.0.4.tgz#f8cdf77884826fe4dff93e3a9cc37b1e4480742e"
+  integrity sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=
+
+onetime@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789"
+  integrity sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=
+
+onetime@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4"
+  integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=
+  dependencies:
+    mimic-fn "^1.0.0"
+
+opn@^3.0.2:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/opn/-/opn-3.0.3.tgz#b6d99e7399f78d65c3baaffef1fb288e9b85243a"
+  integrity sha1-ttmec5n3jWXDuq/+8fsojpuFJDo=
+  dependencies:
+    object-assign "^4.0.1"
+
+optimist@^0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
+  integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY=
+  dependencies:
+    minimist "~0.0.1"
+    wordwrap "~0.0.2"
+
+ordered-read-streams@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz#7137e69b3298bb342247a1bbee3881c80e2fd78b"
+  integrity sha1-cTfmmzKYuzQiR6G77jiByA4v14s=
+  dependencies:
+    is-stream "^1.0.1"
+    readable-stream "^2.0.1"
+
+os-homedir@^1.0.0, os-homedir@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
+  integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
+
+os-name@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/os-name/-/os-name-3.1.0.tgz#dec19d966296e1cd62d701a5a66ee1ddeae70801"
+  integrity sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg==
+  dependencies:
+    macos-release "^2.2.0"
+    windows-release "^3.1.0"
+
+os-shim@^0.1.2:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917"
+  integrity sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=
+
+os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+  integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
+
+osenv@^0.1.0, osenv@^0.1.3:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
+  integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==
+  dependencies:
+    os-homedir "^1.0.0"
+    os-tmpdir "^1.0.0"
+
+p-cancelable@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa"
+  integrity sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==
+
+p-finally@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
+  integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
+
+p-limit@^2.0.0:
+  version "2.2.2"
+  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e"
+  integrity sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==
+  dependencies:
+    p-try "^2.0.0"
+
+p-locate@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
+  integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==
+  dependencies:
+    p-limit "^2.0.0"
+
+p-map@^1.1.1:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b"
+  integrity sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==
+
+p-timeout@^1.1.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386"
+  integrity sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=
+  dependencies:
+    p-finally "^1.0.0"
+
+p-try@^2.0.0, p-try@^2.1.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
+  integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
+
+package-json@^2.0.0:
+  version "2.4.0"
+  resolved "https://registry.yarnpkg.com/package-json/-/package-json-2.4.0.tgz#0d15bd67d1cbbddbb2ca222ff2edb86bcb31a8bb"
+  integrity sha1-DRW9Z9HLvduyyiIv8u24a8sxqLs=
+  dependencies:
+    got "^5.0.0"
+    registry-auth-token "^3.0.1"
+    registry-url "^3.0.3"
+    semver "^5.1.0"
+
+package-json@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed"
+  integrity sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=
+  dependencies:
+    got "^6.7.1"
+    registry-auth-token "^3.0.1"
+    registry-url "^3.0.3"
+    semver "^5.1.0"
+
+pako@~0.2.0:
+  version "0.2.9"
+  resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
+  integrity sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=
+
+param-case@2.1.x:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247"
+  integrity sha1-35T9jPZTHs915r75oIWPvHK+Ikc=
+  dependencies:
+    no-case "^2.2.0"
+
+parse-glob@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
+  integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw=
+  dependencies:
+    glob-base "^0.3.0"
+    is-dotfile "^1.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.0"
+
+parse-json@^2.1.0, parse-json@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
+  integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=
+  dependencies:
+    error-ex "^1.2.0"
+
+parse-json@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
+  integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=
+  dependencies:
+    error-ex "^1.3.1"
+    json-parse-better-errors "^1.0.1"
+
+parse-passwd@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
+  integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=
+
+parse5@^1.4.1:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94"
+  integrity sha1-m387DeMr543CQBsXVzzK8Pb1nZQ=
+
+parse5@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608"
+  integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==
+
+parseqs@0.0.5:
+  version "0.0.5"
+  resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d"
+  integrity sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=
+  dependencies:
+    better-assert "~1.0.0"
+
+parseuri@0.0.5:
+  version "0.0.5"
+  resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a"
+  integrity sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=
+  dependencies:
+    better-assert "~1.0.0"
+
+parseurl@~1.3.3:
+  version "1.3.3"
+  resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
+  integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
+
+pascalcase@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
+  integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=
+
+path-dirname@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
+  integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=
+
+path-exists@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
+  integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=
+  dependencies:
+    pinkie-promise "^2.0.0"
+
+path-exists@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
+  integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=
+
+path-is-absolute@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+  integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
+
+path-is-inside@^1.0.1, path-is-inside@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
+  integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=
+
+path-key@^2.0.0, path-key@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
+  integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
+
+path-parse@^1.0.6:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
+  integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
+
+path-to-regexp@0.1.7:
+  version "0.1.7"
+  resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
+  integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
+
+path-to-regexp@^1.0.1, path-to-regexp@^1.7.0:
+  version "1.8.0"
+  resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a"
+  integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==
+  dependencies:
+    isarray "0.0.1"
+
+path-type@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
+  integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=
+  dependencies:
+    graceful-fs "^4.1.2"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+path-type@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
+  integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==
+  dependencies:
+    pify "^3.0.0"
+
+peek-stream@^1.1.0:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/peek-stream/-/peek-stream-1.1.3.tgz#3b35d84b7ccbbd262fff31dc10da56856ead6d67"
+  integrity sha512-FhJ+YbOSBb9/rIl2ZeE/QHEsWn7PqNYt8ARAY3kIgNGOk13g9FGyIY6JIl/xB/3TFRVoTv5as0l11weORrTekA==
+  dependencies:
+    buffer-from "^1.0.0"
+    duplexify "^3.5.0"
+    through2 "^2.0.3"
+
+pem@^1.8.3:
+  version "1.14.4"
+  resolved "https://registry.yarnpkg.com/pem/-/pem-1.14.4.tgz#a68c70c6e751ccc5b3b5bcd7af78b0aec1177ff9"
+  integrity sha512-v8lH3NpirgiEmbOqhx0vwQTxwi0ExsiWBGYh0jYNq7K6mQuO4gI6UEFlr6fLAdv9TPXRt6GqiwE37puQdIDS8g==
+  dependencies:
+    es6-promisify "^6.0.0"
+    md5 "^2.2.1"
+    os-tmpdir "^1.0.1"
+    which "^2.0.2"
+
+pend@~1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
+  integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA=
+
+performance-now@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
+  integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
+
+pify@^2.0.0, pify@^2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
+  integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
+
+pify@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
+  integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
+
+pify@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
+  integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==
+
+pinkie-promise@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
+  integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o=
+  dependencies:
+    pinkie "^2.0.0"
+
+pinkie@^2.0.0:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
+  integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
+
+plist@^2.0.1:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/plist/-/plist-2.1.0.tgz#57ccdb7a0821df21831217a3cad54e3e146a1025"
+  integrity sha1-V8zbeggh3yGDEhejytVOPhRqECU=
+  dependencies:
+    base64-js "1.2.0"
+    xmlbuilder "8.2.2"
+    xmldom "0.1.x"
+
+plylog@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/plylog/-/plylog-1.1.0.tgz#f6f354e2ae0b01f6db4ed111f4b3855da9c37417"
+  integrity sha512-/QnY5aSVaP54va6hruzNtAj02HpsLlAt7V5EndMrtq6ZUTZJKUja43rgiUtGXqm95yrSJjbZoPW0yQQQwLpoJA==
+  dependencies:
+    logform "^1.9.1"
+    winston "^3.0.0"
+    winston-transport "^4.2.0"
+
+polymer-analyzer@^3.0.0, polymer-analyzer@^3.1.3, polymer-analyzer@^3.2.2:
+  version "3.2.4"
+  resolved "https://registry.yarnpkg.com/polymer-analyzer/-/polymer-analyzer-3.2.4.tgz#7d76356620a2328e8bc9e30e47069f9729260ca1"
+  integrity sha512-JmxUhMajTuC18tLXbTtu2+aN2x9bTX+4MvCD4IZKJ0rtAL8jWi1iRLfogpHJB4Ig9Dc8EEEuEYipLuzPFl3vqA==
+  dependencies:
+    "@babel/generator" "^7.0.0-beta.42"
+    "@babel/traverse" "^7.0.0-beta.42"
+    "@babel/types" "^7.0.0-beta.42"
+    "@types/babel-generator" "^6.25.1"
+    "@types/babel-traverse" "^6.25.2"
+    "@types/babel-types" "^6.25.1"
+    "@types/babylon" "^6.16.2"
+    "@types/chai-subset" "^1.3.0"
+    "@types/chalk" "^0.4.30"
+    "@types/clone" "^0.1.30"
+    "@types/cssbeautify" "^0.3.1"
+    "@types/doctrine" "^0.0.1"
+    "@types/is-windows" "^0.2.0"
+    "@types/minimatch" "^3.0.1"
+    "@types/parse5" "^2.2.34"
+    "@types/path-is-inside" "^1.0.0"
+    "@types/resolve" "0.0.6"
+    "@types/whatwg-url" "^6.4.0"
+    babylon "^7.0.0-beta.42"
+    cancel-token "^0.1.1"
+    chalk "^1.1.3"
+    clone "^2.0.0"
+    cssbeautify "^0.3.1"
+    doctrine "^2.0.2"
+    dom5 "^3.0.0"
+    indent "0.0.2"
+    is-windows "^1.0.2"
+    jsonschema "^1.1.0"
+    minimatch "^3.0.4"
+    parse5 "^4.0.0"
+    path-is-inside "^1.0.2"
+    resolve "^1.5.0"
+    shady-css-parser "^0.1.0"
+    stable "^0.1.6"
+    strip-indent "^2.0.0"
+    vscode-uri "=1.0.6"
+    whatwg-url "^6.4.0"
+
+polymer-build@^3.1.0, polymer-build@^3.1.4:
+  version "3.1.4"
+  resolved "https://registry.yarnpkg.com/polymer-build/-/polymer-build-3.1.4.tgz#ab539f1a13d803518b13b73ffd09198431d98142"
+  integrity sha512-OhTOPG5Y/tK2HqGZ5XA/CVDh+TuOaDv7wTZWXDCg6hxeMgNKuljDMn2coyGU5NLM0pLbS+gwFAc2ZJ5cWHCHNg==
+  dependencies:
+    "@babel/core" "^7.0.0"
+    "@babel/plugin-external-helpers" "^7.0.0"
+    "@babel/plugin-proposal-async-generator-functions" "^7.0.0"
+    "@babel/plugin-proposal-object-rest-spread" "^7.0.0"
+    "@babel/plugin-syntax-async-generators" "^7.0.0"
+    "@babel/plugin-syntax-dynamic-import" "^7.0.0"
+    "@babel/plugin-syntax-import-meta" "^7.0.0"
+    "@babel/plugin-syntax-object-rest-spread" "^7.0.0"
+    "@babel/plugin-transform-arrow-functions" "^7.0.0"
+    "@babel/plugin-transform-async-to-generator" "^7.0.0"
+    "@babel/plugin-transform-block-scoped-functions" "^7.0.0"
+    "@babel/plugin-transform-block-scoping" "^7.0.0"
+    "@babel/plugin-transform-classes" "^7.0.0"
+    "@babel/plugin-transform-computed-properties" "^7.0.0"
+    "@babel/plugin-transform-destructuring" "^7.0.0"
+    "@babel/plugin-transform-duplicate-keys" "^7.0.0"
+    "@babel/plugin-transform-exponentiation-operator" "^7.0.0"
+    "@babel/plugin-transform-for-of" "^7.0.0"
+    "@babel/plugin-transform-function-name" "^7.0.0"
+    "@babel/plugin-transform-instanceof" "^7.0.0"
+    "@babel/plugin-transform-literals" "^7.0.0"
+    "@babel/plugin-transform-modules-amd" "^7.0.0"
+    "@babel/plugin-transform-object-super" "^7.0.0"
+    "@babel/plugin-transform-parameters" "^7.0.0"
+    "@babel/plugin-transform-regenerator" "^7.0.0"
+    "@babel/plugin-transform-shorthand-properties" "^7.0.0"
+    "@babel/plugin-transform-spread" "^7.0.0"
+    "@babel/plugin-transform-sticky-regex" "^7.0.0"
+    "@babel/plugin-transform-template-literals" "^7.0.0"
+    "@babel/plugin-transform-typeof-symbol" "^7.0.0"
+    "@babel/plugin-transform-unicode-regex" "^7.0.0"
+    "@babel/traverse" "^7.0.0"
+    "@polymer/esm-amd-loader" "^1.0.0"
+    "@types/babel-types" "^6.25.1"
+    "@types/babylon" "^6.16.2"
+    "@types/gulp-if" "0.0.33"
+    "@types/html-minifier" "^3.5.1"
+    "@types/is-windows" "^0.2.0"
+    "@types/mz" "0.0.31"
+    "@types/parse5" "^2.2.34"
+    "@types/resolve" "0.0.7"
+    "@types/uuid" "^3.4.3"
+    "@types/vinyl" "^2.0.0"
+    "@types/vinyl-fs" "^2.4.8"
+    babel-plugin-minify-guarded-expressions "^0.4.3"
+    babel-preset-minify "^0.5.0"
+    babylon "^7.0.0-beta.42"
+    css-slam "^2.1.2"
+    dom5 "^3.0.0"
+    gulp-if "^2.0.2"
+    html-minifier "^3.5.10"
+    matcher "^1.1.0"
+    multipipe "^1.0.2"
+    mz "^2.6.0"
+    parse5 "^4.0.0"
+    plylog "^1.0.0"
+    polymer-analyzer "^3.1.3"
+    polymer-bundler "^4.0.9"
+    polymer-project-config "^4.0.3"
+    regenerator-runtime "^0.11.1"
+    stream "0.0.2"
+    sw-precache "^5.1.1"
+    uuid "^3.2.1"
+    vinyl "^1.2.0"
+    vinyl-fs "^2.4.4"
+
+polymer-bundler@^4.0.10, polymer-bundler@^4.0.9:
+  version "4.0.10"
+  resolved "https://registry.yarnpkg.com/polymer-bundler/-/polymer-bundler-4.0.10.tgz#abc8d33977652f031068d034c8104841e80d4cbb"
+  integrity sha512-nwlN3LQlQDqbZ2sUH3394C/dHZUDHq8tpdS5HARvPDb0Q9IXWD+znOR1cr7wSjF0EZN4LiUH5hWyUoV4QSjhpQ==
+  dependencies:
+    "@types/babel-generator" "^6.25.1"
+    "@types/babel-traverse" "^6.25.3"
+    babel-generator "^6.26.1"
+    babel-traverse "^6.26.0"
+    babel-types "^6.26.0"
+    clone "^2.1.0"
+    command-line-args "^5.0.2"
+    command-line-usage "^5.0.5"
+    dom5 "^3.0.0"
+    espree "^3.5.2"
+    magic-string "^0.22.4"
+    mkdirp "^0.5.1"
+    parse5 "^4.0.0"
+    polymer-analyzer "^3.2.2"
+    rollup "^1.3.0"
+    source-map "^0.5.6"
+    vscode-uri "=1.0.6"
+
+polymer-cli@^1.9.11:
+  version "1.9.11"
+  resolved "https://registry.yarnpkg.com/polymer-cli/-/polymer-cli-1.9.11.tgz#0b5310732b787e07b811af96627ef0fd1263f5da"
+  integrity sha512-tiURjHDCOUUtDVPuVYvrfFI9PXe4OOUmBbn6Sg5GJNQ2POtP7r7hv+I5yI8P9qsxmalHTa19chVtf5/t9IBXDg==
+  dependencies:
+    "@octokit/rest" "^16.2.0"
+    "@types/chalk" "^2.2.0"
+    "@types/del" "^3.0.0"
+    "@types/findup-sync" "^0.3.29"
+    "@types/globby" "^6.1.0"
+    "@types/inquirer" "0.0.32"
+    "@types/merge-stream" "^1.0.28"
+    "@types/mz" "^0.0.31"
+    "@types/request" "2.0.3"
+    "@types/resolve" "0.0.4"
+    "@types/rimraf" "^0.0.28"
+    "@types/semver" "^5.3.30"
+    "@types/temp" "^0.8.28"
+    "@types/update-notifier" "^1.0.0"
+    "@types/vinyl" "^2.0.0"
+    "@types/vinyl-fs" "0.0.28"
+    "@types/yeoman-generator" "^2.0.3"
+    bower "^1.8.8"
+    bower-json "^0.8.1"
+    bower-logger "^0.2.2"
+    chalk "^2.4.2"
+    chokidar "^1.7.0"
+    command-line-args "^5.0.2"
+    command-line-commands "^2.0.1"
+    command-line-usage "^5.0.5"
+    del "^3.0.0"
+    findup-sync "^0.4.2"
+    globby "^8.0.1"
+    gunzip-maybe "^1.3.1"
+    inquirer "^1.0.2"
+    merge-stream "^1.0.1"
+    mz "^2.6.0"
+    plylog "^1.0.0"
+    polymer-analyzer "^3.2.2"
+    polymer-build "^3.1.4"
+    polymer-bundler "^4.0.9"
+    polymer-linter "^3.0.0"
+    polymer-project-config "^4.0.3"
+    polyserve "^0.27.15"
+    request "^2.72.0"
+    rimraf "^2.6.1"
+    semver "^5.3.0"
+    tar-fs "^1.12.0"
+    temp "^0.8.3"
+    update-notifier "^1.0.0"
+    validate-element-name "^2.1.1"
+    vinyl "^1.1.1"
+    vinyl-fs "^2.4.3"
+    web-component-tester "^6.9.0"
+    yeoman-environment "^1.5.2"
+    yeoman-generator "^3.1.1"
+
+polymer-linter@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/polymer-linter/-/polymer-linter-3.0.1.tgz#8804e1705fa2a7c263467b8a22da11bb764ee26b"
+  integrity sha512-eDh2CeswZz4Rwf8gfYXpMN66pieq4qJvP9bH3m39LLGm81hRePo4N5OHoQzR5unen1PUdmtjDv0Iicz3dTYEZQ==
+  dependencies:
+    "@types/fast-levenshtein" "0.0.1"
+    "@types/parse5" "^2.2.34"
+    babel-traverse "^6.26.0"
+    babel-types "^6.26.0"
+    cancel-token "^0.1.1"
+    css-what "^2.1.0"
+    dom5 "^3.0.0"
+    fast-levenshtein "^2.0.6"
+    parse5 "^4.0.0"
+    polymer-analyzer "^3.0.0"
+    shady-css-parser "^0.1.0"
+    stable "^0.1.6"
+    strip-indent "^2.0.0"
+    validate-element-name "^2.1.1"
+
+polymer-project-config@^4.0.0, polymer-project-config@^4.0.3:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/polymer-project-config/-/polymer-project-config-4.0.3.tgz#ef0c1a676ce4809907986c8e910745660de8024f"
+  integrity sha512-Drr+Imq+znhBC8XSt9pMlmPixoGnIOmleV5SD6mto1zOGC5oCDbSNsQL2v89DWOk+9aSUO79vnWwOmEPDSvYfw==
+  dependencies:
+    "@types/parse5" "^2.2.34"
+    browser-capabilities "^1.0.0"
+    jsonschema "^1.1.1"
+    minimatch-all "^1.1.0"
+    plylog "^1.0.0"
+    winston "^3.0.0"
+
+polyserve@^0.27.13, polyserve@^0.27.15:
+  version "0.27.15"
+  resolved "https://registry.yarnpkg.com/polyserve/-/polyserve-0.27.15.tgz#261fa5a0873c8d95fd7068598f44c9dac20cf9c4"
+  integrity sha512-AaFgANt+tUUVgHLw+BnaVYcn649JiwL1ru0TOZUKj1gGGn/Bq2S16gxql+1muGpRaAsgFu13Zu7k5XkwatwwSg==
+  dependencies:
+    "@types/compression" "^0.0.33"
+    "@types/content-type" "^1.1.0"
+    "@types/escape-html" "0.0.20"
+    "@types/express" "^4.0.36"
+    "@types/mime" "^2.0.0"
+    "@types/mz" "0.0.29"
+    "@types/opn" "^3.0.28"
+    "@types/parse5" "^2.2.34"
+    "@types/pem" "^1.8.1"
+    "@types/resolve" "0.0.6"
+    "@types/serve-static" "^1.7.31"
+    "@types/spdy" "^3.4.1"
+    bower-config "^1.4.1"
+    browser-capabilities "^1.0.0"
+    command-line-args "^5.0.2"
+    command-line-usage "^5.0.5"
+    compression "^1.6.2"
+    content-type "^1.0.2"
+    cors "^2.8.4"
+    escape-html "^1.0.3"
+    express "^4.8.5"
+    find-port "^1.0.1"
+    http-proxy-middleware "^0.17.2"
+    lru-cache "^4.0.2"
+    mime "^2.3.1"
+    mz "^2.4.0"
+    opn "^3.0.2"
+    pem "^1.8.3"
+    polymer-build "^3.1.0"
+    polymer-project-config "^4.0.0"
+    requirejs "^2.3.4"
+    resolve "^1.5.0"
+    send "^0.16.2"
+    spdy "^3.3.3"
+
+posix-character-classes@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
+  integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
+
+prepend-http@^1.0.1:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
+  integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=
+
+preserve@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
+  integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=
+
+pretty-bytes@^4.0.2:
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-4.0.2.tgz#b2bf82e7350d65c6c33aa95aaa5a4f6327f61cd9"
+  integrity sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk=
+
+pretty-bytes@^5.1.0:
+  version "5.3.0"
+  resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.3.0.tgz#f2849e27db79fb4d6cfe24764fc4134f165989f2"
+  integrity sha512-hjGrh+P926p4R4WbaB6OckyRtO0F0/lQBiT+0gnxjV+5kjPBrfVBFCsCLbMqVQeydvIoouYTCmmEURiH3R1Bdg==
+
+private@^0.1.6:
+  version "0.1.8"
+  resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"
+  integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==
+
+process-nextick-args@^2.0.0, process-nextick-args@~2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
+  integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
+
+progress@2.0.3:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
+  integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
+
+protobufjs@6.8.8:
+  version "6.8.8"
+  resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.8.8.tgz#c8b4f1282fd7a90e6f5b109ed11c84af82908e7c"
+  integrity sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==
+  dependencies:
+    "@protobufjs/aspromise" "^1.1.2"
+    "@protobufjs/base64" "^1.1.2"
+    "@protobufjs/codegen" "^2.0.4"
+    "@protobufjs/eventemitter" "^1.1.0"
+    "@protobufjs/fetch" "^1.1.0"
+    "@protobufjs/float" "^1.0.2"
+    "@protobufjs/inquire" "^1.1.0"
+    "@protobufjs/path" "^1.1.2"
+    "@protobufjs/pool" "^1.1.0"
+    "@protobufjs/utf8" "^1.1.0"
+    "@types/long" "^4.0.0"
+    "@types/node" "^10.1.0"
+    long "^4.0.0"
+
+proxy-addr@~2.0.5:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34"
+  integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==
+  dependencies:
+    forwarded "~0.1.2"
+    ipaddr.js "1.9.0"
+
+pseudomap@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
+  integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
+
+psl@^1.1.24:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/psl/-/psl-1.7.0.tgz#f1c4c47a8ef97167dea5d6bbf4816d736e884a3c"
+  integrity sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==
+
+pump@^1.0.0:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954"
+  integrity sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==
+  dependencies:
+    end-of-stream "^1.1.0"
+    once "^1.3.1"
+
+pump@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909"
+  integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==
+  dependencies:
+    end-of-stream "^1.1.0"
+    once "^1.3.1"
+
+pump@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
+  integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
+  dependencies:
+    end-of-stream "^1.1.0"
+    once "^1.3.1"
+
+pumpify@^1.3.3:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce"
+  integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==
+  dependencies:
+    duplexify "^3.6.0"
+    inherits "^2.0.3"
+    pump "^2.0.0"
+
+punycode@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
+  integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
+
+punycode@^2.1.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
+  integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
+
+q@^1.4.1, q@^1.5.1:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
+  integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
+
+qs@6.7.0:
+  version "6.7.0"
+  resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
+  integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
+
+qs@~6.5.2:
+  version "6.5.2"
+  resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
+  integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
+
+randomatic@^3.0.0:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed"
+  integrity sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==
+  dependencies:
+    is-number "^4.0.0"
+    kind-of "^6.0.0"
+    math-random "^1.0.1"
+
+range-parser@~1.2.0, range-parser@~1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
+  integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
+
+raw-body@2.4.0:
+  version "2.4.0"
+  resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332"
+  integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==
+  dependencies:
+    bytes "3.1.0"
+    http-errors "1.7.2"
+    iconv-lite "0.4.24"
+    unpipe "1.0.0"
+
+rc@^1.0.1, rc@^1.1.6:
+  version "1.2.8"
+  resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
+  integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
+  dependencies:
+    deep-extend "^0.6.0"
+    ini "~1.3.0"
+    minimist "^1.2.0"
+    strip-json-comments "~2.0.1"
+
+read-all-stream@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/read-all-stream/-/read-all-stream-3.1.0.tgz#35c3e177f2078ef789ee4bfafa4373074eaef4fa"
+  integrity sha1-NcPhd/IHjveJ7kv6+kNzB06u9Po=
+  dependencies:
+    pinkie-promise "^2.0.0"
+    readable-stream "^2.0.0"
+
+read-chunk@^3.0.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/read-chunk/-/read-chunk-3.2.0.tgz#2984afe78ca9bfbbdb74b19387bf9e86289c16ca"
+  integrity sha512-CEjy9LCzhmD7nUpJ1oVOE6s/hBkejlcJEgLQHVnQznOSilOPb+kpKktlLfFDK3/WP43+F80xkUTM2VOkYoSYvQ==
+  dependencies:
+    pify "^4.0.1"
+    with-open-file "^0.1.6"
+
+read-pkg-up@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
+  integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=
+  dependencies:
+    find-up "^1.0.0"
+    read-pkg "^1.0.0"
+
+read-pkg-up@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-4.0.0.tgz#1b221c6088ba7799601c808f91161c66e58f8978"
+  integrity sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==
+  dependencies:
+    find-up "^3.0.0"
+    read-pkg "^3.0.0"
+
+read-pkg@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
+  integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=
+  dependencies:
+    load-json-file "^1.0.0"
+    normalize-package-data "^2.3.2"
+    path-type "^1.0.0"
+
+read-pkg@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389"
+  integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=
+  dependencies:
+    load-json-file "^4.0.0"
+    normalize-package-data "^2.3.2"
+    path-type "^3.0.0"
+
+readable-stream@1.1.x:
+  version "1.1.14"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
+  integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk=
+  dependencies:
+    core-util-is "~1.0.0"
+    inherits "~2.0.1"
+    isarray "0.0.1"
+    string_decoder "~0.10.x"
+
+"readable-stream@2 || 3", readable-stream@^3.0.1, readable-stream@^3.1.1, readable-stream@^3.4.0:
+  version "3.5.0"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.5.0.tgz#465d70e6d1087f6162d079cd0b5db7fbebfd1606"
+  integrity sha512-gSz026xs2LfxBPudDuI41V1lka8cxg64E66SGe78zJlsUofOg/yqwezdIcdfwik6B4h8LFmWPA9ef9X3FiNFLA==
+  dependencies:
+    inherits "^2.0.3"
+    string_decoder "^1.1.1"
+    util-deprecate "^1.0.1"
+
+"readable-stream@>=1.0.33-1 <1.1.0-0":
+  version "1.0.34"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c"
+  integrity sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=
+  dependencies:
+    core-util-is "~1.0.0"
+    inherits "~2.0.1"
+    isarray "0.0.1"
+    string_decoder "~0.10.x"
+
+readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6:
+  version "2.3.7"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
+  integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
+  dependencies:
+    core-util-is "~1.0.0"
+    inherits "~2.0.3"
+    isarray "~1.0.0"
+    process-nextick-args "~2.0.0"
+    safe-buffer "~5.1.1"
+    string_decoder "~1.1.1"
+    util-deprecate "~1.0.1"
+
+readdirp@^2.0.0:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525"
+  integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==
+  dependencies:
+    graceful-fs "^4.1.11"
+    micromatch "^3.1.10"
+    readable-stream "^2.0.2"
+
+rechoir@^0.6.2:
+  version "0.6.2"
+  resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
+  integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=
+  dependencies:
+    resolve "^1.1.6"
+
+redent@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"
+  integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=
+  dependencies:
+    indent-string "^2.1.0"
+    strip-indent "^1.0.1"
+
+reduce-flatten@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-1.0.1.tgz#258c78efd153ddf93cb561237f61184f3696e327"
+  integrity sha1-JYx479FT3fk8tWEjf2EYTzaW4yc=
+
+regenerate-unicode-properties@^8.1.0:
+  version "8.1.0"
+  resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e"
+  integrity sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==
+  dependencies:
+    regenerate "^1.4.0"
+
+regenerate@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
+  integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==
+
+regenerator-runtime@^0.11.0, regenerator-runtime@^0.11.1:
+  version "0.11.1"
+  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
+  integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
+
+regenerator-transform@^0.14.0:
+  version "0.14.1"
+  resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.1.tgz#3b2fce4e1ab7732c08f665dfdb314749c7ddd2fb"
+  integrity sha512-flVuee02C3FKRISbxhXl9mGzdbWUVHubl1SMaknjxkFB1/iqpJhArQUvRxOOPEc/9tAiX0BaQ28FJH10E4isSQ==
+  dependencies:
+    private "^0.1.6"
+
+regex-cache@^0.4.2:
+  version "0.4.4"
+  resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd"
+  integrity sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==
+  dependencies:
+    is-equal-shallow "^0.1.3"
+
+regex-not@^1.0.0, regex-not@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
+  integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==
+  dependencies:
+    extend-shallow "^3.0.2"
+    safe-regex "^1.1.0"
+
+regexpu-core@^4.6.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.6.0.tgz#2037c18b327cfce8a6fea2a4ec441f2432afb8b6"
+  integrity sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg==
+  dependencies:
+    regenerate "^1.4.0"
+    regenerate-unicode-properties "^8.1.0"
+    regjsgen "^0.5.0"
+    regjsparser "^0.6.0"
+    unicode-match-property-ecmascript "^1.0.4"
+    unicode-match-property-value-ecmascript "^1.1.0"
+
+registry-auth-token@^3.0.1:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.4.0.tgz#d7446815433f5d5ed6431cd5dca21048f66b397e"
+  integrity sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==
+  dependencies:
+    rc "^1.1.6"
+    safe-buffer "^5.0.1"
+
+registry-url@^3.0.3:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942"
+  integrity sha1-PU74cPc93h138M+aOBQyRE4XSUI=
+  dependencies:
+    rc "^1.0.1"
+
+regjsgen@^0.5.0:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.1.tgz#48f0bf1a5ea205196929c0d9798b42d1ed98443c"
+  integrity sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==
+
+regjsparser@^0.6.0:
+  version "0.6.2"
+  resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.2.tgz#fd62c753991467d9d1ffe0a9f67f27a529024b96"
+  integrity sha512-E9ghzUtoLwDekPT0DYCp+c4h+bvuUpe6rRHCTYn6eGoqj1LgKXxT6I0Il4WbjhQkOghzi/V+y03bPKvbllL93Q==
+  dependencies:
+    jsesc "~0.5.0"
+
+relateurl@0.2.x:
+  version "0.2.7"
+  resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
+  integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=
+
+remove-trailing-separator@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
+  integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8=
+
+repeat-element@^1.1.2:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce"
+  integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==
+
+repeat-string@^1.5.2, repeat-string@^1.6.1:
+  version "1.6.1"
+  resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
+  integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
+
+repeating@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
+  integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=
+  dependencies:
+    is-finite "^1.0.0"
+
+replace-ext@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924"
+  integrity sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=
+
+replace-ext@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb"
+  integrity sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=
+
+request@2.88.0, request@^2.72.0, request@^2.85.0:
+  version "2.88.0"
+  resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
+  integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
+  dependencies:
+    aws-sign2 "~0.7.0"
+    aws4 "^1.8.0"
+    caseless "~0.12.0"
+    combined-stream "~1.0.6"
+    extend "~3.0.2"
+    forever-agent "~0.6.1"
+    form-data "~2.3.2"
+    har-validator "~5.1.0"
+    http-signature "~1.2.0"
+    is-typedarray "~1.0.0"
+    isstream "~0.1.2"
+    json-stringify-safe "~5.0.1"
+    mime-types "~2.1.19"
+    oauth-sign "~0.9.0"
+    performance-now "^2.1.0"
+    qs "~6.5.2"
+    safe-buffer "^5.1.2"
+    tough-cookie "~2.4.3"
+    tunnel-agent "^0.6.0"
+    uuid "^3.3.2"
+
+requirejs@^2.3.4:
+  version "2.3.6"
+  resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.3.6.tgz#e5093d9601c2829251258c0b9445d4d19fa9e7c9"
+  integrity sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg==
+
+requires-port@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
+  integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
+
+resolve-dir@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e"
+  integrity sha1-shklmlYC+sXFxJatiUpujMQwJh4=
+  dependencies:
+    expand-tilde "^1.2.2"
+    global-modules "^0.2.3"
+
+resolve-dir@^1.0.0, resolve-dir@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43"
+  integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=
+  dependencies:
+    expand-tilde "^2.0.0"
+    global-modules "^1.0.0"
+
+resolve-url@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
+  integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
+
+resolve@^1.1.6, resolve@^1.10.0, resolve@^1.11.1, resolve@^1.3.2, resolve@^1.5.0:
+  version "1.15.0"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.0.tgz#1b7ca96073ebb52e741ffd799f6b39ea462c67f5"
+  integrity sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==
+  dependencies:
+    path-parse "^1.0.6"
+
+restore-cursor@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541"
+  integrity sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=
+  dependencies:
+    exit-hook "^1.0.0"
+    onetime "^1.0.0"
+
+restore-cursor@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
+  integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368=
+  dependencies:
+    onetime "^2.0.0"
+    signal-exit "^3.0.2"
+
+ret@~0.1.10:
+  version "0.1.15"
+  resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
+  integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
+
+rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2:
+  version "2.7.1"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
+  integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
+  dependencies:
+    glob "^7.1.3"
+
+rimraf@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.0.tgz#614176d4b3010b75e5c390eb0ee96f6dc0cebb9b"
+  integrity sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==
+  dependencies:
+    glob "^7.1.3"
+
+rimraf@~2.6.2:
+  version "2.6.3"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
+  integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
+  dependencies:
+    glob "^7.1.3"
+
+rollup-plugin-node-resolve@^5.2.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz#730f93d10ed202473b1fb54a5997a7db8c6d8523"
+  integrity sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw==
+  dependencies:
+    "@types/resolve" "0.0.8"
+    builtin-modules "^3.1.0"
+    is-module "^1.0.0"
+    resolve "^1.11.1"
+    rollup-pluginutils "^2.8.1"
+
+rollup-plugin-terser@^5.1.3:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-5.2.0.tgz#ba758adf769347b7f1eaf9ef35978d2e207dccc7"
+  integrity sha512-jQI+nYhtDBc9HFRBz8iGttQg7li9klmzR62RG2W2nN6hJ/FI2K2ItYQ7kJ7/zn+vs+BP1AEccmVRjRN989I+Nw==
+  dependencies:
+    "@babel/code-frame" "^7.5.5"
+    jest-worker "^24.9.0"
+    rollup-pluginutils "^2.8.2"
+    serialize-javascript "^2.1.2"
+    terser "^4.6.2"
+
+rollup-pluginutils@^2.8.1, rollup-pluginutils@^2.8.2:
+  version "2.8.2"
+  resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e"
+  integrity sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==
+  dependencies:
+    estree-walker "^0.6.1"
+
+rollup@^1.27.5, rollup@^1.3.0:
+  version "1.30.0"
+  resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.30.0.tgz#ae9c893804e8eaa8f8f74b0aaf7e7fb4374a9d01"
+  integrity sha512-ANcmfaSQwpcJtZUTA0ZMNBtFcQ1B4A5FldlNqEK0WdWm9sHSKu93ffa2KV1ux8HA/yKIV/ZARV28m7rNdXJgEw==
+  dependencies:
+    "@types/estree" "*"
+    "@types/node" "*"
+    acorn "^7.1.0"
+
+run-async@^2.0.0, run-async@^2.2.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0"
+  integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA=
+  dependencies:
+    is-promise "^2.1.0"
+
+rx@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782"
+  integrity sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=
+
+rxjs@^6.4.0:
+  version "6.5.4"
+  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c"
+  integrity sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==
+  dependencies:
+    tslib "^1.9.0"
+
+safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
+  integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
+
+safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
+  integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
+
+safe-regex@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
+  integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4=
+  dependencies:
+    ret "~0.1.10"
+
+"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
+  integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+
+samsam@1.x, samsam@^1.1.3:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.3.0.tgz#8d1d9350e25622da30de3e44ba692b5221ab7c50"
+  integrity sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==
+
+sauce-connect-launcher@^1.0.0:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/sauce-connect-launcher/-/sauce-connect-launcher-1.3.1.tgz#31137f57b0f7176e1c0525b7fb09c6da746647cf"
+  integrity sha512-vIf9qDol3q2FlYzrKt0dr3kvec6LSjX2WS+/mVnAJIhqh1evSkPKCR2AzcJrnSmx9Xt9PtV0tLY7jYh0wsQi8A==
+  dependencies:
+    adm-zip "~0.4.3"
+    async "^2.1.2"
+    https-proxy-agent "^3.0.0"
+    lodash "^4.16.6"
+    rimraf "^2.5.4"
+
+scoped-regex@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/scoped-regex/-/scoped-regex-1.0.0.tgz#a346bb1acd4207ae70bd7c0c7ca9e566b6baddb8"
+  integrity sha1-o0a7Gs1CB65wvXwMfKnlZra63bg=
+
+select-hose@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
+  integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=
+
+selenium-standalone@^6.7.0:
+  version "6.17.0"
+  resolved "https://registry.yarnpkg.com/selenium-standalone/-/selenium-standalone-6.17.0.tgz#0f24b691836205ee9bc3d7a6f207ebcb28170cd9"
+  integrity sha512-5PSnDHwMiq+OCiAGlhwQ8BM9xuwFfvBOZ7Tfbw+ifkTnOy0PWbZmI1B9gPGuyGHpbQ/3J3CzIK7BYwrQ7EjtWQ==
+  dependencies:
+    async "^2.6.2"
+    commander "^2.19.0"
+    cross-spawn "^6.0.5"
+    debug "^4.1.1"
+    lodash "^4.17.11"
+    minimist "^1.2.0"
+    mkdirp "^0.5.1"
+    progress "2.0.3"
+    request "2.88.0"
+    tar-stream "2.0.0"
+    urijs "^1.19.1"
+    which "^1.3.1"
+    yauzl "^2.10.0"
+
+semver-diff@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36"
+  integrity sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=
+  dependencies:
+    semver "^5.0.3"
+
+"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0:
+  version "5.7.1"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
+  integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
+
+semver@5.6.0:
+  version "5.6.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
+  integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==
+
+semver@^6.3.0:
+  version "6.3.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
+  integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
+
+send@0.17.1:
+  version "0.17.1"
+  resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
+  integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==
+  dependencies:
+    debug "2.6.9"
+    depd "~1.1.2"
+    destroy "~1.0.4"
+    encodeurl "~1.0.2"
+    escape-html "~1.0.3"
+    etag "~1.8.1"
+    fresh "0.5.2"
+    http-errors "~1.7.2"
+    mime "1.6.0"
+    ms "2.1.1"
+    on-finished "~2.3.0"
+    range-parser "~1.2.1"
+    statuses "~1.5.0"
+
+send@^0.16.1, send@^0.16.2:
+  version "0.16.2"
+  resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1"
+  integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==
+  dependencies:
+    debug "2.6.9"
+    depd "~1.1.2"
+    destroy "~1.0.4"
+    encodeurl "~1.0.2"
+    escape-html "~1.0.3"
+    etag "~1.8.1"
+    fresh "0.5.2"
+    http-errors "~1.6.2"
+    mime "1.4.1"
+    ms "2.0.0"
+    on-finished "~2.3.0"
+    range-parser "~1.2.0"
+    statuses "~1.4.0"
+
+serialize-javascript@^2.1.2:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61"
+  integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==
+
+serve-static@1.14.1:
+  version "1.14.1"
+  resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9"
+  integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==
+  dependencies:
+    encodeurl "~1.0.2"
+    escape-html "~1.0.3"
+    parseurl "~1.3.3"
+    send "0.17.1"
+
+server-destroy@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/server-destroy/-/server-destroy-1.0.1.tgz#f13bf928e42b9c3e79383e61cc3998b5d14e6cdd"
+  integrity sha1-8Tv5KOQrnD55OD5hzDmYtdFObN0=
+
+serviceworker-cache-polyfill@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/serviceworker-cache-polyfill/-/serviceworker-cache-polyfill-4.0.0.tgz#de19ee73bef21ab3c0740a37b33db62464babdeb"
+  integrity sha1-3hnuc77yGrPAdAo3sz22JGS6ves=
+
+set-value@^2.0.0, set-value@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
+  integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==
+  dependencies:
+    extend-shallow "^2.0.1"
+    is-extendable "^0.1.1"
+    is-plain-object "^2.0.3"
+    split-string "^3.0.1"
+
+setprototypeof@1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
+  integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==
+
+setprototypeof@1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
+  integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==
+
+shady-css-parser@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/shady-css-parser/-/shady-css-parser-0.1.0.tgz#534dc79c8ca5884c5ed92a4e5a13d6d863bca428"
+  integrity sha512-irfJUUkEuDlNHKZNAp2r7zOyMlmbfVJ+kWSfjlCYYUx/7dJnANLCyTzQZsuxy5NJkvtNwSxY5Gj8MOlqXUQPyA==
+
+shebang-command@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
+  integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=
+  dependencies:
+    shebang-regex "^1.0.0"
+
+shebang-regex@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
+  integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
+
+shelljs@^0.8.0:
+  version "0.8.3"
+  resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.3.tgz#a7f3319520ebf09ee81275b2368adb286659b097"
+  integrity sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==
+  dependencies:
+    glob "^7.0.0"
+    interpret "^1.0.0"
+    rechoir "^0.6.2"
+
+signal-exit@^3.0.0, signal-exit@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
+  integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
+
+simple-swizzle@^0.2.2:
+  version "0.2.2"
+  resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
+  integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=
+  dependencies:
+    is-arrayish "^0.3.1"
+
+sinon-chai@^2.10.0:
+  version "2.14.0"
+  resolved "https://registry.yarnpkg.com/sinon-chai/-/sinon-chai-2.14.0.tgz#da7dd4cc83cd6a260b67cca0f7a9fdae26a1205d"
+  integrity sha512-9stIF1utB0ywNHNT7RgiXbdmen8QDCRsrTjw+G9TgKt1Yexjiv8TOWZ6WHsTPz57Yky3DIswZvEqX8fpuHNDtQ==
+
+sinon@^2.3.5:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/sinon/-/sinon-2.4.1.tgz#021fd64b54cb77d9d2fb0d43cdedfae7629c3a36"
+  integrity sha512-vFTrO9Wt0ECffDYIPSP/E5bBugt0UjcBQOfQUMh66xzkyPEnhl/vM2LRZi2ajuTdkH07sA6DzrM6KvdvGIH8xw==
+  dependencies:
+    diff "^3.1.0"
+    formatio "1.2.0"
+    lolex "^1.6.0"
+    native-promise-only "^0.8.1"
+    path-to-regexp "^1.7.0"
+    samsam "^1.1.3"
+    text-encoding "0.6.4"
+    type-detect "^4.0.0"
+
+slash@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
+  integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=
+
+slide@^1.1.5:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707"
+  integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=
+
+snapdragon-node@^2.0.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
+  integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==
+  dependencies:
+    define-property "^1.0.0"
+    isobject "^3.0.0"
+    snapdragon-util "^3.0.1"
+
+snapdragon-util@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2"
+  integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==
+  dependencies:
+    kind-of "^3.2.0"
+
+snapdragon@^0.8.1:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d"
+  integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==
+  dependencies:
+    base "^0.11.1"
+    debug "^2.2.0"
+    define-property "^0.2.5"
+    extend-shallow "^2.0.1"
+    map-cache "^0.2.2"
+    source-map "^0.5.6"
+    source-map-resolve "^0.5.0"
+    use "^3.1.0"
+
+socket.io-adapter@~1.1.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz#ab3f0d6f66b8fc7fca3959ab5991f82221789be9"
+  integrity sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==
+
+socket.io-client@2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.3.0.tgz#14d5ba2e00b9bcd145ae443ab96b3f86cbcc1bb4"
+  integrity sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==
+  dependencies:
+    backo2 "1.0.2"
+    base64-arraybuffer "0.1.5"
+    component-bind "1.0.0"
+    component-emitter "1.2.1"
+    debug "~4.1.0"
+    engine.io-client "~3.4.0"
+    has-binary2 "~1.0.2"
+    has-cors "1.1.0"
+    indexof "0.0.1"
+    object-component "0.0.3"
+    parseqs "0.0.5"
+    parseuri "0.0.5"
+    socket.io-parser "~3.3.0"
+    to-array "0.1.4"
+
+socket.io-parser@~3.3.0:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.0.tgz#2b52a96a509fdf31440ba40fed6094c7d4f1262f"
+  integrity sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==
+  dependencies:
+    component-emitter "1.2.1"
+    debug "~3.1.0"
+    isarray "2.0.1"
+
+socket.io-parser@~3.4.0:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.4.0.tgz#370bb4a151df2f77ce3345ff55a7072cc6e9565a"
+  integrity sha512-/G/VOI+3DBp0+DJKW4KesGnQkQPFmUCbA/oO2QGT6CWxU7hLGWqU3tyuzeSK/dqcyeHsQg1vTe9jiZI8GU9SCQ==
+  dependencies:
+    component-emitter "1.2.1"
+    debug "~4.1.0"
+    isarray "2.0.1"
+
+socket.io@^2.0.3:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.3.0.tgz#cd762ed6a4faeca59bc1f3e243c0969311eb73fb"
+  integrity sha512-2A892lrj0GcgR/9Qk81EaY2gYhCBxurV0PfmmESO6p27QPrUK1J3zdns+5QPqvUYK2q657nSj0guoIil9+7eFg==
+  dependencies:
+    debug "~4.1.0"
+    engine.io "~3.4.0"
+    has-binary2 "~1.0.2"
+    socket.io-adapter "~1.1.0"
+    socket.io-client "2.3.0"
+    socket.io-parser "~3.4.0"
+
+sort-keys-length@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/sort-keys-length/-/sort-keys-length-1.0.1.tgz#9cb6f4f4e9e48155a6aa0671edd336ff1479a188"
+  integrity sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=
+  dependencies:
+    sort-keys "^1.0.0"
+
+sort-keys@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad"
+  integrity sha1-RBttTTRnmPG05J6JIK37oOVD+a0=
+  dependencies:
+    is-plain-obj "^1.0.0"
+
+source-map-resolve@^0.5.0:
+  version "0.5.3"
+  resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a"
+  integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==
+  dependencies:
+    atob "^2.1.2"
+    decode-uri-component "^0.2.0"
+    resolve-url "^0.2.1"
+    source-map-url "^0.4.0"
+    urix "^0.1.0"
+
+source-map-support@0.5.9:
+  version "0.5.9"
+  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.9.tgz#41bc953b2534267ea2d605bccfa7bfa3111ced5f"
+  integrity sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==
+  dependencies:
+    buffer-from "^1.0.0"
+    source-map "^0.6.0"
+
+source-map-support@~0.5.12:
+  version "0.5.16"
+  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042"
+  integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==
+  dependencies:
+    buffer-from "^1.0.0"
+    source-map "^0.6.0"
+
+source-map-url@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
+  integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=
+
+source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7:
+  version "0.5.7"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
+  integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
+
+source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
+  integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+
+spawn-sync@^1.0.15:
+  version "1.0.15"
+  resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476"
+  integrity sha1-sAeZVX63+wyDdsKdROih6mfldHY=
+  dependencies:
+    concat-stream "^1.4.7"
+    os-shim "^0.1.2"
+
+spdx-correct@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4"
+  integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==
+  dependencies:
+    spdx-expression-parse "^3.0.0"
+    spdx-license-ids "^3.0.0"
+
+spdx-exceptions@^2.1.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977"
+  integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==
+
+spdx-expression-parse@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0"
+  integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==
+  dependencies:
+    spdx-exceptions "^2.1.0"
+    spdx-license-ids "^3.0.0"
+
+spdx-license-ids@^3.0.0:
+  version "3.0.5"
+  resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654"
+  integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==
+
+spdy-transport@^2.0.18:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-2.1.1.tgz#c54815d73858aadd06ce63001e7d25fa6441623b"
+  integrity sha512-q7D8c148escoB3Z7ySCASadkegMmUZW8Wb/Q1u0/XBgDKMO880rLQDj8Twiew/tYi7ghemKUi/whSYOwE17f5Q==
+  dependencies:
+    debug "^2.6.8"
+    detect-node "^2.0.3"
+    hpack.js "^2.1.6"
+    obuf "^1.1.1"
+    readable-stream "^2.2.9"
+    safe-buffer "^5.0.1"
+    wbuf "^1.7.2"
+
+spdy@^3.3.3:
+  version "3.4.7"
+  resolved "https://registry.yarnpkg.com/spdy/-/spdy-3.4.7.tgz#42ff41ece5cc0f99a3a6c28aabb73f5c3b03acbc"
+  integrity sha1-Qv9B7OXMD5mjpsKKq7c/XDsDrLw=
+  dependencies:
+    debug "^2.6.8"
+    handle-thing "^1.2.5"
+    http-deceiver "^1.2.7"
+    safe-buffer "^5.0.1"
+    select-hose "^2.0.0"
+    spdy-transport "^2.0.18"
+
+split-string@^3.0.1, split-string@^3.0.2:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
+  integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==
+  dependencies:
+    extend-shallow "^3.0.0"
+
+sshpk@^1.7.0:
+  version "1.16.1"
+  resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
+  integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==
+  dependencies:
+    asn1 "~0.2.3"
+    assert-plus "^1.0.0"
+    bcrypt-pbkdf "^1.0.0"
+    dashdash "^1.12.0"
+    ecc-jsbn "~0.1.1"
+    getpass "^0.1.1"
+    jsbn "~0.1.0"
+    safer-buffer "^2.0.2"
+    tweetnacl "~0.14.0"
+
+stable@^0.1.6:
+  version "0.1.8"
+  resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
+  integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==
+
+stack-trace@0.0.x:
+  version "0.0.10"
+  resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
+  integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=
+
+stacky@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/stacky/-/stacky-1.3.1.tgz#3f117e5187b9a73d23f876d69f05c85b11804a12"
+  integrity sha1-PxF+UYe5pz0j+HbWnwXIWxGAShI=
+  dependencies:
+    chalk "^1.1.1"
+    lodash "^3.0.0"
+
+static-extend@^0.1.1:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
+  integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=
+  dependencies:
+    define-property "^0.2.5"
+    object-copy "^0.1.0"
+
+"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
+  integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
+
+statuses@~1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
+  integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==
+
+stream-shift@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d"
+  integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==
+
+stream@0.0.2:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/stream/-/stream-0.0.2.tgz#7f5363f057f6592c5595f00bc80a27f5cec1f0ef"
+  integrity sha1-f1Nj8Ff2WSxVlfALyAon9c7B8O8=
+  dependencies:
+    emitter-component "^1.1.1"
+
+streamsearch@0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a"
+  integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=
+
+string-template@~0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add"
+  integrity sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=
+
+string-width@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
+  integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=
+  dependencies:
+    code-point-at "^1.0.0"
+    is-fullwidth-code-point "^1.0.0"
+    strip-ansi "^3.0.0"
+
+string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
+  integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
+  dependencies:
+    is-fullwidth-code-point "^2.0.0"
+    strip-ansi "^4.0.0"
+
+string_decoder@^1.1.1:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
+  integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
+  dependencies:
+    safe-buffer "~5.2.0"
+
+string_decoder@~0.10.x:
+  version "0.10.31"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
+  integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=
+
+string_decoder@~1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
+  integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
+  dependencies:
+    safe-buffer "~5.1.0"
+
+strip-ansi@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+  integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
+  dependencies:
+    ansi-regex "^2.0.0"
+
+strip-ansi@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
+  integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
+  dependencies:
+    ansi-regex "^3.0.0"
+
+strip-ansi@^5.1.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
+  integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
+  dependencies:
+    ansi-regex "^4.1.0"
+
+strip-ansi@~0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.1.1.tgz#39e8a98d044d150660abe4a6808acf70bb7bc991"
+  integrity sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=
+
+strip-bom-stream@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz#e7144398577d51a6bed0fa1994fa05f43fd988ee"
+  integrity sha1-5xRDmFd9Uaa+0PoZlPoF9D/ZiO4=
+  dependencies:
+    first-chunk-stream "^1.0.0"
+    strip-bom "^2.0.0"
+
+strip-bom-stream@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz#f87db5ef2613f6968aa545abfe1ec728b6a829ca"
+  integrity sha1-+H217yYT9paKpUWr/h7HKLaoKco=
+  dependencies:
+    first-chunk-stream "^2.0.0"
+    strip-bom "^2.0.0"
+
+strip-bom@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
+  integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=
+  dependencies:
+    is-utf8 "^0.2.0"
+
+strip-bom@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
+  integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=
+
+strip-eof@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
+  integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
+
+strip-indent@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2"
+  integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=
+  dependencies:
+    get-stdin "^4.0.1"
+
+strip-indent@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68"
+  integrity sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=
+
+strip-json-comments@~2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+  integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
+
+supports-color@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
+  integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
+
+supports-color@^5.3.0:
+  version "5.5.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
+  integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
+  dependencies:
+    has-flag "^3.0.0"
+
+supports-color@^6.1.0:
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3"
+  integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==
+  dependencies:
+    has-flag "^3.0.0"
+
+supports-color@^7.1.0:
+  version "7.1.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1"
+  integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==
+  dependencies:
+    has-flag "^4.0.0"
+
+sw-precache@^5.1.1:
+  version "5.2.1"
+  resolved "https://registry.yarnpkg.com/sw-precache/-/sw-precache-5.2.1.tgz#06134f319eec68f3b9583ce9a7036b1c119f7179"
+  integrity sha512-8FAy+BP/FXE+ILfiVTt+GQJ6UEf4CVHD9OfhzH0JX+3zoy2uFk7Vn9EfXASOtVmmIVbL3jE/W8Z66VgPSZcMhw==
+  dependencies:
+    dom-urls "^1.1.0"
+    es6-promise "^4.0.5"
+    glob "^7.1.1"
+    lodash.defaults "^4.2.0"
+    lodash.template "^4.4.0"
+    meow "^3.7.0"
+    mkdirp "^0.5.1"
+    pretty-bytes "^4.0.2"
+    sw-toolbox "^3.4.0"
+    update-notifier "^2.3.0"
+
+sw-toolbox@^3.4.0:
+  version "3.6.0"
+  resolved "https://registry.yarnpkg.com/sw-toolbox/-/sw-toolbox-3.6.0.tgz#26df1d1c70348658e4dea2884319149b7b3183b5"
+  integrity sha1-Jt8dHHA0hljk3qKIQxkUm3sxg7U=
+  dependencies:
+    path-to-regexp "^1.0.1"
+    serviceworker-cache-polyfill "^4.0.0"
+
+table-layout@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-0.3.0.tgz#6ee20dc483db371b3e5c87f704ed2f7c799d2c9a"
+  integrity sha1-buINxIPbNxs+XIf3BO0vfHmdLJo=
+  dependencies:
+    array-back "^1.0.3"
+    core-js "^2.4.1"
+    deep-extend "~0.4.1"
+    feature-detect-es6 "^1.3.1"
+    typical "^2.6.0"
+    wordwrapjs "^2.0.0-0"
+
+table-layout@^0.4.3:
+  version "0.4.5"
+  resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-0.4.5.tgz#d906de6a25fa09c0c90d1d08ecd833ecedcb7378"
+  integrity sha512-zTvf0mcggrGeTe/2jJ6ECkJHAQPIYEwDoqsiqBjI24mvRmQbInK5jq33fyypaCBxX08hMkfmdOqj6haT33EqWw==
+  dependencies:
+    array-back "^2.0.0"
+    deep-extend "~0.6.0"
+    lodash.padend "^4.6.1"
+    typical "^2.6.1"
+    wordwrapjs "^3.0.0"
+
+tar-fs@^1.12.0:
+  version "1.16.3"
+  resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-1.16.3.tgz#966a628841da2c4010406a82167cbd5e0c72d509"
+  integrity sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==
+  dependencies:
+    chownr "^1.0.1"
+    mkdirp "^0.5.1"
+    pump "^1.0.0"
+    tar-stream "^1.1.2"
+
+tar-stream@2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.0.0.tgz#8829bbf83067bc0288a9089db49c56be395b6aea"
+  integrity sha512-n2vtsWshZOVr/SY4KtslPoUlyNh06I2SGgAOCZmquCEjlbV/LjY2CY80rDtdQRHFOYXNlgBDo6Fr3ww2CWPOtA==
+  dependencies:
+    bl "^2.2.0"
+    end-of-stream "^1.4.1"
+    fs-constants "^1.0.0"
+    inherits "^2.0.3"
+    readable-stream "^3.1.1"
+
+tar-stream@^1.1.2:
+  version "1.6.2"
+  resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555"
+  integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==
+  dependencies:
+    bl "^1.0.0"
+    buffer-alloc "^1.2.0"
+    end-of-stream "^1.0.0"
+    fs-constants "^1.0.0"
+    readable-stream "^2.3.0"
+    to-buffer "^1.1.1"
+    xtend "^4.0.0"
+
+tar-stream@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.0.tgz#d1aaa3661f05b38b5acc9b7020efdca5179a2cc3"
+  integrity sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw==
+  dependencies:
+    bl "^3.0.0"
+    end-of-stream "^1.4.1"
+    fs-constants "^1.0.0"
+    inherits "^2.0.3"
+    readable-stream "^3.1.1"
+
+temp@^0.8.1, temp@^0.8.3:
+  version "0.8.4"
+  resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.4.tgz#8c97a33a4770072e0a05f919396c7665a7dd59f2"
+  integrity sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==
+  dependencies:
+    rimraf "~2.6.2"
+
+term-size@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69"
+  integrity sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=
+  dependencies:
+    execa "^0.7.0"
+
+ternary-stream@^2.0.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/ternary-stream/-/ternary-stream-2.1.1.tgz#4ad64b98668d796a085af2c493885a435a8a8bfc"
+  integrity sha512-j6ei9hxSoyGlqTmoMjOm+QNvUKDOIY6bNl4Uh1lhBvl6yjPW2iLqxDUYyfDPZknQ4KdRziFl+ec99iT4l7g0cw==
+  dependencies:
+    duplexify "^3.5.0"
+    fork-stream "^0.0.4"
+    merge-stream "^1.0.0"
+    through2 "^2.0.1"
+
+terser@^4.6.2:
+  version "4.6.3"
+  resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.3.tgz#e33aa42461ced5238d352d2df2a67f21921f8d87"
+  integrity sha512-Lw+ieAXmY69d09IIc/yqeBqXpEQIpDGZqT34ui1QWXIUpR2RjbqEkT8X7Lgex19hslSqcWM5iMN2kM11eMsESQ==
+  dependencies:
+    commander "^2.20.0"
+    source-map "~0.6.1"
+    source-map-support "~0.5.12"
+
+test-value@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/test-value/-/test-value-2.1.0.tgz#11da6ff670f3471a73b625ca4f3fdcf7bb748291"
+  integrity sha1-Edpv9nDzRxpztiXKTz/c97t0gpE=
+  dependencies:
+    array-back "^1.0.3"
+    typical "^2.6.0"
+
+text-encoding@0.6.4:
+  version "0.6.4"
+  resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.6.4.tgz#e399a982257a276dae428bb92845cb71bdc26d19"
+  integrity sha1-45mpgiV6J22uQou5KEXLcb3CbRk=
+
+text-hex@1.0.x:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5"
+  integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==
+
+text-table@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
+  integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
+
+textextensions@^2.5.0:
+  version "2.6.0"
+  resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.6.0.tgz#d7e4ab13fe54e32e08873be40d51b74229b00fc4"
+  integrity sha512-49WtAWS+tcsy93dRt6P0P3AMD2m5PvXRhuEA0kaXos5ZLlujtYmpmFsB+QvWUSxE1ZsstmYXfQ7L40+EcQgpAQ==
+
+thenify-all@^1.0.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726"
+  integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=
+  dependencies:
+    thenify ">= 3.1.0 < 4"
+
+"thenify@>= 3.1.0 < 4":
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.0.tgz#e69e38a1babe969b0108207978b9f62b88604839"
+  integrity sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=
+  dependencies:
+    any-promise "^1.0.0"
+
+through2-filter@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-2.0.0.tgz#60bc55a0dacb76085db1f9dae99ab43f83d622ec"
+  integrity sha1-YLxVoNrLdghdsfna6Zq0P4PWIuw=
+  dependencies:
+    through2 "~2.0.0"
+    xtend "~4.0.0"
+
+through2-filter@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-3.0.0.tgz#700e786df2367c2c88cd8aa5be4cf9c1e7831254"
+  integrity sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==
+  dependencies:
+    through2 "~2.0.0"
+    xtend "~4.0.0"
+
+through2@^0.6.0:
+  version "0.6.5"
+  resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48"
+  integrity sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=
+  dependencies:
+    readable-stream ">=1.0.33-1 <1.1.0-0"
+    xtend ">=4.0.0 <4.1.0-0"
+
+through2@^2.0.0, through2@^2.0.1, through2@^2.0.3, through2@~2.0.0:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
+  integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==
+  dependencies:
+    readable-stream "~2.3.6"
+    xtend "~4.0.1"
+
+through2@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.1.tgz#39276e713c3302edf9e388dd9c812dd3b825bd5a"
+  integrity sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==
+  dependencies:
+    readable-stream "2 || 3"
+
+through@^2.3.6:
+  version "2.3.8"
+  resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
+  integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
+
+timed-out@^3.0.0:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-3.1.3.tgz#95860bfcc5c76c277f8f8326fd0f5b2e20eba217"
+  integrity sha1-lYYL/MXHbCd/j4Mm/Q9bLiDrohc=
+
+timed-out@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f"
+  integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=
+
+tmp@^0.0.29:
+  version "0.0.29"
+  resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0"
+  integrity sha1-8lEl/w3Z2jzLDC3Tce4SiLuRKMA=
+  dependencies:
+    os-tmpdir "~1.0.1"
+
+tmp@^0.0.33:
+  version "0.0.33"
+  resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
+  integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==
+  dependencies:
+    os-tmpdir "~1.0.2"
+
+to-absolute-glob@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/to-absolute-glob/-/to-absolute-glob-0.1.1.tgz#1cdfa472a9ef50c239ee66999b662ca0eb39937f"
+  integrity sha1-HN+kcqnvUMI57maZm2YsoOs5k38=
+  dependencies:
+    extend-shallow "^2.0.1"
+
+to-array@0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890"
+  integrity sha1-F+bBH3PdTz10zaek/zI46a2b+JA=
+
+to-buffer@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80"
+  integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==
+
+to-fast-properties@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
+  integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=
+
+to-fast-properties@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
+  integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=
+
+to-object-path@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
+  integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=
+  dependencies:
+    kind-of "^3.0.2"
+
+to-regex-range@^2.1.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38"
+  integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=
+  dependencies:
+    is-number "^3.0.0"
+    repeat-string "^1.6.1"
+
+to-regex@^3.0.1, to-regex@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
+  integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==
+  dependencies:
+    define-property "^2.0.2"
+    extend-shallow "^3.0.2"
+    regex-not "^1.0.2"
+    safe-regex "^1.1.0"
+
+toidentifier@1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
+  integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
+
+tough-cookie@~2.4.3:
+  version "2.4.3"
+  resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
+  integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==
+  dependencies:
+    psl "^1.1.24"
+    punycode "^1.4.1"
+
+tr46@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09"
+  integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=
+  dependencies:
+    punycode "^2.1.0"
+
+trim-newlines@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
+  integrity sha1-WIeWa7WCpFA6QetST301ARgVphM=
+
+trim-right@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
+  integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=
+
+triple-beam@^1.2.0, triple-beam@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9"
+  integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==
+
+tslib@^1.8.1, tslib@^1.9.0:
+  version "1.10.0"
+  resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
+  integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==
+
+tsutils@2.27.2:
+  version "2.27.2"
+  resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.27.2.tgz#60ba88a23d6f785ec4b89c6e8179cac9b431f1c7"
+  integrity sha512-qf6rmT84TFMuxAKez2pIfR8UCai49iQsfB7YWVjV1bKpy/d0PWT5rEOSM6La9PiHZ0k1RRZQiwVdVJfQ3BPHgg==
+  dependencies:
+    tslib "^1.8.1"
+
+tunnel-agent@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
+  integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=
+  dependencies:
+    safe-buffer "^5.0.1"
+
+tweetnacl@^0.14.3, tweetnacl@~0.14.0:
+  version "0.14.5"
+  resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
+  integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
+
+type-detect@^4.0.0:
+  version "4.0.8"
+  resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
+  integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
+
+type-is@^1.6.4, type-is@~1.6.17, type-is@~1.6.18:
+  version "1.6.18"
+  resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
+  integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
+  dependencies:
+    media-typer "0.3.0"
+    mime-types "~2.1.24"
+
+typedarray@^0.0.6:
+  version "0.0.6"
+  resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
+  integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
+
+typescript@^3.7.4:
+  version "3.7.5"
+  resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae"
+  integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==
+
+typical@^2.6.0, typical@^2.6.1:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/typical/-/typical-2.6.1.tgz#5c080e5d661cbbe38259d2e70a3c7253e873881d"
+  integrity sha1-XAgOXWYcu+OCWdLnCjxyU+hziB0=
+
+typical@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4"
+  integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==
+
+ua-parser-js@^0.7.15:
+  version "0.7.21"
+  resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.21.tgz#853cf9ce93f642f67174273cc34565ae6f308777"
+  integrity sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ==
+
+uglify-js@3.4.x:
+  version "3.4.10"
+  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f"
+  integrity sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==
+  dependencies:
+    commander "~2.19.0"
+    source-map "~0.6.1"
+
+underscore@^1.8.3:
+  version "1.9.2"
+  resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.2.tgz#0c8d6f536d6f378a5af264a72f7bec50feb7cf2f"
+  integrity sha512-D39qtimx0c1fI3ya1Lnhk3E9nONswSKhnffBI0gME9C99fYOkNi04xs8K6pePLhvl1frbDemkaBQ5ikWllR2HQ==
+
+underscore@~1.6.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.6.0.tgz#8b38b10cacdef63337b8b24e4ff86d45aea529a8"
+  integrity sha1-izixDKze9jM3uLJOT/htRa6lKag=
+
+unicode-canonical-property-names-ecmascript@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818"
+  integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==
+
+unicode-match-property-ecmascript@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c"
+  integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==
+  dependencies:
+    unicode-canonical-property-names-ecmascript "^1.0.4"
+    unicode-property-aliases-ecmascript "^1.0.4"
+
+unicode-match-property-value-ecmascript@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz#5b4b426e08d13a80365e0d657ac7a6c1ec46a277"
+  integrity sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==
+
+unicode-property-aliases-ecmascript@^1.0.4:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz#a9cc6cc7ce63a0a3023fc99e341b94431d405a57"
+  integrity sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==
+
+union-value@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847"
+  integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==
+  dependencies:
+    arr-union "^3.1.0"
+    get-value "^2.0.6"
+    is-extendable "^0.1.1"
+    set-value "^2.0.1"
+
+unique-stream@^2.0.2:
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-2.3.1.tgz#c65d110e9a4adf9a6c5948b28053d9a8d04cbeac"
+  integrity sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==
+  dependencies:
+    json-stable-stringify-without-jsonify "^1.0.1"
+    through2-filter "^3.0.0"
+
+unique-string@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a"
+  integrity sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=
+  dependencies:
+    crypto-random-string "^1.0.0"
+
+universal-user-agent@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-4.0.0.tgz#27da2ec87e32769619f68a14996465ea1cb9df16"
+  integrity sha512-eM8knLpev67iBDizr/YtqkJsF3GK8gzDc6st/WKzrTuPtcsOKW/0IdL4cnMBsU69pOx0otavLWBDGTwg+dB0aA==
+  dependencies:
+    os-name "^3.1.0"
+
+unpipe@1.0.0, unpipe@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
+  integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=
+
+unset-value@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559"
+  integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=
+  dependencies:
+    has-value "^0.3.1"
+    isobject "^3.0.0"
+
+untildify@^2.0.0, untildify@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/untildify/-/untildify-2.1.0.tgz#17eb2807987f76952e9c0485fc311d06a826a2e0"
+  integrity sha1-F+soB5h/dpUunASF/DEdBqgmouA=
+  dependencies:
+    os-homedir "^1.0.0"
+
+untildify@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/untildify/-/untildify-3.0.3.tgz#1e7b42b140bcfd922b22e70ca1265bfe3634c7c9"
+  integrity sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==
+
+unzip-response@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-1.0.2.tgz#b984f0877fc0a89c2c773cc1ef7b5b232b5b06fe"
+  integrity sha1-uYTwh3/AqJwsdzzB73tbIytbBv4=
+
+unzip-response@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97"
+  integrity sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=
+
+update-notifier@^1.0.0:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-1.0.3.tgz#8f92c515482bd6831b7c93013e70f87552c7cf5a"
+  integrity sha1-j5LFFUgr1oMbfJMBPnD4dVLHz1o=
+  dependencies:
+    boxen "^0.6.0"
+    chalk "^1.0.0"
+    configstore "^2.0.0"
+    is-npm "^1.0.0"
+    latest-version "^2.0.0"
+    lazy-req "^1.1.0"
+    semver-diff "^2.0.0"
+    xdg-basedir "^2.0.0"
+
+update-notifier@^2.2.0, update-notifier@^2.3.0:
+  version "2.5.0"
+  resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.5.0.tgz#d0744593e13f161e406acb1d9408b72cad08aff6"
+  integrity sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==
+  dependencies:
+    boxen "^1.2.1"
+    chalk "^2.0.1"
+    configstore "^3.0.0"
+    import-lazy "^2.1.0"
+    is-ci "^1.0.10"
+    is-installed-globally "^0.1.0"
+    is-npm "^1.0.0"
+    latest-version "^3.0.0"
+    semver-diff "^2.0.0"
+    xdg-basedir "^3.0.0"
+
+upper-case@^1.1.1:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598"
+  integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=
+
+uri-js@^4.2.2:
+  version "4.2.2"
+  resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
+  integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
+  dependencies:
+    punycode "^2.1.0"
+
+urijs@^1.16.1, urijs@^1.19.1:
+  version "1.19.2"
+  resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.2.tgz#f9be09f00c4c5134b7cb3cf475c1dd394526265a"
+  integrity sha512-s/UIq9ap4JPZ7H1EB5ULo/aOUbWqfDi7FKzMC2Nz+0Si8GiT1rIEaprt8hy3Vy2Ex2aJPpOQv4P4DuOZ+K1c6w==
+
+urix@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
+  integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=
+
+url-parse-lax@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73"
+  integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=
+  dependencies:
+    prepend-http "^1.0.1"
+
+url-to-options@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9"
+  integrity sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=
+
+use@^3.1.0:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
+  integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
+
+util-deprecate@^1.0.1, util-deprecate@~1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+  integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
+
+utils-merge@1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
+  integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
+
+uuid@^2.0.1:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a"
+  integrity sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=
+
+uuid@^3.2.1, uuid@^3.3.2:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
+  integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
+
+vali-date@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/vali-date/-/vali-date-1.0.0.tgz#1b904a59609fb328ef078138420934f6b86709a6"
+  integrity sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=
+
+validate-element-name@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/validate-element-name/-/validate-element-name-2.1.1.tgz#8ff75f7da69f73e7c510588362130508b7ac644e"
+  integrity sha1-j/dffaafc+fFEFiDYhMFCLesZE4=
+  dependencies:
+    is-potential-custom-element-name "^1.0.0"
+    log-symbols "^1.0.0"
+    meow "^3.7.0"
+
+validate-npm-package-license@^3.0.1:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
+  integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==
+  dependencies:
+    spdx-correct "^3.0.0"
+    spdx-expression-parse "^3.0.0"
+
+vargs@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/vargs/-/vargs-0.1.0.tgz#6b6184da6520cc3204ce1b407cac26d92609ebff"
+  integrity sha1-a2GE2mUgzDIEzhtAfKwm2SYJ6/8=
+
+vary@^1, vary@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
+  integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
+
+verror@1.10.0:
+  version "1.10.0"
+  resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
+  integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=
+  dependencies:
+    assert-plus "^1.0.0"
+    core-util-is "1.0.2"
+    extsprintf "^1.2.0"
+
+vinyl-file@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/vinyl-file/-/vinyl-file-2.0.0.tgz#a7ebf5ffbefda1b7d18d140fcb07b223efb6751a"
+  integrity sha1-p+v1/779obfRjRQPyweyI++2dRo=
+  dependencies:
+    graceful-fs "^4.1.2"
+    pify "^2.3.0"
+    pinkie-promise "^2.0.0"
+    strip-bom "^2.0.0"
+    strip-bom-stream "^2.0.0"
+    vinyl "^1.1.0"
+
+vinyl-fs@^2.4.3, vinyl-fs@^2.4.4:
+  version "2.4.4"
+  resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-2.4.4.tgz#be6ff3270cb55dfd7d3063640de81f25d7532239"
+  integrity sha1-vm/zJwy1Xf19MGNkDegfJddTIjk=
+  dependencies:
+    duplexify "^3.2.0"
+    glob-stream "^5.3.2"
+    graceful-fs "^4.0.0"
+    gulp-sourcemaps "1.6.0"
+    is-valid-glob "^0.3.0"
+    lazystream "^1.0.0"
+    lodash.isequal "^4.0.0"
+    merge-stream "^1.0.0"
+    mkdirp "^0.5.0"
+    object-assign "^4.0.0"
+    readable-stream "^2.0.4"
+    strip-bom "^2.0.0"
+    strip-bom-stream "^1.0.0"
+    through2 "^2.0.0"
+    through2-filter "^2.0.0"
+    vali-date "^1.0.0"
+    vinyl "^1.0.0"
+
+vinyl@^1.0.0, vinyl@^1.1.0, vinyl@^1.1.1, vinyl@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884"
+  integrity sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=
+  dependencies:
+    clone "^1.0.0"
+    clone-stats "^0.0.1"
+    replace-ext "0.0.1"
+
+vinyl@^2.0.1:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.2.0.tgz#d85b07da96e458d25b2ffe19fece9f2caa13ed86"
+  integrity sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==
+  dependencies:
+    clone "^2.1.1"
+    clone-buffer "^1.0.0"
+    clone-stats "^1.0.0"
+    cloneable-readable "^1.0.0"
+    remove-trailing-separator "^1.0.1"
+    replace-ext "^1.0.0"
+
+vlq@^0.2.2:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.3.tgz#8f3e4328cf63b1540c0d67e1b2778386f8975b26"
+  integrity sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==
+
+vscode-uri@=1.0.6:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-1.0.6.tgz#6b8f141b0bbc44ad7b07e94f82f168ac7608ad4d"
+  integrity sha512-sLI2L0uGov3wKVb9EB+vIQBl9tVP90nqRvxSoJ35vI3NjxE8jfsE5DSOhWgSunHSZmKS4OCi2jrtfxK7uyp2ww==
+
+wbuf@^1.1.0, wbuf@^1.7.2:
+  version "1.7.3"
+  resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df"
+  integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==
+  dependencies:
+    minimalistic-assert "^1.0.0"
+
+wct-local@^2.1.1:
+  version "2.1.5"
+  resolved "https://registry.yarnpkg.com/wct-local/-/wct-local-2.1.5.tgz#f7986753e3ad9a35d39178a9989350523561fff1"
+  integrity sha512-eqoZhjGy4Xq2tY0uB46Grkw/ztq+/rC0ImbYKl62unFHXtOgal+kkvnxR3SLRFNM8ty9+ItgycPeH0IpTqVL+w==
+  dependencies:
+    "@types/express" "^4.0.30"
+    "@types/freeport" "^1.0.19"
+    "@types/launchpad" "^0.6.0"
+    "@types/which" "^1.3.1"
+    chalk "^2.3.0"
+    cleankill "^2.0.0"
+    freeport "^1.0.4"
+    launchpad "^0.7.0"
+    selenium-standalone "^6.7.0"
+    which "^1.0.8"
+
+wct-sauce@^2.0.2:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/wct-sauce/-/wct-sauce-2.1.0.tgz#67d0be346aabbbc28384e8d143b8d3ca7ba774c0"
+  integrity sha512-c3R4PJcbpS7Gxv2vZ4HDAqpXV6cT9peslAWMU7hHH9PMhKDPbn8RNa6E4DVL0tOmZznB+3cRmtZ6+vJ/aDwu1A==
+  dependencies:
+    chalk "^2.4.1"
+    cleankill "^2.0.0"
+    lodash "^4.17.10"
+    request "^2.85.0"
+    sauce-connect-launcher "^1.0.0"
+    temp "^0.8.1"
+    uuid "^3.2.1"
+
+wd@^1.2.0:
+  version "1.12.1"
+  resolved "https://registry.yarnpkg.com/wd/-/wd-1.12.1.tgz#067eb3674db00eeb9e506701f9314657c44d5a89"
+  integrity sha512-O99X8OnOgkqfmsPyLIRzG9LmZ+rjmdGFBCyhGpnsSL4MB4xzHoeWmSVcumDiQ5QqPZcwGkszTgeJvjk2VjtiNw==
+  dependencies:
+    archiver "^3.0.0"
+    async "^2.0.0"
+    lodash "^4.0.0"
+    mkdirp "^0.5.1"
+    q "^1.5.1"
+    request "2.88.0"
+    vargs "^0.1.0"
+
+web-component-tester@^6.9.0:
+  version "6.9.2"
+  resolved "https://registry.yarnpkg.com/web-component-tester/-/web-component-tester-6.9.2.tgz#40a7b824f2cf3cbc4305552bdfc3357977ded48a"
+  integrity sha512-s2kB/+IE8XWcnxY1fqSpqTiiHEGHWgUWariAbiRlxmAvWSuvaCVNALHYebsZrLCNCLHKcJR8/sGv/bw0MWMvjw==
+  dependencies:
+    "@polymer/sinonjs" "^1.14.1"
+    "@polymer/test-fixture" "^0.0.3"
+    "@webcomponents/webcomponentsjs" "^1.0.7"
+    accessibility-developer-tools "^2.12.0"
+    async "^2.4.1"
+    body-parser "^1.17.2"
+    bower-config "^1.4.0"
+    chalk "^1.1.3"
+    cleankill "^2.0.0"
+    express "^4.15.3"
+    findup-sync "^2.0.0"
+    glob "^7.1.2"
+    lodash "^3.10.1"
+    multer "^1.3.0"
+    nomnom "^1.8.1"
+    polyserve "^0.27.13"
+    resolve "^1.5.0"
+    semver "^5.3.0"
+    send "^0.16.1"
+    server-destroy "^1.0.1"
+    sinon "^2.3.5"
+    sinon-chai "^2.10.0"
+    socket.io "^2.0.3"
+    stacky "^1.3.1"
+    wd "^1.2.0"
+  optionalDependencies:
+    update-notifier "^2.2.0"
+    wct-local "^2.1.1"
+    wct-sauce "^2.0.2"
+
+webidl-conversions@^4.0.2:
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
+  integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==
+
+whatwg-url@^6.4.0:
+  version "6.5.0"
+  resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.5.0.tgz#f2df02bff176fd65070df74ad5ccbb5a199965a8"
+  integrity sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==
+  dependencies:
+    lodash.sortby "^4.7.0"
+    tr46 "^1.0.1"
+    webidl-conversions "^4.0.2"
+
+which@^1.0.8, which@^1.2.12, which@^1.2.14, which@^1.2.9, which@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
+  integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
+  dependencies:
+    isexe "^2.0.0"
+
+which@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
+  integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
+  dependencies:
+    isexe "^2.0.0"
+
+widest-line@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-1.0.0.tgz#0c09c85c2a94683d0d7eaf8ee097d564bf0e105c"
+  integrity sha1-DAnIXCqUaD0Nfq+O4JfVZL8OEFw=
+  dependencies:
+    string-width "^1.0.1"
+
+widest-line@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.1.tgz#7438764730ec7ef4381ce4df82fb98a53142a3fc"
+  integrity sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==
+  dependencies:
+    string-width "^2.1.1"
+
+windows-release@^3.1.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.2.0.tgz#8122dad5afc303d833422380680a79cdfa91785f"
+  integrity sha512-QTlz2hKLrdqukrsapKsINzqMgOUpQW268eJ0OaOpJN32h272waxR9fkB9VoWRtK7uKHG5EHJcTXQBD8XZVJkFA==
+  dependencies:
+    execa "^1.0.0"
+
+winston-transport@^4.2.0, winston-transport@^4.3.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.3.0.tgz#df68c0c202482c448d9b47313c07304c2d7c2c66"
+  integrity sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A==
+  dependencies:
+    readable-stream "^2.3.6"
+    triple-beam "^1.2.0"
+
+winston@^3.0.0:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/winston/-/winston-3.2.1.tgz#63061377976c73584028be2490a1846055f77f07"
+  integrity sha512-zU6vgnS9dAWCEKg/QYigd6cgMVVNwyTzKs81XZtTFuRwJOcDdBg7AU0mXVyNbs7O5RH2zdv+BdNZUlx7mXPuOw==
+  dependencies:
+    async "^2.6.1"
+    diagnostics "^1.1.1"
+    is-stream "^1.1.0"
+    logform "^2.1.1"
+    one-time "0.0.4"
+    readable-stream "^3.1.1"
+    stack-trace "0.0.x"
+    triple-beam "^1.3.0"
+    winston-transport "^4.3.0"
+
+with-open-file@^0.1.6:
+  version "0.1.7"
+  resolved "https://registry.yarnpkg.com/with-open-file/-/with-open-file-0.1.7.tgz#e2de8d974e8a8ae6e58886be4fe8e7465b58a729"
+  integrity sha512-ecJS2/oHtESJ1t3ZfMI3B7KIDKyfN0O16miWxdn30zdh66Yd3LsRFebXZXq6GU4xfxLf6nVxp9kIqElb5fqczA==
+  dependencies:
+    p-finally "^1.0.0"
+    p-try "^2.1.0"
+    pify "^4.0.1"
+
+wordwrap@~0.0.2:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
+  integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc=
+
+wordwrapjs@^2.0.0-0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/wordwrapjs/-/wordwrapjs-2.0.0.tgz#ab55f695e6118da93858fdd70c053d1c5e01ac20"
+  integrity sha1-q1X2leYRjak4WP3XDAU9HF4BrCA=
+  dependencies:
+    array-back "^1.0.3"
+    feature-detect-es6 "^1.3.1"
+    reduce-flatten "^1.0.1"
+    typical "^2.6.0"
+
+wordwrapjs@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/wordwrapjs/-/wordwrapjs-3.0.0.tgz#c94c372894cadc6feb1a66bff64e1d9af92c5d1e"
+  integrity sha512-mO8XtqyPvykVCsrwj5MlOVWvSnCdT+C+QVbm6blradR7JExAhbkZ7hZ9A+9NUtwzSqrlUo9a67ws0EiILrvRpw==
+  dependencies:
+    reduce-flatten "^1.0.1"
+    typical "^2.6.1"
+
+wrappy@1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+  integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
+
+write-file-atomic@^1.1.2:
+  version "1.3.4"
+  resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f"
+  integrity sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=
+  dependencies:
+    graceful-fs "^4.1.11"
+    imurmurhash "^0.1.4"
+    slide "^1.1.5"
+
+write-file-atomic@^2.0.0:
+  version "2.4.3"
+  resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481"
+  integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==
+  dependencies:
+    graceful-fs "^4.1.11"
+    imurmurhash "^0.1.4"
+    signal-exit "^3.0.2"
+
+ws@^7.1.2:
+  version "7.2.1"
+  resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.1.tgz#03ed52423cd744084b2cf42ed197c8b65a936b8e"
+  integrity sha512-sucePNSafamSKoOqoNfBd8V0StlkzJKL2ZAhGQinCfNQ+oacw+Pk7lcdAElecBF2VkLNZRiIb5Oi1Q5lVUVt2A==
+
+ws@~6.1.0:
+  version "6.1.4"
+  resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9"
+  integrity sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==
+  dependencies:
+    async-limiter "~1.0.0"
+
+xdg-basedir@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2"
+  integrity sha1-7byQPMOF/ARSPZZqM1UEtVBNG9I=
+  dependencies:
+    os-homedir "^1.0.0"
+
+xdg-basedir@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4"
+  integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=
+
+xmlbuilder@8.2.2:
+  version "8.2.2"
+  resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-8.2.2.tgz#69248673410b4ba42e1a6136551d2922335aa773"
+  integrity sha1-aSSGc0ELS6QuGmE2VR0pIjNap3M=
+
+xmldom@0.1.x:
+  version "0.1.31"
+  resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.31.tgz#b76c9a1bd9f0a9737e5a72dc37231cf38375e2ff"
+  integrity sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==
+
+xmlhttprequest-ssl@~1.5.4:
+  version "1.5.5"
+  resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e"
+  integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=
+
+"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@~4.0.0, xtend@~4.0.1:
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
+  integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
+
+yallist@^2.1.2:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
+  integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
+
+yauzl@^2.10.0:
+  version "2.10.0"
+  resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9"
+  integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=
+  dependencies:
+    buffer-crc32 "~0.2.3"
+    fd-slicer "~1.1.0"
+
+yeast@0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"
+  integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk=
+
+yeoman-environment@^1.5.2:
+  version "1.6.6"
+  resolved "https://registry.yarnpkg.com/yeoman-environment/-/yeoman-environment-1.6.6.tgz#cd85fa67d156060e440d7807d7ef7cf0d2d1d671"
+  integrity sha1-zYX6Z9FWBg5EDXgH1+988NLR1nE=
+  dependencies:
+    chalk "^1.0.0"
+    debug "^2.0.0"
+    diff "^2.1.2"
+    escape-string-regexp "^1.0.2"
+    globby "^4.0.0"
+    grouped-queue "^0.3.0"
+    inquirer "^1.0.2"
+    lodash "^4.11.1"
+    log-symbols "^1.0.1"
+    mem-fs "^1.1.0"
+    text-table "^0.2.0"
+    untildify "^2.0.0"
+
+yeoman-environment@^2.0.5:
+  version "2.7.0"
+  resolved "https://registry.yarnpkg.com/yeoman-environment/-/yeoman-environment-2.7.0.tgz#d1b6679de883ce14a68b869c4b19d55a0d66f477"
+  integrity sha512-YNzSUWgJVSgnm0qgLON4Gb2nTm+kywBiWjK4MbvosjUP2YJJ30lNhEx7ukyzKRPUlsavd5IsuALtF6QaVrq81A==
+  dependencies:
+    chalk "^2.4.1"
+    cross-spawn "^6.0.5"
+    debug "^3.1.0"
+    diff "^3.5.0"
+    escape-string-regexp "^1.0.2"
+    globby "^8.0.1"
+    grouped-queue "^0.3.3"
+    inquirer "^6.0.0"
+    is-scoped "^1.0.0"
+    lodash "^4.17.10"
+    log-symbols "^2.2.0"
+    mem-fs "^1.1.0"
+    strip-ansi "^4.0.0"
+    text-table "^0.2.0"
+    untildify "^3.0.3"
+
+yeoman-generator@^3.1.1:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/yeoman-generator/-/yeoman-generator-3.2.0.tgz#02077d2d7ff28fedc1ed7dad7f9967fd7c3604cc"
+  integrity sha512-iR/qb2je3GdXtSfxgvOXxUW0Cp8+C6LaZaNlK2BAICzFNzwHtM10t/QBwz5Ea9nk6xVDQNj4Q889TjCXGuIv8w==
+  dependencies:
+    async "^2.6.0"
+    chalk "^2.3.0"
+    cli-table "^0.3.1"
+    cross-spawn "^6.0.5"
+    dargs "^6.0.0"
+    dateformat "^3.0.3"
+    debug "^4.1.0"
+    detect-conflict "^1.0.0"
+    error "^7.0.2"
+    find-up "^3.0.0"
+    github-username "^4.0.0"
+    istextorbinary "^2.2.1"
+    lodash "^4.17.10"
+    make-dir "^1.1.0"
+    mem-fs-editor "^5.0.0"
+    minimist "^1.2.0"
+    pretty-bytes "^5.1.0"
+    read-chunk "^3.0.0"
+    read-pkg-up "^4.0.0"
+    rimraf "^2.6.2"
+    run-async "^2.0.0"
+    shelljs "^0.8.0"
+    text-table "^0.2.0"
+    through2 "^3.0.0"
+    yeoman-environment "^2.0.5"
+
+zip-stream@^2.1.2:
+  version "2.1.3"
+  resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-2.1.3.tgz#26cc4bdb93641a8590dd07112e1f77af1758865b"
+  integrity sha512-EkXc2JGcKhO5N5aZ7TmuNo45budRaFGHOmz24wtJR7znbNqDPmdZtUauKX6et8KAVseAMBOyWJqEpXcHTBsh7Q==
+  dependencies:
+    archiver-utils "^2.1.0"
+    compress-commons "^2.1.1"
+    readable-stream "^3.4.0"
diff --git a/tools/nongoogle.bzl b/tools/nongoogle.bzl
index 1210504..73af4fd 100644
--- a/tools/nongoogle.bzl
+++ b/tools/nongoogle.bzl
@@ -102,8 +102,8 @@
     # and httpasyncclient as necessary.
     maven_jar(
         name = "elasticsearch-rest-client",
-        artifact = "org.elasticsearch.client:elasticsearch-rest-client:7.5.2",
-        sha1 = "e11393f600a425b7f62e6f653e19a9e53556fd79",
+        artifact = "org.elasticsearch.client:elasticsearch-rest-client:7.6.0",
+        sha1 = "3d56c1fca22af1aab5a1b23698ae9ec6f71db1a2",
     )
 
     maven_jar(
diff --git a/yarn.lock b/yarn.lock
new file mode 100644
index 0000000..a393f14
--- /dev/null
+++ b/yarn.lock
@@ -0,0 +1,9101 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@babel/code-frame@^7.0.0":
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8"
+  integrity sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==
+  dependencies:
+    "@babel/highlight" "^7.0.0"
+
+"@babel/core@^7.0.0":
+  version "7.5.4"
+  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.5.4.tgz#4c32df7ad5a58e9ea27ad025c11276324e0b4ddd"
+  integrity sha512-+DaeBEpYq6b2+ZmHx3tHspC+ZRflrvLqwfv8E3hNr5LVQoyBnL8RPKSBCg+rK2W2My9PWlujBiqd0ZPsR9Q6zQ==
+  dependencies:
+    "@babel/code-frame" "^7.0.0"
+    "@babel/generator" "^7.5.0"
+    "@babel/helpers" "^7.5.4"
+    "@babel/parser" "^7.5.0"
+    "@babel/template" "^7.4.4"
+    "@babel/traverse" "^7.5.0"
+    "@babel/types" "^7.5.0"
+    convert-source-map "^1.1.0"
+    debug "^4.1.0"
+    json5 "^2.1.0"
+    lodash "^4.17.11"
+    resolve "^1.3.2"
+    semver "^5.4.1"
+    source-map "^0.5.0"
+
+"@babel/generator@^7.0.0-beta.42", "@babel/generator@^7.5.0":
+  version "7.5.0"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.5.0.tgz#f20e4b7a91750ee8b63656073d843d2a736dca4a"
+  integrity sha512-1TTVrt7J9rcG5PMjvO7VEG3FrEoEJNHxumRq66GemPmzboLWtIjjcJgk8rokuAS7IiRSpgVSu5Vb9lc99iJkOA==
+  dependencies:
+    "@babel/types" "^7.5.0"
+    jsesc "^2.5.1"
+    lodash "^4.17.11"
+    source-map "^0.5.0"
+    trim-right "^1.0.1"
+
+"@babel/helper-annotate-as-pure@^7.0.0":
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32"
+  integrity sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==
+  dependencies:
+    "@babel/types" "^7.0.0"
+
+"@babel/helper-builder-binary-assignment-operator-visitor@^7.1.0":
+  version "7.1.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz#6b69628dfe4087798e0c4ed98e3d4a6b2fbd2f5f"
+  integrity sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==
+  dependencies:
+    "@babel/helper-explode-assignable-expression" "^7.1.0"
+    "@babel/types" "^7.0.0"
+
+"@babel/helper-call-delegate@^7.4.4":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz#87c1f8ca19ad552a736a7a27b1c1fcf8b1ff1f43"
+  integrity sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ==
+  dependencies:
+    "@babel/helper-hoist-variables" "^7.4.4"
+    "@babel/traverse" "^7.4.4"
+    "@babel/types" "^7.4.4"
+
+"@babel/helper-define-map@^7.4.4":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.4.4.tgz#6969d1f570b46bdc900d1eba8e5d59c48ba2c12a"
+  integrity sha512-IX3Ln8gLhZpSuqHJSnTNBWGDE9kdkTEWl21A/K7PQ00tseBwbqCHTvNLHSBd9M0R5rER4h5Rsvj9vw0R5SieBg==
+  dependencies:
+    "@babel/helper-function-name" "^7.1.0"
+    "@babel/types" "^7.4.4"
+    lodash "^4.17.11"
+
+"@babel/helper-explode-assignable-expression@^7.1.0":
+  version "7.1.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz#537fa13f6f1674df745b0c00ec8fe4e99681c8f6"
+  integrity sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==
+  dependencies:
+    "@babel/traverse" "^7.1.0"
+    "@babel/types" "^7.0.0"
+
+"@babel/helper-function-name@^7.1.0":
+  version "7.1.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53"
+  integrity sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==
+  dependencies:
+    "@babel/helper-get-function-arity" "^7.0.0"
+    "@babel/template" "^7.1.0"
+    "@babel/types" "^7.0.0"
+
+"@babel/helper-get-function-arity@^7.0.0":
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3"
+  integrity sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==
+  dependencies:
+    "@babel/types" "^7.0.0"
+
+"@babel/helper-hoist-variables@^7.4.4":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz#0298b5f25c8c09c53102d52ac4a98f773eb2850a"
+  integrity sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w==
+  dependencies:
+    "@babel/types" "^7.4.4"
+
+"@babel/helper-member-expression-to-functions@^7.0.0":
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz#8cd14b0a0df7ff00f009e7d7a436945f47c7a16f"
+  integrity sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg==
+  dependencies:
+    "@babel/types" "^7.0.0"
+
+"@babel/helper-module-imports@^7.0.0":
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d"
+  integrity sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==
+  dependencies:
+    "@babel/types" "^7.0.0"
+
+"@babel/helper-module-transforms@^7.1.0":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.4.4.tgz#96115ea42a2f139e619e98ed46df6019b94414b8"
+  integrity sha512-3Z1yp8TVQf+B4ynN7WoHPKS8EkdTbgAEy0nU0rs/1Kw4pDgmvYH3rz3aI11KgxKCba2cn7N+tqzV1mY2HMN96w==
+  dependencies:
+    "@babel/helper-module-imports" "^7.0.0"
+    "@babel/helper-simple-access" "^7.1.0"
+    "@babel/helper-split-export-declaration" "^7.4.4"
+    "@babel/template" "^7.4.4"
+    "@babel/types" "^7.4.4"
+    lodash "^4.17.11"
+
+"@babel/helper-optimise-call-expression@^7.0.0":
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz#a2920c5702b073c15de51106200aa8cad20497d5"
+  integrity sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==
+  dependencies:
+    "@babel/types" "^7.0.0"
+
+"@babel/helper-plugin-utils@^7.0.0":
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250"
+  integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==
+
+"@babel/helper-regex@^7.0.0", "@babel/helper-regex@^7.4.4":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.4.4.tgz#a47e02bc91fb259d2e6727c2a30013e3ac13c4a2"
+  integrity sha512-Y5nuB/kESmR3tKjU8Nkn1wMGEx1tjJX076HBMeL3XLQCu6vA/YRzuTW0bbb+qRnXvQGn+d6Rx953yffl8vEy7Q==
+  dependencies:
+    lodash "^4.17.11"
+
+"@babel/helper-remap-async-to-generator@^7.1.0":
+  version "7.1.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz#361d80821b6f38da75bd3f0785ece20a88c5fe7f"
+  integrity sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.0.0"
+    "@babel/helper-wrap-function" "^7.1.0"
+    "@babel/template" "^7.1.0"
+    "@babel/traverse" "^7.1.0"
+    "@babel/types" "^7.0.0"
+
+"@babel/helper-replace-supers@^7.1.0", "@babel/helper-replace-supers@^7.4.4":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.4.4.tgz#aee41783ebe4f2d3ab3ae775e1cc6f1a90cefa27"
+  integrity sha512-04xGEnd+s01nY1l15EuMS1rfKktNF+1CkKmHoErDppjAAZL+IUBZpzT748x262HF7fibaQPhbvWUl5HeSt1EXg==
+  dependencies:
+    "@babel/helper-member-expression-to-functions" "^7.0.0"
+    "@babel/helper-optimise-call-expression" "^7.0.0"
+    "@babel/traverse" "^7.4.4"
+    "@babel/types" "^7.4.4"
+
+"@babel/helper-simple-access@^7.1.0":
+  version "7.1.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz#65eeb954c8c245beaa4e859da6188f39d71e585c"
+  integrity sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==
+  dependencies:
+    "@babel/template" "^7.1.0"
+    "@babel/types" "^7.0.0"
+
+"@babel/helper-split-export-declaration@^7.4.4":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz#ff94894a340be78f53f06af038b205c49d993677"
+  integrity sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==
+  dependencies:
+    "@babel/types" "^7.4.4"
+
+"@babel/helper-wrap-function@^7.1.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz#c4e0012445769e2815b55296ead43a958549f6fa"
+  integrity sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ==
+  dependencies:
+    "@babel/helper-function-name" "^7.1.0"
+    "@babel/template" "^7.1.0"
+    "@babel/traverse" "^7.1.0"
+    "@babel/types" "^7.2.0"
+
+"@babel/helpers@^7.5.4":
+  version "7.5.4"
+  resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.5.4.tgz#2f00608aa10d460bde0ccf665d6dcf8477357cf0"
+  integrity sha512-6LJ6xwUEJP51w0sIgKyfvFMJvIb9mWAfohJp0+m6eHJigkFdcH8duZ1sfhn0ltJRzwUIT/yqqhdSfRpCpL7oow==
+  dependencies:
+    "@babel/template" "^7.4.4"
+    "@babel/traverse" "^7.5.0"
+    "@babel/types" "^7.5.0"
+
+"@babel/highlight@^7.0.0":
+  version "7.5.0"
+  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540"
+  integrity sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==
+  dependencies:
+    chalk "^2.0.0"
+    esutils "^2.0.2"
+    js-tokens "^4.0.0"
+
+"@babel/parser@^7.4.4", "@babel/parser@^7.5.0":
+  version "7.5.0"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.5.0.tgz#3e0713dff89ad6ae37faec3b29dcfc5c979770b7"
+  integrity sha512-I5nW8AhGpOXGCCNYGc+p7ExQIBxRFnS2fd/d862bNOKvmoEPjYPcfIjsfdy0ujagYOIYPczKgD9l3FsgTkAzKA==
+
+"@babel/plugin-external-helpers@^7.0.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-external-helpers/-/plugin-external-helpers-7.2.0.tgz#7f4cb7dee651cd380d2034847d914288467a6be4"
+  integrity sha512-QFmtcCShFkyAsNtdCM3lJPmRe1iB+vPZymlB4LnDIKEBj2yKQLQKtoxXxJ8ePT5fwMl4QGg303p4mB0UsSI2/g==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-proposal-async-generator-functions@^7.0.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz#b289b306669dce4ad20b0252889a15768c9d417e"
+  integrity sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+    "@babel/helper-remap-async-to-generator" "^7.1.0"
+    "@babel/plugin-syntax-async-generators" "^7.2.0"
+
+"@babel/plugin-proposal-object-rest-spread@^7.0.0":
+  version "7.5.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.5.4.tgz#250de35d867ce8260a31b1fdac6c4fc1baa99331"
+  integrity sha512-KCx0z3y7y8ipZUMAEEJOyNi11lMb/FOPUjjB113tfowgw0c16EGYos7worCKBcUAh2oG+OBnoUhsnTSoLpV9uA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+    "@babel/plugin-syntax-object-rest-spread" "^7.2.0"
+
+"@babel/plugin-syntax-async-generators@^7.0.0", "@babel/plugin-syntax-async-generators@^7.2.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz#69e1f0db34c6f5a0cf7e2b3323bf159a76c8cb7f"
+  integrity sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-syntax-dynamic-import@^7.0.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.2.0.tgz#69c159ffaf4998122161ad8ebc5e6d1f55df8612"
+  integrity sha512-mVxuJ0YroI/h/tbFTPGZR8cv6ai+STMKNBq0f8hFxsxWjl94qqhsb+wXbpNMDPU3cfR1TIsVFzU3nXyZMqyK4w==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-syntax-import-meta@^7.0.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.2.0.tgz#2333ef4b875553a3bcd1e93f8ebc09f5b9213a40"
+  integrity sha512-Hq6kFSZD7+PHkmBN8bCpHR6J8QEoCuEV/B38AIQscYjgMZkGlXB7cHNFzP5jR4RCh5545yP1ujHdmO7hAgKtBA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.2.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz#3b7a3e733510c57e820b9142a6579ac8b0dfad2e"
+  integrity sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-arrow-functions@^7.0.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz#9aeafbe4d6ffc6563bf8f8372091628f00779550"
+  integrity sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-async-to-generator@^7.0.0":
+  version "7.5.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.5.0.tgz#89a3848a0166623b5bc481164b5936ab947e887e"
+  integrity sha512-mqvkzwIGkq0bEF1zLRRiTdjfomZJDV33AH3oQzHVGkI2VzEmXLpKKOBvEVaFZBJdN0XTyH38s9j/Kiqr68dggg==
+  dependencies:
+    "@babel/helper-module-imports" "^7.0.0"
+    "@babel/helper-plugin-utils" "^7.0.0"
+    "@babel/helper-remap-async-to-generator" "^7.1.0"
+
+"@babel/plugin-transform-block-scoped-functions@^7.0.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz#5d3cc11e8d5ddd752aa64c9148d0db6cb79fd190"
+  integrity sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-block-scoping@^7.0.0":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.4.4.tgz#c13279fabf6b916661531841a23c4b7dae29646d"
+  integrity sha512-jkTUyWZcTrwxu5DD4rWz6rDB5Cjdmgz6z7M7RLXOJyCUkFBawssDGcGh8M/0FTSB87avyJI1HsTwUXp9nKA1PA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+    lodash "^4.17.11"
+
+"@babel/plugin-transform-classes@^7.0.0":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.4.4.tgz#0ce4094cdafd709721076d3b9c38ad31ca715eb6"
+  integrity sha512-/e44eFLImEGIpL9qPxSRat13I5QNRgBLu2hOQJCF7VLy/otSM/sypV1+XaIw5+502RX/+6YaSAPmldk+nhHDPw==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.0.0"
+    "@babel/helper-define-map" "^7.4.4"
+    "@babel/helper-function-name" "^7.1.0"
+    "@babel/helper-optimise-call-expression" "^7.0.0"
+    "@babel/helper-plugin-utils" "^7.0.0"
+    "@babel/helper-replace-supers" "^7.4.4"
+    "@babel/helper-split-export-declaration" "^7.4.4"
+    globals "^11.1.0"
+
+"@babel/plugin-transform-computed-properties@^7.0.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz#83a7df6a658865b1c8f641d510c6f3af220216da"
+  integrity sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-destructuring@^7.0.0":
+  version "7.5.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.5.0.tgz#f6c09fdfe3f94516ff074fe877db7bc9ef05855a"
+  integrity sha512-YbYgbd3TryYYLGyC7ZR+Tq8H/+bCmwoaxHfJHupom5ECstzbRLTch6gOQbhEY9Z4hiCNHEURgq06ykFv9JZ/QQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-duplicate-keys@^7.0.0":
+  version "7.5.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.5.0.tgz#c5dbf5106bf84cdf691222c0974c12b1df931853"
+  integrity sha512-igcziksHizyQPlX9gfSjHkE2wmoCH3evvD2qR5w29/Dk0SMKE/eOI7f1HhBdNhR/zxJDqrgpoDTq5YSLH/XMsQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-exponentiation-operator@^7.0.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz#a63868289e5b4007f7054d46491af51435766008"
+  integrity sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A==
+  dependencies:
+    "@babel/helper-builder-binary-assignment-operator-visitor" "^7.1.0"
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-for-of@^7.0.0":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz#0267fc735e24c808ba173866c6c4d1440fc3c556"
+  integrity sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-function-name@^7.0.0":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz#e1436116abb0610c2259094848754ac5230922ad"
+  integrity sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA==
+  dependencies:
+    "@babel/helper-function-name" "^7.1.0"
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-instanceof@^7.0.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-instanceof/-/plugin-transform-instanceof-7.2.0.tgz#2ee9dc9b389fa13cf325be10ff8414be0d10aecf"
+  integrity sha512-tw2fb96tpcd5XaJXns19tGKo/SeIUS0exAteHJ/7EP27Bke7RmV/gAftHCf1WKZgKeZOUfzOL7nrXH2HIH9auA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-literals@^7.0.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz#690353e81f9267dad4fd8cfd77eafa86aba53ea1"
+  integrity sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-modules-amd@^7.0.0":
+  version "7.5.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.5.0.tgz#ef00435d46da0a5961aa728a1d2ecff063e4fb91"
+  integrity sha512-n20UsQMKnWrltocZZm24cRURxQnWIvsABPJlw/fvoy9c6AgHZzoelAIzajDHAQrDpuKFFPPcFGd7ChsYuIUMpg==
+  dependencies:
+    "@babel/helper-module-transforms" "^7.1.0"
+    "@babel/helper-plugin-utils" "^7.0.0"
+    babel-plugin-dynamic-import-node "^2.3.0"
+
+"@babel/plugin-transform-object-super@^7.0.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.2.0.tgz#b35d4c10f56bab5d650047dad0f1d8e8814b6598"
+  integrity sha512-VMyhPYZISFZAqAPVkiYb7dUe2AsVi2/wCT5+wZdsNO31FojQJa9ns40hzZ6U9f50Jlq4w6qwzdBB2uwqZ00ebg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+    "@babel/helper-replace-supers" "^7.1.0"
+
+"@babel/plugin-transform-parameters@^7.0.0":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz#7556cf03f318bd2719fe4c922d2d808be5571e16"
+  integrity sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw==
+  dependencies:
+    "@babel/helper-call-delegate" "^7.4.4"
+    "@babel/helper-get-function-arity" "^7.0.0"
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-regenerator@^7.0.0":
+  version "7.4.5"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.5.tgz#629dc82512c55cee01341fb27bdfcb210354680f"
+  integrity sha512-gBKRh5qAaCWntnd09S8QC7r3auLCqq5DI6O0DlfoyDjslSBVqBibrMdsqO+Uhmx3+BlOmE/Kw1HFxmGbv0N9dA==
+  dependencies:
+    regenerator-transform "^0.14.0"
+
+"@babel/plugin-transform-shorthand-properties@^7.0.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz#6333aee2f8d6ee7e28615457298934a3b46198f0"
+  integrity sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-spread@^7.0.0":
+  version "7.2.2"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.2.2.tgz#3103a9abe22f742b6d406ecd3cd49b774919b406"
+  integrity sha512-KWfky/58vubwtS0hLqEnrWJjsMGaOeSBn90Ezn5Jeg9Z8KKHmELbP1yGylMlm5N6TPKeY9A2+UaSYLdxahg01w==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-sticky-regex@^7.0.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz#a1e454b5995560a9c1e0d537dfc15061fd2687e1"
+  integrity sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+    "@babel/helper-regex" "^7.0.0"
+
+"@babel/plugin-transform-template-literals@^7.0.0":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz#9d28fea7bbce637fb7612a0750989d8321d4bcb0"
+  integrity sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.0.0"
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-typeof-symbol@^7.0.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz#117d2bcec2fbf64b4b59d1f9819894682d29f2b2"
+  integrity sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-unicode-regex@^7.0.0":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.4.4.tgz#ab4634bb4f14d36728bf5978322b35587787970f"
+  integrity sha512-il+/XdNw01i93+M9J9u4T7/e/Ue/vWfNZE4IRUQjplu2Mqb/AFTDimkw2tdEdSH50wuQXZAbXSql0UphQke+vA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+    "@babel/helper-regex" "^7.4.4"
+    regexpu-core "^4.5.4"
+
+"@babel/template@^7.1.0", "@babel/template@^7.4.4":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.4.tgz#f4b88d1225689a08f5bc3a17483545be9e4ed237"
+  integrity sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==
+  dependencies:
+    "@babel/code-frame" "^7.0.0"
+    "@babel/parser" "^7.4.4"
+    "@babel/types" "^7.4.4"
+
+"@babel/traverse@^7.0.0", "@babel/traverse@^7.0.0-beta.42", "@babel/traverse@^7.1.0", "@babel/traverse@^7.4.4", "@babel/traverse@^7.5.0":
+  version "7.5.0"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.5.0.tgz#4216d6586854ef5c3c4592dab56ec7eb78485485"
+  integrity sha512-SnA9aLbyOCcnnbQEGwdfBggnc142h/rbqqsXcaATj2hZcegCl903pUD/lfpsNBlBSuWow/YDfRyJuWi2EPR5cg==
+  dependencies:
+    "@babel/code-frame" "^7.0.0"
+    "@babel/generator" "^7.5.0"
+    "@babel/helper-function-name" "^7.1.0"
+    "@babel/helper-split-export-declaration" "^7.4.4"
+    "@babel/parser" "^7.5.0"
+    "@babel/types" "^7.5.0"
+    debug "^4.1.0"
+    globals "^11.1.0"
+    lodash "^4.17.11"
+
+"@babel/types@^7.0.0", "@babel/types@^7.0.0-beta.42", "@babel/types@^7.2.0", "@babel/types@^7.4.4", "@babel/types@^7.5.0":
+  version "7.5.0"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.5.0.tgz#e47d43840c2e7f9105bc4d3a2c371b4d0c7832ab"
+  integrity sha512-UFpDVqRABKsW01bvw7/wSUe56uy6RXM5+VJibVVAybDGxEW25jdwiFJEf7ASvSaC7sN7rbE/l3cLp2izav+CtQ==
+  dependencies:
+    esutils "^2.0.2"
+    lodash "^4.17.11"
+    to-fast-properties "^2.0.0"
+
+"@bazel/rollup@^1.1.0":
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/@bazel/rollup/-/rollup-1.2.0.tgz#8b9569ed6f1c00d2a833567901f8ee4600a389fb"
+  integrity sha512-yrXW+AAUoqc9qN/CweD5p8OEN9bNKFjXnXPBRE4w84LxpkmaJFx+yQJ++c1F57zWMoq2o9EV4CM7y+mK8zxwUg==
+
+"@bazel/typescript@^1.0.1":
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-1.2.0.tgz#ab2016e1d6eb7a86b44536e887f51eaf3d75f1a7"
+  integrity sha512-hPEG8K0psyEcs6HFRiqZNQwXL/dQ8sXKdrNFWv87+rh+YUNfd58uktoynhllympOPThcbUZcZicLWBEFQOc8nA==
+  dependencies:
+    protobufjs "6.8.8"
+    semver "5.6.0"
+    source-map-support "0.5.9"
+    tsutils "2.27.2"
+
+"@mrmlnc/readdir-enhanced@^2.2.1":
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
+  integrity sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==
+  dependencies:
+    call-me-maybe "^1.0.1"
+    glob-to-regexp "^0.3.0"
+
+"@nodelib/fs.stat@^1.1.2":
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b"
+  integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==
+
+"@octokit/endpoint@^5.1.0":
+  version "5.2.1"
+  resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-5.2.1.tgz#e5ef98bc4a41fad62b17e71af1a1710f6076b8df"
+  integrity sha512-GoUsRSRhtbCQugRY8eDWg5BnsczUZNq00qArrP7tKPHFmvz2KzJ8DoEq6IAQhLGwAOBHbZQ/Zml3DiaEKAWwkA==
+  dependencies:
+    deepmerge "4.0.0"
+    is-plain-object "^3.0.0"
+    universal-user-agent "^2.1.0"
+    url-template "^2.0.8"
+
+"@octokit/request-error@^1.0.1", "@octokit/request-error@^1.0.2":
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-1.0.4.tgz#15e1dc22123ba4a9a4391914d80ec1e5303a23be"
+  integrity sha512-L4JaJDXn8SGT+5G0uX79rZLv0MNJmfGa4vb4vy1NnpjSnWDLJRy6m90udGwvMmavwsStgbv2QNkPzzTCMmL+ig==
+  dependencies:
+    deprecation "^2.0.0"
+    once "^1.4.0"
+
+"@octokit/request@^4.0.1":
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/@octokit/request/-/request-4.1.1.tgz#614262214f48417b4d3b14e047d09a9c8e2f7a09"
+  integrity sha512-LOyL0i3oxRo418EXRSJNk/3Q4I0/NKawTn6H/CQp+wnrG1UFLGu080gSsgnWobhPo5BpUNgSQ5BRk5FOOJhD1Q==
+  dependencies:
+    "@octokit/endpoint" "^5.1.0"
+    "@octokit/request-error" "^1.0.1"
+    deprecation "^2.0.0"
+    is-plain-object "^3.0.0"
+    node-fetch "^2.3.0"
+    once "^1.4.0"
+    universal-user-agent "^2.1.0"
+
+"@octokit/rest@^16.2.0":
+  version "16.28.2"
+  resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-16.28.2.tgz#3fc3b8700046ab29ab1e2a4bdf49f89e94f7ba27"
+  integrity sha512-csuYiHvJ1P/GFDadVn0QhwO83R1+YREjcwCY7ZIezB6aJTRIEidJZj+R7gAkUhT687cqYb4cXTZsDVu9F+Fmug==
+  dependencies:
+    "@octokit/request" "^4.0.1"
+    "@octokit/request-error" "^1.0.2"
+    atob-lite "^2.0.0"
+    before-after-hook "^1.4.0"
+    btoa-lite "^1.0.0"
+    deprecation "^2.0.0"
+    lodash.get "^4.4.2"
+    lodash.set "^4.3.2"
+    lodash.uniq "^4.5.0"
+    octokit-pagination-methods "^1.1.0"
+    once "^1.4.0"
+    universal-user-agent "^2.0.0"
+    url-template "^2.0.8"
+
+"@polymer/esm-amd-loader@^1.0.0":
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/@polymer/esm-amd-loader/-/esm-amd-loader-1.0.4.tgz#4e77f2f59b29b01e0ad02aa83d33716cddc5f9f9"
+  integrity sha512-h+hqYkL+tQV/y2ESD5gFXMl5z4cC+XY1jTlBeGSBaTcj3VbB5OBEScbvRXm63NcEbBneQQYbHfBAXAkF9i9wIA==
+
+"@polymer/sinonjs@^1.14.1":
+  version "1.17.1"
+  resolved "https://registry.yarnpkg.com/@polymer/sinonjs/-/sinonjs-1.17.1.tgz#e47d3785b7d0e8c29feb97f7e924b0fc597e2e9b"
+  integrity sha512-/U8F/cOTrbF2iVVYgINYmvKbtbexs+89Q3v8AaHADRYabTg7aOZGOb0RyWpOI+sUJt04kj63U4FwMhzW5r4wZA==
+
+"@polymer/test-fixture@^0.0.3":
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/@polymer/test-fixture/-/test-fixture-0.0.3.tgz#4443752697d4d9293bbc412ea0b5e4d341f149d9"
+  integrity sha1-REN1JpfU2Sk7vEEuoLXk00HxSdk=
+
+"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf"
+  integrity sha1-m4sMxmPWaafY9vXQiToU00jzD78=
+
+"@protobufjs/base64@^1.1.2":
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735"
+  integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==
+
+"@protobufjs/codegen@^2.0.4":
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb"
+  integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==
+
+"@protobufjs/eventemitter@^1.1.0":
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70"
+  integrity sha1-NVy8mLr61ZePntCV85diHx0Ga3A=
+
+"@protobufjs/fetch@^1.1.0":
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45"
+  integrity sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=
+  dependencies:
+    "@protobufjs/aspromise" "^1.1.1"
+    "@protobufjs/inquire" "^1.1.0"
+
+"@protobufjs/float@^1.0.2":
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1"
+  integrity sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=
+
+"@protobufjs/inquire@^1.1.0":
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089"
+  integrity sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=
+
+"@protobufjs/path@^1.1.2":
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d"
+  integrity sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=
+
+"@protobufjs/pool@^1.1.0":
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54"
+  integrity sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=
+
+"@protobufjs/utf8@^1.1.0":
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
+  integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=
+
+"@types/babel-generator@^6.25.1":
+  version "6.25.3"
+  resolved "https://registry.yarnpkg.com/@types/babel-generator/-/babel-generator-6.25.3.tgz#8f06caa12d0595a0538560abe771966d77d29286"
+  integrity sha512-pGgnuxVddKcYIc+VJkRDop7gxLhqclNKBdlsm/5Vp8d+37pQkkDK7fef8d9YYImRzw9xcojEPc18pUYnbxmjqA==
+  dependencies:
+    "@types/babel-types" "*"
+
+"@types/babel-traverse@^6.25.2", "@types/babel-traverse@^6.25.3":
+  version "6.25.5"
+  resolved "https://registry.yarnpkg.com/@types/babel-traverse/-/babel-traverse-6.25.5.tgz#6d293cf7523e48b524faa7b86dc3c488191484e5"
+  integrity sha512-WrMbwmu+MWf8FiUMbmVOGkc7bHPzndUafn1CivMaBHthBBoo0VNIcYk1KV71UovYguhsNOwf3UF5oRmkkGOU3w==
+  dependencies:
+    "@types/babel-types" "*"
+
+"@types/babel-types@*", "@types/babel-types@^6.25.1":
+  version "6.25.2"
+  resolved "https://registry.yarnpkg.com/@types/babel-types/-/babel-types-6.25.2.tgz#5c57f45973e4f13742dbc5273dd84cffe7373a9e"
+  integrity sha512-+3bMuktcY4a70a0KZc8aPJlEOArPuAKQYHU5ErjkOqGJdx8xuEEVK6nWogqigBOJ8nKPxRpyCUDTCPmZ3bUxGA==
+
+"@types/babylon@^6.16.2":
+  version "6.16.5"
+  resolved "https://registry.yarnpkg.com/@types/babylon/-/babylon-6.16.5.tgz#1c5641db69eb8cdf378edd25b4be7754beeb48b4"
+  integrity sha512-xH2e58elpj1X4ynnKp9qSnWlsRTIs6n3tgLGNfwAGHwePw0mulHQllV34n0T25uYSu1k0hRKkWXF890B1yS47w==
+  dependencies:
+    "@types/babel-types" "*"
+
+"@types/bluebird@*":
+  version "3.5.29"
+  resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.29.tgz#7cd933c902c4fc83046517a1bef973886d00bdb6"
+  integrity sha512-kmVtnxTuUuhCET669irqQmPAez4KFnFVKvpleVRyfC3g+SHD1hIkFZcWLim9BVcwUBLO59o8VZE4yGCmTif8Yw==
+
+"@types/body-parser@*":
+  version "1.17.1"
+  resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.17.1.tgz#18fcf61768fb5c30ccc508c21d6fd2e8b3bf7897"
+  integrity sha512-RoX2EZjMiFMjZh9lmYrwgoP9RTpAjSHiJxdp4oidAQVO02T7HER3xj9UKue5534ULWeqVEkujhWcyvUce+d68w==
+  dependencies:
+    "@types/connect" "*"
+    "@types/node" "*"
+
+"@types/chai-subset@^1.3.0":
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/@types/chai-subset/-/chai-subset-1.3.2.tgz#16e3267e0557aaec0d77651c0ce27b684f4602c1"
+  integrity sha512-VMA1aOXwPEJADlj5ykmYv77YKmbEuAxiLz/+lT6vFIWQ1EA06jF01TytVBAbVTNk0pjfW1Uhw5R5MaEq426N0A==
+  dependencies:
+    "@types/chai" "*"
+
+"@types/chai@*":
+  version "4.1.7"
+  resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.7.tgz#1b8e33b61a8c09cbe1f85133071baa0dbf9fa71a"
+  integrity sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA==
+
+"@types/chalk@^0.4.30":
+  version "0.4.31"
+  resolved "https://registry.yarnpkg.com/@types/chalk/-/chalk-0.4.31.tgz#a31d74241a6b1edbb973cf36d97a2896834a51f9"
+  integrity sha1-ox10JBprHtu5c8822XooloNKUfk=
+
+"@types/chalk@^2.2.0":
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/@types/chalk/-/chalk-2.2.0.tgz#b7f6e446f4511029ee8e3f43075fb5b73fbaa0ba"
+  integrity sha512-1zzPV9FDe1I/WHhRkf9SNgqtRJWZqrBWgu7JGveuHmmyR9CnAPCie2N/x+iHrgnpYBIcCJWHBoMRv2TRWktsvw==
+  dependencies:
+    chalk "*"
+
+"@types/cheerio@^0.22.2":
+  version "0.22.15"
+  resolved "https://registry.yarnpkg.com/@types/cheerio/-/cheerio-0.22.15.tgz#69040ffa92c309beeeeb7e92db66ac3f80700c0b"
+  integrity sha512-UGiiVtJK5niCqMKYmLEFz1Wl/3L5zF/u78lu8CwoUywWXRr9LDimeYuOzXVLXBMO758fcTdFtgjvqlztMH90MA==
+  dependencies:
+    "@types/node" "*"
+
+"@types/clean-css@*":
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/@types/clean-css/-/clean-css-4.2.1.tgz#cb0134241ec5e6ede1b5344bc829668fd9871a8d"
+  integrity sha512-A1HQhQ0hkvqqByJMgg+Wiv9p9XdoYEzuwm11SVo1mX2/4PSdhjcrUlilJQoqLscIheC51t1D5g+EFWCXZ2VTQQ==
+  dependencies:
+    "@types/node" "*"
+
+"@types/clone@^0.1.30":
+  version "0.1.30"
+  resolved "https://registry.yarnpkg.com/@types/clone/-/clone-0.1.30.tgz#e7365648c1b42136a59c7d5040637b3b5c83b614"
+  integrity sha1-5zZWSMG0ITalnH1QQGN7O1yDthQ=
+
+"@types/compression@^0.0.33":
+  version "0.0.33"
+  resolved "https://registry.yarnpkg.com/@types/compression/-/compression-0.0.33.tgz#95dc733a2339aa846381d7f1377792d2553dc27d"
+  integrity sha1-ldxzOiM5qoRjgdfxN3eS0lU9wn0=
+  dependencies:
+    "@types/express" "*"
+
+"@types/connect@*":
+  version "3.4.33"
+  resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.33.tgz#31610c901eca573b8713c3330abc6e6b9f588546"
+  integrity sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==
+  dependencies:
+    "@types/node" "*"
+
+"@types/content-type@^1.1.0":
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/@types/content-type/-/content-type-1.1.3.tgz#3688bd77fc12f935548eef102a4e34c512b03a07"
+  integrity sha512-pv8VcFrZ3fN93L4rTNIbbUzdkzjEyVMp5mPVjsFfOYTDOZMZiZ8P1dhu+kEv3faYyKzZgLlSvnyQNFg+p/v5ug==
+
+"@types/cssbeautify@^0.3.1":
+  version "0.3.1"
+  resolved "https://registry.yarnpkg.com/@types/cssbeautify/-/cssbeautify-0.3.1.tgz#8e0bee8f7decb952250da0caebe05e30591c17ef"
+  integrity sha1-jgvuj33suVIlDaDK6+BeMFkcF+8=
+
+"@types/del@^3.0.0":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@types/del/-/del-3.0.1.tgz#4712da8c119873cbbf533ad8dbf1baac5940ac5d"
+  integrity sha512-y6qRq6raBuu965clKgx6FHuiPu3oHdtmzMPXi8Uahsjdq1L6DL5fS/aY5/s71YwM7k6K1QIWvem5vNwlnNGIkQ==
+  dependencies:
+    "@types/glob" "*"
+
+"@types/doctrine@^0.0.1":
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/@types/doctrine/-/doctrine-0.0.1.tgz#b999f2d9f7b43cabe0a1a2f39bc203bc7dcada9d"
+  integrity sha1-uZny2fe0PKvgoaLzm8IDvH3K2p0=
+
+"@types/escape-html@0.0.20":
+  version "0.0.20"
+  resolved "https://registry.yarnpkg.com/@types/escape-html/-/escape-html-0.0.20.tgz#cae698714dd61ebee5ab3f2aeb9a34ba1011735a"
+  integrity sha512-6dhZJLbA7aOwkYB2GDGdIqJ20wmHnkDzaxV9PJXe7O02I2dSFTERzRB6JrX6cWKaS+VqhhY7cQUMCbO5kloFUw==
+
+"@types/estree@0.0.39":
+  version "0.0.39"
+  resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
+  integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==
+
+"@types/events@*":
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
+  integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==
+
+"@types/express-serve-static-core@*":
+  version "4.17.1"
+  resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.1.tgz#82be64a77211b205641e0209096fd3afb62481d3"
+  integrity sha512-9e7jj549ZI+RxY21Cl0t8uBnWyb22HzILupyHZjYEVK//5TT/1bZodU+yUbLnPdoYViBBnNWbxp4zYjGV0zUGw==
+  dependencies:
+    "@types/node" "*"
+    "@types/range-parser" "*"
+
+"@types/express@*", "@types/express@^4.0.30", "@types/express@^4.0.36":
+  version "4.17.2"
+  resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.2.tgz#a0fb7a23d8855bac31bc01d5a58cadd9b2173e6c"
+  integrity sha512-5mHFNyavtLoJmnusB8OKJ5bshSzw+qkMIBAobLrIM48HJvunFva9mOa6aBwh64lBFyNwBbs0xiEFuj4eU/NjCA==
+  dependencies:
+    "@types/body-parser" "*"
+    "@types/express-serve-static-core" "*"
+    "@types/serve-static" "*"
+
+"@types/fast-levenshtein@0.0.1":
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/@types/fast-levenshtein/-/fast-levenshtein-0.0.1.tgz#3a3615cf173645c8fca58d051e4e32824e4bd286"
+  integrity sha1-OjYVzxc2Rcj8pY0FHk4ygk5L0oY=
+
+"@types/findup-sync@^0.3.29":
+  version "0.3.30"
+  resolved "https://registry.yarnpkg.com/@types/findup-sync/-/findup-sync-0.3.30.tgz#8ab7bdbd6ba7cbf4f33b6596fde6fff1129c738d"
+  integrity sha512-Dpt1x3rhz6t8BMTS4vziTVos8VLkF4RngIxMBCSE6w0STmnVEEaoe3w+BG5xHyZXshye9lyZE99lpBDoLGY8eA==
+  dependencies:
+    "@types/minimatch" "*"
+
+"@types/form-data@*":
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/@types/form-data/-/form-data-2.2.1.tgz#ee2b3b8eaa11c0938289953606b745b738c54b1e"
+  integrity sha512-JAMFhOaHIciYVh8fb5/83nmuO/AHwmto+Hq7a9y8FzLDcC1KCU344XDOMEmahnrTFlHjgh4L0WJFczNIX2GxnQ==
+  dependencies:
+    "@types/node" "*"
+
+"@types/freeport@^1.0.19":
+  version "1.0.21"
+  resolved "https://registry.yarnpkg.com/@types/freeport/-/freeport-1.0.21.tgz#73f6543ed67d3ca3fff97b985591598b7092066f"
+  integrity sha1-c/ZUPtZ9PKP/+XuYVZFZi3CSBm8=
+
+"@types/glob-stream@*":
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/@types/glob-stream/-/glob-stream-6.1.0.tgz#7ede8a33e59140534f8d8adfb8ac9edfb31897bc"
+  integrity sha512-RHv6ZQjcTncXo3thYZrsbAVwoy4vSKosSWhuhuQxLOTv74OJuFQxXkmUuZCr3q9uNBEVCvIzmZL/FeRNbHZGUg==
+  dependencies:
+    "@types/glob" "*"
+    "@types/node" "*"
+
+"@types/glob@*":
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575"
+  integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==
+  dependencies:
+    "@types/events" "*"
+    "@types/minimatch" "*"
+    "@types/node" "*"
+
+"@types/globby@^6.1.0":
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/@types/globby/-/globby-6.1.0.tgz#7c25b975512a89effea2a656ca8cf6db7fb29d11"
+  integrity sha512-j3XSDNoK4LO5T+ZviQD6PqfEjm07QFEacOTbJR3hnLWuWX0ZMLJl9oRPgj1PyrfGbXhfHFkksC9QZ9HFltJyrw==
+  dependencies:
+    "@types/glob" "*"
+
+"@types/gulp-if@0.0.33":
+  version "0.0.33"
+  resolved "https://registry.yarnpkg.com/@types/gulp-if/-/gulp-if-0.0.33.tgz#edece22b7925d9a6db5f9c8c0d7882aa776fb678"
+  integrity sha512-J5lzff21X7r1x/4hSzn02GgIUEyjCqYIXZ9GgGBLhbsD3RiBdqwnkFWgF16/0jO5rcVZ52Zp+6MQMQdvIsWuKg==
+  dependencies:
+    "@types/node" "*"
+    "@types/vinyl" "*"
+
+"@types/html-minifier@^3.5.1":
+  version "3.5.3"
+  resolved "https://registry.yarnpkg.com/@types/html-minifier/-/html-minifier-3.5.3.tgz#5276845138db2cebc54c789e0aaf87621a21e84f"
+  integrity sha512-j1P/4PcWVVCPEy5lofcHnQ6BtXz9tHGiFPWzqm7TtGuWZEfCHEP446HlkSNc9fQgNJaJZ6ewPtp2aaFla/Uerg==
+  dependencies:
+    "@types/clean-css" "*"
+    "@types/relateurl" "*"
+    "@types/uglify-js" "*"
+
+"@types/inquirer@*", "@types/inquirer@0.0.32":
+  version "0.0.32"
+  resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-0.0.32.tgz#a4a08e83741c500a7c3c8e7776014f7f8a65870d"
+  integrity sha1-pKCOg3QcUAp8PI53dgFPf4plhw0=
+  dependencies:
+    "@types/rx" "*"
+    "@types/through" "*"
+
+"@types/is-windows@^0.2.0":
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/@types/is-windows/-/is-windows-0.2.0.tgz#6f24ee48731d31168ea510610d6dd15e5fc9c6ff"
+  integrity sha1-byTuSHMdMRaOpRBhDW3RXl/Jxv8=
+
+"@types/launchpad@^0.6.0":
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/@types/launchpad/-/launchpad-0.6.0.tgz#37296109b7f277f6e6c5fd7e0c0706bc918fbb51"
+  integrity sha1-NylhCbfyd/bmxf1+DAcGvJGPu1E=
+
+"@types/long@^4.0.0":
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9"
+  integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==
+
+"@types/merge-stream@^1.0.28":
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/@types/merge-stream/-/merge-stream-1.1.2.tgz#a880ff66b1fbbb5eef4958d015c5947a9334dbb1"
+  integrity sha512-7faLmaE99g/yX0Y9pF1neh2IUqOf/fXMOWCVzsXjqI1EJ91lrgXmaBKf6bRWM164lLyiHxHt6t/ZO/cIzq61XA==
+  dependencies:
+    "@types/node" "*"
+
+"@types/mime@*", "@types/mime@^2.0.0":
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d"
+  integrity sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==
+
+"@types/minimatch@*", "@types/minimatch@^3.0.1":
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
+  integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
+
+"@types/mz@0.0.29":
+  version "0.0.29"
+  resolved "https://registry.yarnpkg.com/@types/mz/-/mz-0.0.29.tgz#bc24728c649973f1c7851e9033f9ce525668c27b"
+  integrity sha1-vCRyjGSZc/HHhR6QM/nOUlZowns=
+  dependencies:
+    "@types/bluebird" "*"
+    "@types/node" "*"
+
+"@types/mz@0.0.31", "@types/mz@^0.0.31":
+  version "0.0.31"
+  resolved "https://registry.yarnpkg.com/@types/mz/-/mz-0.0.31.tgz#a4d80c082fefe71e40a7c0f07d1e6555bbbc7b52"
+  integrity sha1-pNgMCC/v5x5Ap8DwfR5lVbu8e1I=
+  dependencies:
+    "@types/node" "*"
+
+"@types/node@*", "@types/node@^12.0.10":
+  version "12.6.1"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-12.6.1.tgz#d5544f6de0aae03eefbb63d5120f6c8be0691946"
+  integrity sha512-rp7La3m845mSESCgsJePNL/JQyhkOJA6G4vcwvVgkDAwHhGdq5GCumxmPjEk1MZf+8p5ZQAUE7tqgQRQTXN7uQ==
+
+"@types/node@^10.1.0":
+  version "10.17.13"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.13.tgz#ccebcdb990bd6139cd16e84c39dc2fb1023ca90c"
+  integrity sha512-pMCcqU2zT4TjqYFrWtYHKal7Sl30Ims6ulZ4UFXxI4xbtQqK/qqKwkDoBFCfooRqqmRu9vY3xaJRwxSh673aYg==
+
+"@types/node@^4.0.30":
+  version "4.9.3"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-4.9.3.tgz#a24697a8157ab517996afe0c88fa716550ae419a"
+  integrity sha512-Q9eESThBvAbfEzznF1qTAKUoPbJEbK3lTSO0S3mICvmG/vUSZ+HnCtidpuB58Po7CJt5A2goKsDiYScN8d1V4A==
+
+"@types/opn@^3.0.28":
+  version "3.0.28"
+  resolved "https://registry.yarnpkg.com/@types/opn/-/opn-3.0.28.tgz#097d0d1c9b5749573a5d96df132387bb6d02118a"
+  integrity sha1-CX0NHJtXSVc6XZbfEyOHu20CEYo=
+  dependencies:
+    "@types/node" "*"
+
+"@types/parse5@^2.2.34":
+  version "2.2.34"
+  resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-2.2.34.tgz#e3870a10e82735a720f62d71dcd183ba78ef3a9d"
+  integrity sha1-44cKEOgnNacg9i1x3NGDunjvOp0=
+  dependencies:
+    "@types/node" "*"
+
+"@types/path-is-inside@^1.0.0":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@types/path-is-inside/-/path-is-inside-1.0.0.tgz#02d6ff38975d684bdec96204494baf9f29f0e17f"
+  integrity sha512-hfnXRGugz+McgX2jxyy5qz9sB21LRzlGn24zlwN2KEgoPtEvjzNRrLtUkOOebPDPZl3Rq7ywKxYvylVcEZDnEw==
+
+"@types/pem@^1.8.1":
+  version "1.9.5"
+  resolved "https://registry.yarnpkg.com/@types/pem/-/pem-1.9.5.tgz#cd5548b5e0acb4b41a9e21067e9fcd8c57089c99"
+  integrity sha512-C0txxEw8B7DCoD85Ko7SEvzUogNd5VDJ5/YBG8XUcacsOGqxr5Oo4g3OUAfdEDUbhXanwUoVh/ZkMFw77FGPQQ==
+  dependencies:
+    "@types/node" "*"
+
+"@types/range-parser@*":
+  version "1.2.3"
+  resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c"
+  integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==
+
+"@types/relateurl@*":
+  version "0.2.28"
+  resolved "https://registry.yarnpkg.com/@types/relateurl/-/relateurl-0.2.28.tgz#6bda7db8653fa62643f5ee69e9f69c11a392e3a6"
+  integrity sha1-a9p9uGU/piZD9e5p6facEaOS46Y=
+
+"@types/request@2.0.3":
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/@types/request/-/request-2.0.3.tgz#bdf0fba9488c822f77e97de3dd8fe357b2fb8c06"
+  integrity sha512-cIvnyFRARxwE4OHpCyYue7H+SxaKFPpeleRCHJicft8QhyTNbVYsMwjvEzEPqG06D2LGHZ+sN5lXc8+bTu6D8A==
+  dependencies:
+    "@types/form-data" "*"
+    "@types/node" "*"
+
+"@types/resolve@0.0.4":
+  version "0.0.4"
+  resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.4.tgz#9b586d65a947dea88c4bc24da0b905fe9520a0d5"
+  integrity sha1-m1htZalH3qiMS8JNoLkF/pUgoNU=
+  dependencies:
+    "@types/node" "*"
+
+"@types/resolve@0.0.6":
+  version "0.0.6"
+  resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.6.tgz#0bd2f236c2e1cebb98b79885df57edd71a8d770e"
+  integrity sha512-g+Rg8uMWY76oYTyaL+m7ZcblqF/oj7pE6uEUyACluJx4zcop1Lk14qQiocdEkEVMDFm6DmKpxJhsER+ZuTwG3g==
+  dependencies:
+    "@types/node" "*"
+
+"@types/resolve@0.0.7":
+  version "0.0.7"
+  resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.7.tgz#b299c13be8d712b1b502fb14a084252acef84f4d"
+  integrity sha512-GPewdjkb0Q76o459qgp6pBLzJj/bD3oveS2kfLhIkZ9U3t3AFKtl5DlFB6lGTw0iZmcmxoGC8lpLW3NNJKrN9A==
+  dependencies:
+    "@types/node" "*"
+
+"@types/rimraf@^0.0.28":
+  version "0.0.28"
+  resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-0.0.28.tgz#5562519bc7963caca8abf7f128cae3b594d41d06"
+  integrity sha1-VWJRm8eWPKyoq/fxKMrjtZTUHQY=
+
+"@types/rx-core-binding@*":
+  version "4.0.4"
+  resolved "https://registry.yarnpkg.com/@types/rx-core-binding/-/rx-core-binding-4.0.4.tgz#d969d32f15a62b89e2862c17b3ee78fe329818d3"
+  integrity sha512-5pkfxnC4w810LqBPUwP5bg7SFR/USwhMSaAeZQQbEHeBp57pjKXRlXmqpMrLJB4y1oglR/c2502853uN0I+DAQ==
+  dependencies:
+    "@types/rx-core" "*"
+
+"@types/rx-core@*":
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/@types/rx-core/-/rx-core-4.0.3.tgz#0b3354b1238cedbe2b74f6326f139dbc7a591d60"
+  integrity sha1-CzNUsSOM7b4rdPYybxOdvHpZHWA=
+
+"@types/rx-lite-aggregates@*":
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/@types/rx-lite-aggregates/-/rx-lite-aggregates-4.0.3.tgz#6efb2b7f3d5f07183a1cb2bd4b1371d7073384c2"
+  integrity sha512-MAGDAHy8cRatm94FDduhJF+iNS5//jrZ/PIfm+QYw9OCeDgbymFHChM8YVIvN2zArwsRftKgE33QfRWvQk4DPg==
+  dependencies:
+    "@types/rx-lite" "*"
+
+"@types/rx-lite-async@*":
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/@types/rx-lite-async/-/rx-lite-async-4.0.2.tgz#27fbf0caeff029f41e2d2aae638b05e91ceb600c"
+  integrity sha512-vTEv5o8l6702ZwfAM5aOeVDfUwBSDOs+ARoGmWAKQ6LOInQ8J4/zjM7ov12fuTpktUKdMQjkeCp07Vd73mPkxw==
+  dependencies:
+    "@types/rx-lite" "*"
+
+"@types/rx-lite-backpressure@*":
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/@types/rx-lite-backpressure/-/rx-lite-backpressure-4.0.3.tgz#05abb19bdf87cc740196c355e5d0b37bb50b5d56"
+  integrity sha512-Y6aIeQCtNban5XSAF4B8dffhIKu6aAy/TXFlScHzSxh6ivfQBQw6UjxyEJxIOt3IT49YkS+siuayM2H/Q0cmgA==
+  dependencies:
+    "@types/rx-lite" "*"
+
+"@types/rx-lite-coincidence@*":
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/@types/rx-lite-coincidence/-/rx-lite-coincidence-4.0.3.tgz#80bd69acc4054a15cdc1638e2dc8843498cd85c0"
+  integrity sha512-1VNJqzE9gALUyMGypDXZZXzR0Tt7LC9DdAZQ3Ou/Q0MubNU35agVUNXKGHKpNTba+fr8GdIdkC26bRDqtCQBeQ==
+  dependencies:
+    "@types/rx-lite" "*"
+
+"@types/rx-lite-experimental@*":
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/@types/rx-lite-experimental/-/rx-lite-experimental-4.0.1.tgz#c532f5cbdf3f2c15da16ded8930d1b2984023cbd"
+  integrity sha1-xTL1y98/LBXaFt7Ykw0bKYQCPL0=
+  dependencies:
+    "@types/rx-lite" "*"
+
+"@types/rx-lite-joinpatterns@*":
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/@types/rx-lite-joinpatterns/-/rx-lite-joinpatterns-4.0.1.tgz#f70fe370518a8432f29158cc92ffb56b4e4afc3e"
+  integrity sha1-9w/jcFGKhDLykVjMkv+1a05K/D4=
+  dependencies:
+    "@types/rx-lite" "*"
+
+"@types/rx-lite-testing@*":
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/@types/rx-lite-testing/-/rx-lite-testing-4.0.1.tgz#21b19d11f4dfd6ffef5a9d1648e9c8879bfe21e9"
+  integrity sha1-IbGdEfTf1v/vWp0WSOnIh5v+Iek=
+  dependencies:
+    "@types/rx-lite-virtualtime" "*"
+
+"@types/rx-lite-time@*":
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/@types/rx-lite-time/-/rx-lite-time-4.0.3.tgz#0eda65474570237598f3448b845d2696f2dbb1c4"
+  integrity sha512-ukO5sPKDRwCGWRZRqPlaAU0SKVxmWwSjiOrLhoQDoWxZWg6vyB9XLEZViKOzIO6LnTIQBlk4UylYV0rnhJLxQw==
+  dependencies:
+    "@types/rx-lite" "*"
+
+"@types/rx-lite-virtualtime@*":
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/@types/rx-lite-virtualtime/-/rx-lite-virtualtime-4.0.3.tgz#4b30cacd0fe2e53af29f04f7438584c7d3959537"
+  integrity sha512-3uC6sGmjpOKatZSVHI2xB1+dedgml669ZRvqxy+WqmGJDVusOdyxcKfyzjW0P3/GrCiN4nmRkLVMhPwHCc5QLg==
+  dependencies:
+    "@types/rx-lite" "*"
+
+"@types/rx-lite@*":
+  version "4.0.6"
+  resolved "https://registry.yarnpkg.com/@types/rx-lite/-/rx-lite-4.0.6.tgz#3c02921c4244074234f26b772241bcc20c18c253"
+  integrity sha512-oYiDrFIcor9zDm0VDUca1UbROiMYBxMLMaM6qzz4ADAfOmA9r1dYEcAFH+2fsPI5BCCjPvV9pWC3X3flbrvs7w==
+  dependencies:
+    "@types/rx-core" "*"
+    "@types/rx-core-binding" "*"
+
+"@types/rx@*":
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/@types/rx/-/rx-4.1.1.tgz#598fc94a56baed975f194574e0f572fd8e627a48"
+  integrity sha1-WY/JSla67ZdfGUV04PVy/Y5iekg=
+  dependencies:
+    "@types/rx-core" "*"
+    "@types/rx-core-binding" "*"
+    "@types/rx-lite" "*"
+    "@types/rx-lite-aggregates" "*"
+    "@types/rx-lite-async" "*"
+    "@types/rx-lite-backpressure" "*"
+    "@types/rx-lite-coincidence" "*"
+    "@types/rx-lite-experimental" "*"
+    "@types/rx-lite-joinpatterns" "*"
+    "@types/rx-lite-testing" "*"
+    "@types/rx-lite-time" "*"
+    "@types/rx-lite-virtualtime" "*"
+
+"@types/semver@^5.3.30":
+  version "5.5.0"
+  resolved "https://registry.yarnpkg.com/@types/semver/-/semver-5.5.0.tgz#146c2a29ee7d3bae4bf2fcb274636e264c813c45"
+  integrity sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ==
+
+"@types/serve-static@*", "@types/serve-static@^1.7.31":
+  version "1.13.3"
+  resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.3.tgz#eb7e1c41c4468272557e897e9171ded5e2ded9d1"
+  integrity sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g==
+  dependencies:
+    "@types/express-serve-static-core" "*"
+    "@types/mime" "*"
+
+"@types/spdy@^3.4.1":
+  version "3.4.4"
+  resolved "https://registry.yarnpkg.com/@types/spdy/-/spdy-3.4.4.tgz#3282fd4ad8c4603aa49f7017dd520a08a345b2bc"
+  integrity sha512-N9LBlbVRRYq6HgYpPkqQc3a9HJ/iEtVZToW6xlTtJiMhmRJ7jJdV7TaZQJw/Ve/1ePUsQiCTDc4JMuzzag94GA==
+  dependencies:
+    "@types/node" "*"
+
+"@types/temp@^0.8.28":
+  version "0.8.34"
+  resolved "https://registry.yarnpkg.com/@types/temp/-/temp-0.8.34.tgz#03e4b3cb67cbb48c425bbf54b12230fef85540ac"
+  integrity sha512-oLa9c5LHXgS6UimpEVp08De7QvZ+Dfu5bMQuWyMhf92Z26Q10ubEMOWy9OEfUdzW7Y/sDWVHmUaLFtmnX/2j0w==
+  dependencies:
+    "@types/node" "*"
+
+"@types/through@*":
+  version "0.0.29"
+  resolved "https://registry.yarnpkg.com/@types/through/-/through-0.0.29.tgz#72943aac922e179339c651fa34a4428a4d722f93"
+  integrity sha512-9a7C5VHh+1BKblaYiq+7Tfc+EOmjMdZaD1MYtkQjSoxgB69tBjW98ry6SKsi4zEIWztLOMRuL87A3bdT/Fc/4w==
+  dependencies:
+    "@types/node" "*"
+
+"@types/ua-parser-js@^0.7.31":
+  version "0.7.33"
+  resolved "https://registry.yarnpkg.com/@types/ua-parser-js/-/ua-parser-js-0.7.33.tgz#4a92089511574e12928a7cb6b99a01831acd1dd7"
+  integrity sha512-ngUKcHnytUodUCL7C6EZ+lVXUjTMQb+9p/e1JjV5tN9TVzS98lHozWEFRPY1QcCdwFeMsmVWfZ3DPPT/udCyIw==
+
+"@types/uglify-js@*":
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.0.4.tgz#96beae23df6f561862a830b4288a49e86baac082"
+  integrity sha512-SudIN9TRJ+v8g5pTG8RRCqfqTMNqgWCKKd3vtynhGzkIIjxaicNAMuY5TRadJ6tzDu3Dotf3ngaMILtmOdmWEQ==
+  dependencies:
+    source-map "^0.6.1"
+
+"@types/update-notifier@^1.0.0":
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/@types/update-notifier/-/update-notifier-1.0.3.tgz#3c7ee1921af6f16149cdcaef356baf57d7a0b806"
+  integrity sha512-BLStNhP2DFF7funARwTcoD6tetRte8NK3Sc59mn7GNALCN975jOlKX3dGvsFxXr/HwQMxxCuRn9IWB3WQ7odHQ==
+
+"@types/uuid@^3.4.3":
+  version "3.4.5"
+  resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-3.4.5.tgz#d4dc10785b497a1474eae0ba7f0cb09c0ddfd6eb"
+  integrity sha512-MNL15wC3EKyw1VLF+RoVO4hJJdk9t/Hlv3rt1OL65Qvuadm4BYo6g9ZJQqoq7X8NBFSsQXgAujWciovh2lpVjA==
+  dependencies:
+    "@types/node" "*"
+
+"@types/vinyl-fs@0.0.28":
+  version "0.0.28"
+  resolved "https://registry.yarnpkg.com/@types/vinyl-fs/-/vinyl-fs-0.0.28.tgz#4663017bc802c6570eae4f3409fd5cabf97cbfde"
+  integrity sha1-RmMBe8gCxlcOrk80Cf1cq/l8v94=
+  dependencies:
+    "@types/glob-stream" "*"
+    "@types/node" "*"
+    "@types/vinyl" "*"
+
+"@types/vinyl-fs@^2.4.8":
+  version "2.4.11"
+  resolved "https://registry.yarnpkg.com/@types/vinyl-fs/-/vinyl-fs-2.4.11.tgz#b98119b8bb2494141eaf649b09fbfeb311161206"
+  integrity sha512-2OzQSfIr9CqqWMGqmcERE6Hnd2KY3eBVtFaulVo3sJghplUcaeMdL9ZjEiljcQQeHjheWY9RlNmumjIAvsBNaA==
+  dependencies:
+    "@types/glob-stream" "*"
+    "@types/node" "*"
+    "@types/vinyl" "*"
+
+"@types/vinyl@*", "@types/vinyl@^2.0.0":
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/@types/vinyl/-/vinyl-2.0.3.tgz#80a6ce362ab5b32a0c98e860748a31bce9bff0de"
+  integrity sha512-hrT6xg16CWSmndZqOTJ6BGIn2abKyTw0B58bI+7ioUoj3Sma6u8ftZ1DTI2yCaJamOVGLOnQWiPH3a74+EaqTA==
+  dependencies:
+    "@types/node" "*"
+
+"@types/whatwg-url@^6.4.0":
+  version "6.4.0"
+  resolved "https://registry.yarnpkg.com/@types/whatwg-url/-/whatwg-url-6.4.0.tgz#1e59b8c64bc0dbdf66d037cf8449d1c3d5270237"
+  integrity sha512-tonhlcbQ2eho09am6RHnHOgvtDfDYINd5rgxD+2YSkKENooVCFsWizJz139MQW/PV8FfClyKrNe9ZbdHrSCxGg==
+  dependencies:
+    "@types/node" "*"
+
+"@types/which@^1.3.1":
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/@types/which/-/which-1.3.2.tgz#9c246fc0c93ded311c8512df2891fb41f6227fdf"
+  integrity sha512-8oDqyLC7eD4HM307boe2QWKyuzdzWBj56xI/imSl2cpL+U3tCMaTAkMJ4ee5JBZ/FsOJlvRGeIShiZDAl1qERA==
+
+"@types/yeoman-generator@^2.0.3":
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/@types/yeoman-generator/-/yeoman-generator-2.0.3.tgz#f4b161ee354078b526e0901a5a5f87d4f8e085f6"
+  integrity sha512-vch2UFd6k7DdfWEv/alRwZIRXQoxZNUDpfLOK24+005dzE1HVnwSWfETF3WxJnWlsOcH87wU4uzldAE/7F/6Lw==
+  dependencies:
+    "@types/events" "*"
+    "@types/inquirer" "*"
+
+"@webcomponents/webcomponentsjs@^1.0.7":
+  version "1.3.3"
+  resolved "https://registry.yarnpkg.com/@webcomponents/webcomponentsjs/-/webcomponentsjs-1.3.3.tgz#5bb82a0d3210c836bd4623e13a4a93145cb9dc27"
+  integrity sha512-eLH04VBMpuZGzBIhOnUjECcQPEPcmfhWEijW9u1B5I+2PPYdWf3vWUExdDxu4Y3GljRSTCOlWnGtS9tpzmXMyQ==
+
+abbrev@1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
+  integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
+
+accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7:
+  version "1.3.7"
+  resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
+  integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
+  dependencies:
+    mime-types "~2.1.24"
+    negotiator "0.6.2"
+
+accessibility-developer-tools@^2.12.0:
+  version "2.12.0"
+  resolved "https://registry.yarnpkg.com/accessibility-developer-tools/-/accessibility-developer-tools-2.12.0.tgz#3da0cce9d6ec6373964b84f35db7cfc3df7ab514"
+  integrity sha1-PaDM6dbsY3OWS4TzXbfPw996tRQ=
+
+acorn-jsx@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b"
+  integrity sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=
+  dependencies:
+    acorn "^3.0.4"
+
+acorn-jsx@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.1.0.tgz#294adb71b57398b0680015f0a38c563ee1db5384"
+  integrity sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==
+
+acorn@^3.0.4:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
+  integrity sha1-ReN/s56No/JbruP/U2niu18iAXo=
+
+acorn@^5.5.0:
+  version "5.7.3"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279"
+  integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==
+
+acorn@^6.1.1:
+  version "6.2.0"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.2.0.tgz#67f0da2fc339d6cfb5d6fb244fd449f33cd8bbe3"
+  integrity sha512-8oe72N3WPMjA+2zVG71Ia0nXZ8DpQH+QyyHO+p06jT8eg8FGG3FbcUIi8KziHlAfheJQZeoqbvq1mQSQHXKYLw==
+
+acorn@^7.1.0:
+  version "7.1.0"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.0.tgz#949d36f2c292535da602283586c2477c57eb2d6c"
+  integrity sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==
+
+adm-zip@~0.4.3:
+  version "0.4.13"
+  resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.13.tgz#597e2f8cc3672151e1307d3e95cddbc75672314a"
+  integrity sha512-fERNJX8sOXfel6qCBCMPvZLzENBEhZTzKqg6vrOW5pvoEaQuJhRU4ndTAh6lHOxn1I6jnz2NHra56ZODM751uw==
+
+after@0.8.2:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
+  integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=
+
+agent-base@^4.3.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee"
+  integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==
+  dependencies:
+    es6-promisify "^5.0.0"
+
+ajv@^6.10.0, ajv@^6.10.2:
+  version "6.10.2"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52"
+  integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==
+  dependencies:
+    fast-deep-equal "^2.0.1"
+    fast-json-stable-stringify "^2.0.0"
+    json-schema-traverse "^0.4.1"
+    uri-js "^4.2.2"
+
+ajv@^6.5.5:
+  version "6.10.1"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.1.tgz#ebf8d3af22552df9dd049bfbe50cc2390e823593"
+  integrity sha512-w1YQaVGNC6t2UCPjEawK/vo/dG8OOrVtUmhBT1uJJYxbl5kU2Tj3v6LGqBcsysN1yhuCStJCCA3GqdvKY8sqXQ==
+  dependencies:
+    fast-deep-equal "^2.0.1"
+    fast-json-stable-stringify "^2.0.0"
+    json-schema-traverse "^0.4.1"
+    uri-js "^4.2.2"
+
+amdefine@>=0.0.4:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
+  integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=
+
+ansi-align@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-1.1.0.tgz#2f0c1658829739add5ebb15e6b0c6e3423f016ba"
+  integrity sha1-LwwWWIKXOa3V67FeawxuNCPwFro=
+  dependencies:
+    string-width "^1.0.1"
+
+ansi-align@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f"
+  integrity sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=
+  dependencies:
+    string-width "^2.0.0"
+
+ansi-escapes@^1.1.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
+  integrity sha1-06ioOzGapneTZisT52HHkRQiMG4=
+
+ansi-escapes@^3.2.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b"
+  integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==
+
+ansi-escapes@^4.2.1:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.0.tgz#a4ce2b33d6b214b7950d8595c212f12ac9cc569d"
+  integrity sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==
+  dependencies:
+    type-fest "^0.8.1"
+
+ansi-regex@^2.0.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+  integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
+
+ansi-regex@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
+  integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
+
+ansi-regex@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
+  integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
+
+ansi-regex@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
+  integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==
+
+ansi-styles@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
+  integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=
+
+ansi-styles@^3.2.0, ansi-styles@^3.2.1:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+  integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
+  dependencies:
+    color-convert "^1.9.0"
+
+ansi-styles@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178"
+  integrity sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=
+
+any-promise@^1.0.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
+  integrity sha1-q8av7tzqUugJzcA3au0845Y10X8=
+
+anymatch@^1.3.0:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a"
+  integrity sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==
+  dependencies:
+    micromatch "^2.1.5"
+    normalize-path "^2.0.0"
+
+append-field@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56"
+  integrity sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=
+
+aproba@^1.0.3:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
+  integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
+
+archiver-utils@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2"
+  integrity sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==
+  dependencies:
+    glob "^7.1.4"
+    graceful-fs "^4.2.0"
+    lazystream "^1.0.0"
+    lodash.defaults "^4.2.0"
+    lodash.difference "^4.5.0"
+    lodash.flatten "^4.4.0"
+    lodash.isplainobject "^4.0.6"
+    lodash.union "^4.6.0"
+    normalize-path "^3.0.0"
+    readable-stream "^2.0.0"
+
+archiver@^3.0.0:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/archiver/-/archiver-3.1.1.tgz#9db7819d4daf60aec10fe86b16cb9258ced66ea0"
+  integrity sha512-5Hxxcig7gw5Jod/8Gq0OneVgLYET+oNHcxgWItq4TbhOzRLKNAFUb9edAftiMKXvXfCB0vbGrJdZDNq0dWMsxg==
+  dependencies:
+    archiver-utils "^2.1.0"
+    async "^2.6.3"
+    buffer-crc32 "^0.2.1"
+    glob "^7.1.4"
+    readable-stream "^3.4.0"
+    tar-stream "^2.1.0"
+    zip-stream "^2.1.2"
+
+are-we-there-yet@~1.1.2:
+  version "1.1.5"
+  resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21"
+  integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==
+  dependencies:
+    delegates "^1.0.0"
+    readable-stream "^2.0.6"
+
+argparse@^1.0.7:
+  version "1.0.10"
+  resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
+  integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
+  dependencies:
+    sprintf-js "~1.0.2"
+
+arr-diff@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
+  integrity sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=
+  dependencies:
+    arr-flatten "^1.0.1"
+
+arr-diff@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
+  integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=
+
+arr-flatten@^1.0.1, arr-flatten@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1"
+  integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==
+
+arr-union@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
+  integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=
+
+array-back@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/array-back/-/array-back-2.0.0.tgz#6877471d51ecc9c9bfa6136fb6c7d5fe69748022"
+  integrity sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==
+  dependencies:
+    typical "^2.6.1"
+
+array-back@^3.0.1:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0"
+  integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==
+
+array-differ@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031"
+  integrity sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=
+
+array-find-index@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
+  integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=
+
+array-flatten@1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
+  integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
+
+array-union@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
+  integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=
+  dependencies:
+    array-uniq "^1.0.1"
+
+array-uniq@^1.0.1:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
+  integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=
+
+array-unique@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
+  integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=
+
+array-unique@^0.3.2:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
+  integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=
+
+arraybuffer.slice@~0.0.7:
+  version "0.0.7"
+  resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675"
+  integrity sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==
+
+arrify@^1.0.0, arrify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
+  integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=
+
+asn1@~0.2.3:
+  version "0.2.4"
+  resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
+  integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
+  dependencies:
+    safer-buffer "~2.1.0"
+
+assert-plus@1.0.0, assert-plus@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
+  integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=
+
+assign-symbols@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
+  integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=
+
+astral-regex@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
+  integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==
+
+async-each@^1.0.0:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf"
+  integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==
+
+async-limiter@~1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
+  integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
+
+async@^2.0.0, async@^2.0.1, async@^2.1.2, async@^2.4.1, async@^2.6.2, async@^2.6.3:
+  version "2.6.3"
+  resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
+  integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==
+  dependencies:
+    lodash "^4.17.14"
+
+async@^2.6.0, async@^2.6.1:
+  version "2.6.2"
+  resolved "https://registry.yarnpkg.com/async/-/async-2.6.2.tgz#18330ea7e6e313887f5d2f2a904bac6fe4dd5381"
+  integrity sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==
+  dependencies:
+    lodash "^4.17.11"
+
+async@~0.2.9:
+  version "0.2.10"
+  resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1"
+  integrity sha1-trvgsGdLnXGXCMo43owjfLUmw9E=
+
+asynckit@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+  integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
+
+atob-lite@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/atob-lite/-/atob-lite-2.0.0.tgz#0fef5ad46f1bd7a8502c65727f0367d5ee43d696"
+  integrity sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY=
+
+atob@^2.1.2:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
+  integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
+
+aws-sign2@~0.7.0:
+  version "0.7.0"
+  resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
+  integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
+
+aws4@^1.8.0:
+  version "1.8.0"
+  resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
+  integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==
+
+babel-code-frame@^6.26.0:
+  version "6.26.0"
+  resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
+  integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=
+  dependencies:
+    chalk "^1.1.3"
+    esutils "^2.0.2"
+    js-tokens "^3.0.2"
+
+babel-generator@^6.26.1:
+  version "6.26.1"
+  resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90"
+  integrity sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==
+  dependencies:
+    babel-messages "^6.23.0"
+    babel-runtime "^6.26.0"
+    babel-types "^6.26.0"
+    detect-indent "^4.0.0"
+    jsesc "^1.3.0"
+    lodash "^4.17.4"
+    source-map "^0.5.7"
+    trim-right "^1.0.1"
+
+babel-helper-evaluate-path@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.5.0.tgz#a62fa9c4e64ff7ea5cea9353174ef023a900a67c"
+  integrity sha512-mUh0UhS607bGh5wUMAQfOpt2JX2ThXMtppHRdRU1kL7ZLRWIXxoV2UIV1r2cAeeNeU1M5SB5/RSUgUxrK8yOkA==
+
+babel-helper-flip-expressions@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.4.3.tgz#3696736a128ac18bc25254b5f40a22ceb3c1d3fd"
+  integrity sha1-NpZzahKKwYvCUlS19AoizrPB0/0=
+
+babel-helper-is-nodes-equiv@^0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz#34e9b300b1479ddd98ec77ea0bbe9342dfe39684"
+  integrity sha1-NOmzALFHnd2Y7HfqC76TQt/jloQ=
+
+babel-helper-is-void-0@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-helper-is-void-0/-/babel-helper-is-void-0-0.4.3.tgz#7d9c01b4561e7b95dbda0f6eee48f5b60e67313e"
+  integrity sha1-fZwBtFYee5Xb2g9u7kj1tg5nMT4=
+
+babel-helper-mark-eval-scopes@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.4.3.tgz#d244a3bef9844872603ffb46e22ce8acdf551562"
+  integrity sha1-0kSjvvmESHJgP/tG4izorN9VFWI=
+
+babel-helper-remove-or-void@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.4.3.tgz#a4f03b40077a0ffe88e45d07010dee241ff5ae60"
+  integrity sha1-pPA7QAd6D/6I5F0HAQ3uJB/1rmA=
+
+babel-helper-to-multiple-sequence-expressions@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.5.0.tgz#a3f924e3561882d42fcf48907aa98f7979a4588d"
+  integrity sha512-m2CvfDW4+1qfDdsrtf4dwOslQC3yhbgyBFptncp4wvtdrDHqueW7slsYv4gArie056phvQFhT2nRcGS4bnm6mA==
+
+babel-messages@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e"
+  integrity sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-dynamic-import-node@^2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f"
+  integrity sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==
+  dependencies:
+    object.assign "^4.1.0"
+
+babel-plugin-minify-builtins@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.5.0.tgz#31eb82ed1a0d0efdc31312f93b6e4741ce82c36b"
+  integrity sha512-wpqbN7Ov5hsNwGdzuzvFcjgRlzbIeVv1gMIlICbPj0xkexnfoIDe7q+AZHMkQmAE/F9R5jkrB6TLfTegImlXag==
+
+babel-plugin-minify-constant-folding@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.5.0.tgz#f84bc8dbf6a561e5e350ff95ae216b0ad5515b6e"
+  integrity sha512-Vj97CTn/lE9hR1D+jKUeHfNy+m1baNiJ1wJvoGyOBUx7F7kJqDZxr9nCHjO/Ad+irbR3HzR6jABpSSA29QsrXQ==
+  dependencies:
+    babel-helper-evaluate-path "^0.5.0"
+
+babel-plugin-minify-dead-code-elimination@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.5.0.tgz#d23ef5445238ad06e8addf5c1cf6aec835bcda87"
+  integrity sha512-XQteBGXlgEoAKc/BhO6oafUdT4LBa7ARi55mxoyhLHNuA+RlzRmeMAfc31pb/UqU01wBzRc36YqHQzopnkd/6Q==
+  dependencies:
+    babel-helper-evaluate-path "^0.5.0"
+    babel-helper-mark-eval-scopes "^0.4.3"
+    babel-helper-remove-or-void "^0.4.3"
+    lodash.some "^4.6.0"
+
+babel-plugin-minify-flip-comparisons@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.4.3.tgz#00ca870cb8f13b45c038b3c1ebc0f227293c965a"
+  integrity sha1-AMqHDLjxO0XAOLPB68DyJyk8llo=
+  dependencies:
+    babel-helper-is-void-0 "^0.4.3"
+
+babel-plugin-minify-guarded-expressions@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.4.3.tgz#cc709b4453fd21b1f302877444c89f88427ce397"
+  integrity sha1-zHCbRFP9IbHzAod0RMifiEJ845c=
+  dependencies:
+    babel-helper-flip-expressions "^0.4.3"
+
+babel-plugin-minify-infinity@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.4.3.tgz#dfb876a1b08a06576384ef3f92e653ba607b39ca"
+  integrity sha1-37h2obCKBldjhO8/kuZTumB7Oco=
+
+babel-plugin-minify-mangle-names@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.5.0.tgz#bcddb507c91d2c99e138bd6b17a19c3c271e3fd3"
+  integrity sha512-3jdNv6hCAw6fsX1p2wBGPfWuK69sfOjfd3zjUXkbq8McbohWy23tpXfy5RnToYWggvqzuMOwlId1PhyHOfgnGw==
+  dependencies:
+    babel-helper-mark-eval-scopes "^0.4.3"
+
+babel-plugin-minify-numeric-literals@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.4.3.tgz#8e4fd561c79f7801286ff60e8c5fd9deee93c0bc"
+  integrity sha1-jk/VYcefeAEob/YOjF/Z3u6TwLw=
+
+babel-plugin-minify-replace@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.5.0.tgz#d3e2c9946c9096c070efc96761ce288ec5c3f71c"
+  integrity sha512-aXZiaqWDNUbyNNNpWs/8NyST+oU7QTpK7J9zFEFSA0eOmtUNMU3fczlTTTlnCxHmq/jYNFEmkkSG3DDBtW3Y4Q==
+
+babel-plugin-minify-simplify@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.5.0.tgz#1f090018afb90d8b54d3d027fd8a4927f243da6f"
+  integrity sha512-TM01J/YcKZ8XIQd1Z3nF2AdWHoDsarjtZ5fWPDksYZNsoOjQ2UO2EWm824Ym6sp127m44gPlLFiO5KFxU8pA5Q==
+  dependencies:
+    babel-helper-flip-expressions "^0.4.3"
+    babel-helper-is-nodes-equiv "^0.0.1"
+    babel-helper-to-multiple-sequence-expressions "^0.5.0"
+
+babel-plugin-minify-type-constructors@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.4.3.tgz#1bc6f15b87f7ab1085d42b330b717657a2156500"
+  integrity sha1-G8bxW4f3qxCF1CszC3F2V6IVZQA=
+  dependencies:
+    babel-helper-is-void-0 "^0.4.3"
+
+babel-plugin-transform-inline-consecutive-adds@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.4.3.tgz#323d47a3ea63a83a7ac3c811ae8e6941faf2b0d1"
+  integrity sha1-Mj1Ho+pjqDp6w8gRro5pQfrysNE=
+
+babel-plugin-transform-member-expression-literals@^6.9.4:
+  version "6.9.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.9.4.tgz#37039c9a0c3313a39495faac2ff3a6b5b9d038bf"
+  integrity sha1-NwOcmgwzE6OUlfqsL/OmtbnQOL8=
+
+babel-plugin-transform-merge-sibling-variables@^6.9.4:
+  version "6.9.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.9.4.tgz#85b422fc3377b449c9d1cde44087203532401dae"
+  integrity sha1-hbQi/DN3tEnJ0c3kQIcgNTJAHa4=
+
+babel-plugin-transform-minify-booleans@^6.9.4:
+  version "6.9.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.4.tgz#acbb3e56a3555dd23928e4b582d285162dd2b198"
+  integrity sha1-rLs+VqNVXdI5KOS1gtKFFi3SsZg=
+
+babel-plugin-transform-property-literals@^6.9.4:
+  version "6.9.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.9.4.tgz#98c1d21e255736573f93ece54459f6ce24985d39"
+  integrity sha1-mMHSHiVXNlc/k+zlRFn2ziSYXTk=
+  dependencies:
+    esutils "^2.0.2"
+
+babel-plugin-transform-regexp-constructors@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.4.3.tgz#58b7775b63afcf33328fae9a5f88fbd4fb0b4965"
+  integrity sha1-WLd3W2OvzzMyj66aX4j71PsLSWU=
+
+babel-plugin-transform-remove-console@^6.9.4:
+  version "6.9.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.4.tgz#b980360c067384e24b357a588d807d3c83527780"
+  integrity sha1-uYA2DAZzhOJLNXpYjYB9PINSd4A=
+
+babel-plugin-transform-remove-debugger@^6.9.4:
+  version "6.9.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.9.4.tgz#42b727631c97978e1eb2d199a7aec84a18339ef2"
+  integrity sha1-QrcnYxyXl44estGZp67IShgznvI=
+
+babel-plugin-transform-remove-undefined@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.5.0.tgz#80208b31225766c630c97fa2d288952056ea22dd"
+  integrity sha512-+M7fJYFaEE/M9CXa0/IRkDbiV3wRELzA1kKQFCJ4ifhrzLKn/9VCCgj9OFmYWwBd8IB48YdgPkHYtbYq+4vtHQ==
+  dependencies:
+    babel-helper-evaluate-path "^0.5.0"
+
+babel-plugin-transform-simplify-comparison-operators@^6.9.4:
+  version "6.9.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.9.4.tgz#f62afe096cab0e1f68a2d753fdf283888471ceb9"
+  integrity sha1-9ir+CWyrDh9ootdT/fKDiIRxzrk=
+
+babel-plugin-transform-undefined-to-void@^6.9.4:
+  version "6.9.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.4.tgz#be241ca81404030678b748717322b89d0c8fe280"
+  integrity sha1-viQcqBQEAwZ4t0hxcyK4nQyP4oA=
+
+babel-preset-minify@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/babel-preset-minify/-/babel-preset-minify-0.5.0.tgz#e25bb8d3590087af02b650967159a77c19bfb96b"
+  integrity sha512-xj1s9Mon+RFubH569vrGCayA9Fm2GMsCgDRm1Jb8SgctOB7KFcrVc2o8K3YHUyMz+SWP8aea75BoS8YfsXXuiA==
+  dependencies:
+    babel-plugin-minify-builtins "^0.5.0"
+    babel-plugin-minify-constant-folding "^0.5.0"
+    babel-plugin-minify-dead-code-elimination "^0.5.0"
+    babel-plugin-minify-flip-comparisons "^0.4.3"
+    babel-plugin-minify-guarded-expressions "^0.4.3"
+    babel-plugin-minify-infinity "^0.4.3"
+    babel-plugin-minify-mangle-names "^0.5.0"
+    babel-plugin-minify-numeric-literals "^0.4.3"
+    babel-plugin-minify-replace "^0.5.0"
+    babel-plugin-minify-simplify "^0.5.0"
+    babel-plugin-minify-type-constructors "^0.4.3"
+    babel-plugin-transform-inline-consecutive-adds "^0.4.3"
+    babel-plugin-transform-member-expression-literals "^6.9.4"
+    babel-plugin-transform-merge-sibling-variables "^6.9.4"
+    babel-plugin-transform-minify-booleans "^6.9.4"
+    babel-plugin-transform-property-literals "^6.9.4"
+    babel-plugin-transform-regexp-constructors "^0.4.3"
+    babel-plugin-transform-remove-console "^6.9.4"
+    babel-plugin-transform-remove-debugger "^6.9.4"
+    babel-plugin-transform-remove-undefined "^0.5.0"
+    babel-plugin-transform-simplify-comparison-operators "^6.9.4"
+    babel-plugin-transform-undefined-to-void "^6.9.4"
+    lodash.isplainobject "^4.0.6"
+
+babel-runtime@^6.22.0, babel-runtime@^6.26.0:
+  version "6.26.0"
+  resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
+  integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4=
+  dependencies:
+    core-js "^2.4.0"
+    regenerator-runtime "^0.11.0"
+
+babel-traverse@^6.26.0:
+  version "6.26.0"
+  resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee"
+  integrity sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=
+  dependencies:
+    babel-code-frame "^6.26.0"
+    babel-messages "^6.23.0"
+    babel-runtime "^6.26.0"
+    babel-types "^6.26.0"
+    babylon "^6.18.0"
+    debug "^2.6.8"
+    globals "^9.18.0"
+    invariant "^2.2.2"
+    lodash "^4.17.4"
+
+babel-types@^6.26.0:
+  version "6.26.0"
+  resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497"
+  integrity sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=
+  dependencies:
+    babel-runtime "^6.26.0"
+    esutils "^2.0.2"
+    lodash "^4.17.4"
+    to-fast-properties "^1.0.3"
+
+babylon@^6.18.0:
+  version "6.18.0"
+  resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3"
+  integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==
+
+babylon@^7.0.0-beta.42:
+  version "7.0.0-beta.47"
+  resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.47.tgz#6d1fa44f0abec41ab7c780481e62fd9aafbdea80"
+  integrity sha512-+rq2cr4GDhtToEzKFD6KZZMDBXhjFAr9JjPw9pAppZACeEWqNM294j+NdBzkSHYXwzzBmVjZ3nEVJlOhbR2gOQ==
+
+backo2@1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
+  integrity sha1-MasayLEpNjRj41s+u2n038+6eUc=
+
+balanced-match@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
+  integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
+
+base64-arraybuffer@0.1.5:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8"
+  integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg=
+
+base64-js@1.2.0, base64-js@^1.0.2:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
+  integrity sha1-o5mS1yNYSBGYK+XikLtqU9hnAPE=
+
+base64id@2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6"
+  integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==
+
+base@^0.11.1:
+  version "0.11.2"
+  resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
+  integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==
+  dependencies:
+    cache-base "^1.0.1"
+    class-utils "^0.3.5"
+    component-emitter "^1.2.1"
+    define-property "^1.0.0"
+    isobject "^3.0.1"
+    mixin-deep "^1.2.0"
+    pascalcase "^0.1.1"
+
+bcrypt-pbkdf@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
+  integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=
+  dependencies:
+    tweetnacl "^0.14.3"
+
+before-after-hook@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-1.4.0.tgz#2b6bf23dca4f32e628fd2747c10a37c74a4b484d"
+  integrity sha512-l5r9ir56nda3qu14nAXIlyq1MmUSs0meCIaFAh8HwkFwP1F8eToOuS3ah2VAHHcY04jaYD7FpJC5JTXHYRbkzg==
+
+better-assert@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522"
+  integrity sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=
+  dependencies:
+    callsite "1.0.0"
+
+binary-extensions@^1.0.0:
+  version "1.13.1"
+  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65"
+  integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==
+
+binaryextensions@^2.1.2:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.1.2.tgz#c83c3d74233ba7674e4f313cb2a2b70f54e94b7c"
+  integrity sha512-xVNN69YGDghOqCCtA6FI7avYrr02mTJjOgB0/f1VPD3pJC8QEvjTKWc4epDx8AqxxA75NI0QpVM2gPJXUbE4Tg==
+
+bl@^1.0.0:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c"
+  integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==
+  dependencies:
+    readable-stream "^2.3.5"
+    safe-buffer "^5.1.1"
+
+bl@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/bl/-/bl-2.2.0.tgz#e1a574cdf528e4053019bb800b041c0ac88da493"
+  integrity sha512-wbgvOpqopSr7uq6fJrLH8EsvYMJf9gzfo2jCsL2eTy75qXPukA4pCgHamOQkZtY5vmfVtjB+P3LNlMHW5CEZXA==
+  dependencies:
+    readable-stream "^2.3.5"
+    safe-buffer "^5.1.1"
+
+bl@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/bl/-/bl-3.0.0.tgz#3611ec00579fd18561754360b21e9f784500ff88"
+  integrity sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A==
+  dependencies:
+    readable-stream "^3.0.1"
+
+blob@0.0.5:
+  version "0.0.5"
+  resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683"
+  integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==
+
+body-parser@1.19.0, body-parser@^1.17.2:
+  version "1.19.0"
+  resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
+  integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==
+  dependencies:
+    bytes "3.1.0"
+    content-type "~1.0.4"
+    debug "2.6.9"
+    depd "~1.1.2"
+    http-errors "1.7.2"
+    iconv-lite "0.4.24"
+    on-finished "~2.3.0"
+    qs "6.7.0"
+    raw-body "2.4.0"
+    type-is "~1.6.17"
+
+boolbase@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
+  integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
+
+bower-config@^1.4.0, bower-config@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/bower-config/-/bower-config-1.4.1.tgz#85fd9df367c2b8dbbd0caa4c5f2bad40cd84c2cc"
+  integrity sha1-hf2d82fCuNu9DKpMXyutQM2Ewsw=
+  dependencies:
+    graceful-fs "^4.1.3"
+    mout "^1.0.0"
+    optimist "^0.6.1"
+    osenv "^0.1.3"
+    untildify "^2.1.0"
+
+bower-json@^0.8.1:
+  version "0.8.1"
+  resolved "https://registry.yarnpkg.com/bower-json/-/bower-json-0.8.1.tgz#96c14723241ae6466a9c52e16caa32623a883843"
+  integrity sha1-lsFHIyQa5kZqnFLhbKoyYjqIOEM=
+  dependencies:
+    deep-extend "^0.4.0"
+    ext-name "^3.0.0"
+    graceful-fs "^4.1.3"
+    intersect "^1.0.1"
+
+bower-logger@^0.2.2:
+  version "0.2.2"
+  resolved "https://registry.yarnpkg.com/bower-logger/-/bower-logger-0.2.2.tgz#39be07e979b2fc8e03a94634205ed9422373d381"
+  integrity sha1-Ob4H6Xmy/I4DqUY0IF7ZQiNz04E=
+
+bower@^1.8.8:
+  version "1.8.8"
+  resolved "https://registry.yarnpkg.com/bower/-/bower-1.8.8.tgz#82544be34a33aeae7efb8bdf9905247b2cffa985"
+  integrity sha512-1SrJnXnkP9soITHptSO+ahx3QKp3cVzn8poI6ujqc5SeOkg5iqM1pK9H+DSc2OQ8SnO0jC/NG4Ur/UIwy7574A==
+
+boxen@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/boxen/-/boxen-0.6.0.tgz#8364d4248ac34ff0ef1b2f2bf49a6c60ce0d81b6"
+  integrity sha1-g2TUJIrDT/DvGy8r9JpsYM4NgbY=
+  dependencies:
+    ansi-align "^1.1.0"
+    camelcase "^2.1.0"
+    chalk "^1.1.1"
+    cli-boxes "^1.0.0"
+    filled-array "^1.0.0"
+    object-assign "^4.0.1"
+    repeating "^2.0.0"
+    string-width "^1.0.1"
+    widest-line "^1.0.0"
+
+boxen@^1.2.1:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b"
+  integrity sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==
+  dependencies:
+    ansi-align "^2.0.0"
+    camelcase "^4.0.0"
+    chalk "^2.0.1"
+    cli-boxes "^1.0.0"
+    string-width "^2.0.0"
+    term-size "^1.2.0"
+    widest-line "^2.0.0"
+
+brace-expansion@^1.1.7:
+  version "1.1.11"
+  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+  integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+  dependencies:
+    balanced-match "^1.0.0"
+    concat-map "0.0.1"
+
+braces@^1.8.2:
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
+  integrity sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=
+  dependencies:
+    expand-range "^1.8.1"
+    preserve "^0.2.0"
+    repeat-element "^1.1.2"
+
+braces@^2.3.1:
+  version "2.3.2"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
+  integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==
+  dependencies:
+    arr-flatten "^1.1.0"
+    array-unique "^0.3.2"
+    extend-shallow "^2.0.1"
+    fill-range "^4.0.0"
+    isobject "^3.0.1"
+    repeat-element "^1.1.2"
+    snapdragon "^0.8.1"
+    snapdragon-node "^2.0.1"
+    split-string "^3.0.2"
+    to-regex "^3.0.1"
+
+browser-capabilities@^1.0.0:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/browser-capabilities/-/browser-capabilities-1.1.4.tgz#a6bd657a07a134532ad66c722b8949904478b973"
+  integrity sha512-BezMQhbQklxjRQpZZQ8tnbzEo6AldUwMh8/PeWt5/CTBSwByQRXZEAK2fbnEahQ4poeeaI0suAYRq25A1YGOmw==
+  dependencies:
+    "@types/ua-parser-js" "^0.7.31"
+    ua-parser-js "^0.7.15"
+
+browserify-zlib@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d"
+  integrity sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=
+  dependencies:
+    pako "~0.2.0"
+
+browserstack@^1.2.0:
+  version "1.5.3"
+  resolved "https://registry.yarnpkg.com/browserstack/-/browserstack-1.5.3.tgz#93ab48799a12ef99dbd074dd595410ddb196a7ac"
+  integrity sha512-AO+mECXsW4QcqC9bxwM29O7qWa7bJT94uBFzeb5brylIQwawuEziwq20dPYbins95GlWzOawgyDNdjYAo32EKg==
+  dependencies:
+    https-proxy-agent "^2.2.1"
+
+btoa-lite@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337"
+  integrity sha1-M3dm2hWAEhD92VbCLpxokaudAzc=
+
+buffer-alloc-unsafe@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
+  integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==
+
+buffer-alloc@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec"
+  integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==
+  dependencies:
+    buffer-alloc-unsafe "^1.1.0"
+    buffer-fill "^1.0.0"
+
+buffer-crc32@^0.2.1, buffer-crc32@^0.2.13, buffer-crc32@~0.2.3:
+  version "0.2.13"
+  resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
+  integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=
+
+buffer-fill@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c"
+  integrity sha1-+PeLdniYiO858gXNY39o5wISKyw=
+
+buffer-from@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
+  integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
+
+buffer@^5.1.0:
+  version "5.4.3"
+  resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.4.3.tgz#3fbc9c69eb713d323e3fc1a895eee0710c072115"
+  integrity sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==
+  dependencies:
+    base64-js "^1.0.2"
+    ieee754 "^1.1.4"
+
+busboy@^0.2.11:
+  version "0.2.14"
+  resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453"
+  integrity sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=
+  dependencies:
+    dicer "0.2.5"
+    readable-stream "1.1.x"
+
+bytes@3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
+  integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=
+
+bytes@3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
+  integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
+
+cache-base@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
+  integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==
+  dependencies:
+    collection-visit "^1.0.0"
+    component-emitter "^1.2.1"
+    get-value "^2.0.6"
+    has-value "^1.0.0"
+    isobject "^3.0.1"
+    set-value "^2.0.0"
+    to-object-path "^0.3.0"
+    union-value "^1.0.0"
+    unset-value "^1.0.0"
+
+call-me-maybe@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b"
+  integrity sha1-JtII6onje1y95gJQoV8DHBak1ms=
+
+callsite@1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20"
+  integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA=
+
+callsites@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
+  integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
+
+camel-case@3.0.x:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73"
+  integrity sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=
+  dependencies:
+    no-case "^2.2.0"
+    upper-case "^1.1.1"
+
+camelcase-keys@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7"
+  integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc=
+  dependencies:
+    camelcase "^2.0.0"
+    map-obj "^1.0.0"
+
+camelcase@^2.0.0, camelcase@^2.1.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
+  integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=
+
+camelcase@^4.0.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
+  integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=
+
+cancel-token@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/cancel-token/-/cancel-token-0.1.1.tgz#c18197674bb1c84c1d6933ebf15d8d5a5ce79b4f"
+  integrity sha1-wYGXZ0uxyEwdaTPr8V2NWlznm08=
+  dependencies:
+    "@types/node" "^4.0.30"
+
+capture-stack-trace@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz#a6c0bbe1f38f3aa0b92238ecb6ff42c344d4135d"
+  integrity sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==
+
+caseless@~0.12.0:
+  version "0.12.0"
+  resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
+  integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
+
+chalk@*, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4.2:
+  version "2.4.2"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
+  integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
+  dependencies:
+    ansi-styles "^3.2.1"
+    escape-string-regexp "^1.0.5"
+    supports-color "^5.3.0"
+
+chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
+  integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=
+  dependencies:
+    ansi-styles "^2.2.1"
+    escape-string-regexp "^1.0.2"
+    has-ansi "^2.0.0"
+    strip-ansi "^3.0.0"
+    supports-color "^2.0.0"
+
+chalk@~0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f"
+  integrity sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=
+  dependencies:
+    ansi-styles "~1.0.0"
+    has-color "~0.1.0"
+    strip-ansi "~0.1.0"
+
+chardet@^0.7.0:
+  version "0.7.0"
+  resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
+  integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
+
+charenc@~0.0.1:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
+  integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=
+
+cheerio@^1.0.0-rc.2:
+  version "1.0.0-rc.3"
+  resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.3.tgz#094636d425b2e9c0f4eb91a46c05630c9a1a8bf6"
+  integrity sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA==
+  dependencies:
+    css-select "~1.2.0"
+    dom-serializer "~0.1.1"
+    entities "~1.1.1"
+    htmlparser2 "^3.9.1"
+    lodash "^4.15.0"
+    parse5 "^3.0.1"
+
+chokidar@^1.7.0:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
+  integrity sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=
+  dependencies:
+    anymatch "^1.3.0"
+    async-each "^1.0.0"
+    glob-parent "^2.0.0"
+    inherits "^2.0.1"
+    is-binary-path "^1.0.0"
+    is-glob "^2.0.0"
+    path-is-absolute "^1.0.0"
+    readdirp "^2.0.0"
+  optionalDependencies:
+    fsevents "^1.0.0"
+
+chownr@^1.0.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.2.tgz#a18f1e0b269c8a6a5d3c86eb298beb14c3dd7bf6"
+  integrity sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A==
+
+chownr@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494"
+  integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==
+
+ci-info@^1.5.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497"
+  integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==
+
+class-utils@^0.3.5:
+  version "0.3.6"
+  resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
+  integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==
+  dependencies:
+    arr-union "^3.1.0"
+    define-property "^0.2.5"
+    isobject "^3.0.0"
+    static-extend "^0.1.1"
+
+clean-css@4.2.x:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.1.tgz#2d411ef76b8569b6d0c84068dabe85b0aa5e5c17"
+  integrity sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==
+  dependencies:
+    source-map "~0.6.0"
+
+cleankill@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/cleankill/-/cleankill-2.0.0.tgz#59830dfc8b411d53dc72ad09d45a78ea33161a91"
+  integrity sha1-WYMN/ItBHVPccq0J1Fp46jMWGpE=
+
+cli-boxes@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143"
+  integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM=
+
+cli-cursor@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987"
+  integrity sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=
+  dependencies:
+    restore-cursor "^1.0.1"
+
+cli-cursor@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5"
+  integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=
+  dependencies:
+    restore-cursor "^2.0.0"
+
+cli-cursor@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307"
+  integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==
+  dependencies:
+    restore-cursor "^3.1.0"
+
+cli-table@^0.3.1:
+  version "0.3.1"
+  resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23"
+  integrity sha1-9TsFJmqLGguTSz0IIebi3FkUriM=
+  dependencies:
+    colors "1.0.3"
+
+cli-width@^2.0.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639"
+  integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=
+
+clone-buffer@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58"
+  integrity sha1-4+JbIHrE5wGvch4staFnksrD3Fg=
+
+clone-stats@^0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1"
+  integrity sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=
+
+clone-stats@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680"
+  integrity sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=
+
+clone@^1.0.0:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
+  integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
+
+clone@^2.0.0, clone@^2.1.0, clone@^2.1.1:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
+  integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=
+
+cloneable-readable@^1.0.0:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.1.3.tgz#120a00cb053bfb63a222e709f9683ea2e11d8cec"
+  integrity sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==
+  dependencies:
+    inherits "^2.0.1"
+    process-nextick-args "^2.0.0"
+    readable-stream "^2.3.5"
+
+code-point-at@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
+  integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
+
+collection-visit@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
+  integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=
+  dependencies:
+    map-visit "^1.0.0"
+    object-visit "^1.0.0"
+
+color-convert@^1.9.0, color-convert@^1.9.1:
+  version "1.9.3"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
+  integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
+  dependencies:
+    color-name "1.1.3"
+
+color-name@1.1.3, color-name@^1.0.0:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+  integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
+
+color-string@^1.5.2:
+  version "1.5.3"
+  resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.3.tgz#c9bbc5f01b58b5492f3d6857459cb6590ce204cc"
+  integrity sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==
+  dependencies:
+    color-name "^1.0.0"
+    simple-swizzle "^0.2.2"
+
+color@3.0.x:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/color/-/color-3.0.0.tgz#d920b4328d534a3ac8295d68f7bd4ba6c427be9a"
+  integrity sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==
+  dependencies:
+    color-convert "^1.9.1"
+    color-string "^1.5.2"
+
+colornames@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/colornames/-/colornames-1.1.1.tgz#f8889030685c7c4ff9e2a559f5077eb76a816f96"
+  integrity sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=
+
+colors@1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b"
+  integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=
+
+colors@^1.2.1:
+  version "1.3.3"
+  resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.3.tgz#39e005d546afe01e01f9c4ca8fa50f686a01205d"
+  integrity sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==
+
+colorspace@1.1.x:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.2.tgz#e0128950d082b86a2168580796a0aa5d6c68d8c5"
+  integrity sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==
+  dependencies:
+    color "3.0.x"
+    text-hex "1.0.x"
+
+combined-stream@^1.0.6, combined-stream@~1.0.6:
+  version "1.0.8"
+  resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
+  integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
+  dependencies:
+    delayed-stream "~1.0.0"
+
+command-line-args@^5.0.2:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.1.1.tgz#88e793e5bb3ceb30754a86863f0401ac92fd369a"
+  integrity sha512-hL/eG8lrll1Qy1ezvkant+trihbGnaKaeEjj6Scyr3DN+RC7iQ5Rz84IeLERfAWDGo0HBSNAakczwgCilDXnWg==
+  dependencies:
+    array-back "^3.0.1"
+    find-replace "^3.0.0"
+    lodash.camelcase "^4.3.0"
+    typical "^4.0.0"
+
+command-line-commands@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/command-line-commands/-/command-line-commands-2.0.1.tgz#c58aa13dc78c06038ed67077e57ad09a6f858f46"
+  integrity sha512-m8c2p1DrNd2ruIAggxd/y6DgygQayf6r8RHwchhXryaLF8I6koYjoYroVP+emeROE9DXN5b9sP1Gh+WtvTTdtQ==
+  dependencies:
+    array-back "^2.0.0"
+
+command-line-usage@^5.0.5:
+  version "5.0.5"
+  resolved "https://registry.yarnpkg.com/command-line-usage/-/command-line-usage-5.0.5.tgz#5f25933ffe6dedd983c635d38a21d7e623fda357"
+  integrity sha512-d8NrGylA5oCXSbGoKz05FkehDAzSmIm4K03S5VDh4d5lZAtTWfc3D1RuETtuQCn8129nYfJfDdF7P/lwcz1BlA==
+  dependencies:
+    array-back "^2.0.0"
+    chalk "^2.4.1"
+    table-layout "^0.4.3"
+    typical "^2.6.1"
+
+commander@2.17.x:
+  version "2.17.1"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
+  integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==
+
+commander@^2.19.0:
+  version "2.20.3"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
+  integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
+
+commander@~2.19.0:
+  version "2.19.0"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
+  integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==
+
+comment-parser@^0.7.2:
+  version "0.7.2"
+  resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-0.7.2.tgz#baf6d99b42038678b81096f15b630d18142f4b8a"
+  integrity sha512-4Rjb1FnxtOcv9qsfuaNuVsmmVn4ooVoBHzYfyKteiXwIU84PClyGA5jASoFMwPV93+FPh9spwueXauxFJZkGAg==
+
+commondir@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
+  integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=
+
+component-bind@1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1"
+  integrity sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=
+
+component-emitter@1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
+  integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=
+
+component-emitter@^1.2.1:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
+  integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
+
+component-inherit@0.0.3:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143"
+  integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=
+
+compress-commons@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-2.1.1.tgz#9410d9a534cf8435e3fbbb7c6ce48de2dc2f0610"
+  integrity sha512-eVw6n7CnEMFzc3duyFVrQEuY1BlHR3rYsSztyG32ibGMW722i3C6IizEGMFmfMU+A+fALvBIwxN3czffTcdA+Q==
+  dependencies:
+    buffer-crc32 "^0.2.13"
+    crc32-stream "^3.0.1"
+    normalize-path "^3.0.0"
+    readable-stream "^2.3.6"
+
+compressible@~2.0.16:
+  version "2.0.18"
+  resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba"
+  integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==
+  dependencies:
+    mime-db ">= 1.43.0 < 2"
+
+compression@^1.6.2:
+  version "1.7.4"
+  resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f"
+  integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==
+  dependencies:
+    accepts "~1.3.5"
+    bytes "3.0.0"
+    compressible "~2.0.16"
+    debug "2.6.9"
+    on-headers "~1.0.2"
+    safe-buffer "5.1.2"
+    vary "~1.1.2"
+
+concat-map@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+  integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
+
+concat-stream@^1.4.7, concat-stream@^1.5.2:
+  version "1.6.2"
+  resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
+  integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
+  dependencies:
+    buffer-from "^1.0.0"
+    inherits "^2.0.3"
+    readable-stream "^2.2.2"
+    typedarray "^0.0.6"
+
+configstore@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/configstore/-/configstore-2.1.0.tgz#737a3a7036e9886102aa6099e47bb33ab1aba1a1"
+  integrity sha1-c3o6cDbpiGECqmCZ5HuzOrGroaE=
+  dependencies:
+    dot-prop "^3.0.0"
+    graceful-fs "^4.1.2"
+    mkdirp "^0.5.0"
+    object-assign "^4.0.1"
+    os-tmpdir "^1.0.0"
+    osenv "^0.1.0"
+    uuid "^2.0.1"
+    write-file-atomic "^1.1.2"
+    xdg-basedir "^2.0.0"
+
+configstore@^3.0.0:
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.2.tgz#c6f25defaeef26df12dd33414b001fe81a543f8f"
+  integrity sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==
+  dependencies:
+    dot-prop "^4.1.0"
+    graceful-fs "^4.1.2"
+    make-dir "^1.0.0"
+    unique-string "^1.0.0"
+    write-file-atomic "^2.0.0"
+    xdg-basedir "^3.0.0"
+
+console-control-strings@^1.0.0, console-control-strings@~1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
+  integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
+
+content-disposition@0.5.3:
+  version "0.5.3"
+  resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
+  integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==
+  dependencies:
+    safe-buffer "5.1.2"
+
+content-type@^1.0.2, content-type@~1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
+  integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
+
+convert-source-map@^1.1.0, convert-source-map@^1.1.1:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20"
+  integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==
+  dependencies:
+    safe-buffer "~5.1.1"
+
+cookie-signature@1.0.6:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
+  integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
+
+cookie@0.3.1:
+  version "0.3.1"
+  resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
+  integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=
+
+cookie@0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
+  integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
+
+copy-descriptor@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
+  integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
+
+core-js@^2.4.0:
+  version "2.6.9"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2"
+  integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==
+
+core-util-is@1.0.2, core-util-is@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
+  integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
+
+cors@^2.8.4:
+  version "2.8.5"
+  resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
+  integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
+  dependencies:
+    object-assign "^4"
+    vary "^1"
+
+crc32-stream@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-3.0.1.tgz#cae6eeed003b0e44d739d279de5ae63b171b4e85"
+  integrity sha512-mctvpXlbzsvK+6z8kJwSJ5crm7yBwrQMTybJzMw1O4lLGJqjlDCXY2Zw7KheiA6XBEcBmfLx1D88mjRGVJtY9w==
+  dependencies:
+    crc "^3.4.4"
+    readable-stream "^3.4.0"
+
+crc@^3.4.4:
+  version "3.8.0"
+  resolved "https://registry.yarnpkg.com/crc/-/crc-3.8.0.tgz#ad60269c2c856f8c299e2c4cc0de4556914056c6"
+  integrity sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==
+  dependencies:
+    buffer "^5.1.0"
+
+create-error-class@^3.0.0, create-error-class@^3.0.1:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6"
+  integrity sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=
+  dependencies:
+    capture-stack-trace "^1.0.0"
+
+cross-spawn@^5.0.1:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
+  integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=
+  dependencies:
+    lru-cache "^4.0.1"
+    shebang-command "^1.2.0"
+    which "^1.2.9"
+
+cross-spawn@^6.0.0, cross-spawn@^6.0.5:
+  version "6.0.5"
+  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
+  integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
+  dependencies:
+    nice-try "^1.0.4"
+    path-key "^2.0.1"
+    semver "^5.5.0"
+    shebang-command "^1.2.0"
+    which "^1.2.9"
+
+crypt@~0.0.1:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
+  integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=
+
+crypto-random-string@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
+  integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=
+
+css-select@~1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858"
+  integrity sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=
+  dependencies:
+    boolbase "~1.0.0"
+    css-what "2.1"
+    domutils "1.5.1"
+    nth-check "~1.0.1"
+
+css-slam@^2.1.2:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/css-slam/-/css-slam-2.1.2.tgz#3d35b1922cb3e0002a45c89ab189492508c493e5"
+  integrity sha512-cObrY+mhFEmepWpua6EpMrgRNTQ0eeym+kvR0lukI6hDEzK7F8himEDS4cJ9+fPHCoArTzVrrR0d+oAUbTR1NA==
+  dependencies:
+    command-line-args "^5.0.2"
+    command-line-usage "^5.0.5"
+    dom5 "^3.0.0"
+    parse5 "^4.0.0"
+    shady-css-parser "^0.1.0"
+
+css-what@2.1, css-what@^2.1.0:
+  version "2.1.3"
+  resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2"
+  integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==
+
+cssbeautify@^0.3.1:
+  version "0.3.1"
+  resolved "https://registry.yarnpkg.com/cssbeautify/-/cssbeautify-0.3.1.tgz#12dd1f734035c2e6faca67dcbdcef74e42811397"
+  integrity sha1-Et0fc0A1wub6ymfcvc73TkKBE5c=
+
+currently-unhandled@^0.4.1:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
+  integrity sha1-mI3zP+qxke95mmE2nddsF635V+o=
+  dependencies:
+    array-find-index "^1.0.1"
+
+dargs@^6.0.0:
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/dargs/-/dargs-6.1.0.tgz#1f3b9b56393ecf8caa7cbfd6c31496ffcfb9b272"
+  integrity sha512-5dVBvpBLBnPwSsYXqfybFyehMmC/EenKEcf23AhCTgTf48JFBbmJKqoZBsERDnjL0FyiVTYWdFsRfTLHxLyKdQ==
+
+dashdash@^1.12.0:
+  version "1.14.1"
+  resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
+  integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=
+  dependencies:
+    assert-plus "^1.0.0"
+
+dateformat@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
+  integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==
+
+debug@2.6.9, debug@^2.0.0, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8:
+  version "2.6.9"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
+  integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
+  dependencies:
+    ms "2.0.0"
+
+debug@^3.0.0, debug@^3.1.0:
+  version "3.2.6"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
+  integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
+  dependencies:
+    ms "^2.1.1"
+
+debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@~4.1.0:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
+  integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
+  dependencies:
+    ms "^2.1.1"
+
+debug@~3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
+  integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
+  dependencies:
+    ms "2.0.0"
+
+decamelize@^1.1.2:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+  integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
+
+decode-uri-component@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
+  integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
+
+decompress-response@^3.2.0:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3"
+  integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=
+  dependencies:
+    mimic-response "^1.0.0"
+
+deep-extend@^0.4.0:
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f"
+  integrity sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=
+
+deep-extend@^0.6.0, deep-extend@~0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
+  integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
+
+deep-is@~0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
+  integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
+
+deepmerge@4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.0.0.tgz#3e3110ca29205f120d7cb064960a39c3d2087c09"
+  integrity sha512-YZ1rOP5+kHor4hMAH+HRQnBQHg+wvS1un1hAOuIcxcBy0hzcUf6Jg2a1w65kpoOUnurOfZbERwjI1TfZxNjcww==
+
+define-properties@^1.1.2:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
+  integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
+  dependencies:
+    object-keys "^1.0.12"
+
+define-property@^0.2.5:
+  version "0.2.5"
+  resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116"
+  integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=
+  dependencies:
+    is-descriptor "^0.1.0"
+
+define-property@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6"
+  integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY=
+  dependencies:
+    is-descriptor "^1.0.0"
+
+define-property@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d"
+  integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==
+  dependencies:
+    is-descriptor "^1.0.2"
+    isobject "^3.0.1"
+
+del@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/del/-/del-3.0.0.tgz#53ecf699ffcbcb39637691ab13baf160819766e5"
+  integrity sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=
+  dependencies:
+    globby "^6.1.0"
+    is-path-cwd "^1.0.0"
+    is-path-in-cwd "^1.0.0"
+    p-map "^1.1.1"
+    pify "^3.0.0"
+    rimraf "^2.2.8"
+
+delayed-stream@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+  integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
+
+delegates@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
+  integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
+
+depd@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
+  integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
+
+deprecation@^2.0.0:
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919"
+  integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==
+
+destroy@~1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
+  integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
+
+detect-conflict@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/detect-conflict/-/detect-conflict-1.0.1.tgz#088657a66a961c05019db7c4230883b1c6b4176e"
+  integrity sha1-CIZXpmqWHAUBnbfEIwiDsca0F24=
+
+detect-file@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63"
+  integrity sha1-STXe39lIhkjgBrASlWbpOGcR6mM=
+  dependencies:
+    fs-exists-sync "^0.1.0"
+
+detect-file@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7"
+  integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=
+
+detect-indent@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208"
+  integrity sha1-920GQ1LN9Docts5hnE7jqUdd4gg=
+  dependencies:
+    repeating "^2.0.0"
+
+detect-libc@^1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
+  integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
+
+detect-node@^2.0.3:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
+  integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==
+
+diagnostics@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/diagnostics/-/diagnostics-1.1.1.tgz#cab6ac33df70c9d9a727490ae43ac995a769b22a"
+  integrity sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==
+  dependencies:
+    colorspace "1.1.x"
+    enabled "1.0.x"
+    kuler "1.0.x"
+
+dicer@0.2.5:
+  version "0.2.5"
+  resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.2.5.tgz#5996c086bb33218c812c090bddc09cd12facb70f"
+  integrity sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=
+  dependencies:
+    readable-stream "1.1.x"
+    streamsearch "0.1.2"
+
+diff@^2.1.2:
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/diff/-/diff-2.2.3.tgz#60eafd0d28ee906e4e8ff0a52c1229521033bf99"
+  integrity sha1-YOr9DSjukG5Oj/ClLBIpUhAzv5k=
+
+diff@^3.1.0, diff@^3.5.0:
+  version "3.5.0"
+  resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
+  integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
+
+dir-glob@2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.0.0.tgz#0b205d2b6aef98238ca286598a8204d29d0a0034"
+  integrity sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==
+  dependencies:
+    arrify "^1.0.1"
+    path-type "^3.0.0"
+
+doctrine@^2.0.2:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
+  integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==
+  dependencies:
+    esutils "^2.0.2"
+
+doctrine@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
+  integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
+  dependencies:
+    esutils "^2.0.2"
+
+dom-serializer@0:
+  version "0.2.2"
+  resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51"
+  integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==
+  dependencies:
+    domelementtype "^2.0.1"
+    entities "^2.0.0"
+
+dom-serializer@~0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0"
+  integrity sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==
+  dependencies:
+    domelementtype "^1.3.0"
+    entities "^1.1.1"
+
+dom-urls@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/dom-urls/-/dom-urls-1.1.0.tgz#001ddf81628cd1e706125c7176f53ccec55d918e"
+  integrity sha1-AB3fgWKM0ecGElxxdvU8zsVdkY4=
+  dependencies:
+    urijs "^1.16.1"
+
+dom5@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/dom5/-/dom5-3.0.1.tgz#cdfc7331f376e284bf379e6ea054afc136702944"
+  integrity sha512-JPFiouQIr16VQ4dX6i0+Hpbg3H2bMKPmZ+WZgBOSSvOPx9QHwwY8sPzeM2baUtViESYto6wC2nuZOMC/6gulcA==
+  dependencies:
+    "@types/parse5" "^2.2.34"
+    clone "^2.1.0"
+    parse5 "^4.0.0"
+
+domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f"
+  integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==
+
+domelementtype@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.0.1.tgz#1f8bdfe91f5a78063274e803b4bdcedf6e94f94d"
+  integrity sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==
+
+domhandler@^2.3.0:
+  version "2.4.2"
+  resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803"
+  integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==
+  dependencies:
+    domelementtype "1"
+
+domutils@1.5.1:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf"
+  integrity sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=
+  dependencies:
+    dom-serializer "0"
+    domelementtype "1"
+
+domutils@^1.5.1:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a"
+  integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==
+  dependencies:
+    dom-serializer "0"
+    domelementtype "1"
+
+dot-prop@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177"
+  integrity sha1-G3CK8JSknJoOfbyteQq6U52sEXc=
+  dependencies:
+    is-obj "^1.0.0"
+
+dot-prop@^4.1.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57"
+  integrity sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==
+  dependencies:
+    is-obj "^1.0.0"
+
+duplexer2@^0.1.2, duplexer2@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1"
+  integrity sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=
+  dependencies:
+    readable-stream "^2.0.2"
+
+duplexer3@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
+  integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=
+
+duplexify@^3.2.0, duplexify@^3.5.0, duplexify@^3.6.0:
+  version "3.7.1"
+  resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309"
+  integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==
+  dependencies:
+    end-of-stream "^1.0.0"
+    inherits "^2.0.1"
+    readable-stream "^2.0.0"
+    stream-shift "^1.0.0"
+
+ecc-jsbn@~0.1.1:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
+  integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=
+  dependencies:
+    jsbn "~0.1.0"
+    safer-buffer "^2.1.0"
+
+editions@^2.1.2, editions@^2.1.3:
+  version "2.1.3"
+  resolved "https://registry.yarnpkg.com/editions/-/editions-2.1.3.tgz#727ccf3ec2c7b12dcc652c71000f16c4824d6f7d"
+  integrity sha512-xDZyVm0A4nLgMNWVVLJvcwMjI80ShiH/27RyLiCnW1L273TcJIA25C4pwJ33AWV01OX6UriP35Xu+lH4S7HWQw==
+  dependencies:
+    errlop "^1.1.1"
+    semver "^5.6.0"
+
+ee-first@1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
+  integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
+
+ejs@^2.5.9:
+  version "2.6.2"
+  resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.6.2.tgz#3a32c63d1cd16d11266cd4703b14fec4e74ab4f6"
+  integrity sha512-PcW2a0tyTuPHz3tWyYqtK6r1fZ3gp+3Sop8Ph+ZYN81Ob5rwmbHEzaqs10N3BEsaGTkh/ooniXK+WwszGlc2+Q==
+
+emitter-component@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/emitter-component/-/emitter-component-1.1.1.tgz#065e2dbed6959bf470679edabeaf7981d1003ab6"
+  integrity sha1-Bl4tvtaVm/RwZ57avq95gdEAOrY=
+
+emoji-regex@^7.0.1:
+  version "7.0.3"
+  resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
+  integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
+
+emoji-regex@^8.0.0:
+  version "8.0.0"
+  resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
+  integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
+
+enabled@1.0.x:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/enabled/-/enabled-1.0.2.tgz#965f6513d2c2d1c5f4652b64a2e3396467fc2f93"
+  integrity sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=
+  dependencies:
+    env-variable "0.0.x"
+
+encodeurl@~1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
+  integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
+
+end-of-stream@^1.0.0, end-of-stream@^1.1.0:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
+  integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==
+  dependencies:
+    once "^1.4.0"
+
+end-of-stream@^1.4.1:
+  version "1.4.4"
+  resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
+  integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
+  dependencies:
+    once "^1.4.0"
+
+ends-with@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/ends-with/-/ends-with-0.2.0.tgz#2f9da98d57a50cfda4571ce4339000500f4e6b8a"
+  integrity sha1-L52pjVelDP2kVxzkM5AAUA9Oa4o=
+
+engine.io-client@~3.4.0:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.4.0.tgz#82a642b42862a9b3f7a188f41776b2deab643700"
+  integrity sha512-a4J5QO2k99CM2a0b12IznnyQndoEvtA4UAldhGzKqnHf42I3Qs2W5SPnDvatZRcMaNZs4IevVicBPayxYt6FwA==
+  dependencies:
+    component-emitter "1.2.1"
+    component-inherit "0.0.3"
+    debug "~4.1.0"
+    engine.io-parser "~2.2.0"
+    has-cors "1.1.0"
+    indexof "0.0.1"
+    parseqs "0.0.5"
+    parseuri "0.0.5"
+    ws "~6.1.0"
+    xmlhttprequest-ssl "~1.5.4"
+    yeast "0.1.2"
+
+engine.io-parser@~2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.2.0.tgz#312c4894f57d52a02b420868da7b5c1c84af80ed"
+  integrity sha512-6I3qD9iUxotsC5HEMuuGsKA0cXerGz+4uGcXQEkfBidgKf0amsjrrtwcbwK/nzpZBxclXlV7gGl9dgWvu4LF6w==
+  dependencies:
+    after "0.8.2"
+    arraybuffer.slice "~0.0.7"
+    base64-arraybuffer "0.1.5"
+    blob "0.0.5"
+    has-binary2 "~1.0.2"
+
+engine.io@~3.4.0:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.4.0.tgz#3a962cc4535928c252759a00f98519cb46c53ff3"
+  integrity sha512-XCyYVWzcHnK5cMz7G4VTu2W7zJS7SM1QkcelghyIk/FmobWBtXE7fwhBusEKvCSqc3bMh8fNFMlUkCKTFRxH2w==
+  dependencies:
+    accepts "~1.3.4"
+    base64id "2.0.0"
+    cookie "0.3.1"
+    debug "~4.1.0"
+    engine.io-parser "~2.2.0"
+    ws "^7.1.2"
+
+entities@^1.1.1, entities@~1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
+  integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==
+
+entities@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4"
+  integrity sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==
+
+env-variable@0.0.x:
+  version "0.0.5"
+  resolved "https://registry.yarnpkg.com/env-variable/-/env-variable-0.0.5.tgz#913dd830bef11e96a039c038d4130604eba37f88"
+  integrity sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==
+
+errlop@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/errlop/-/errlop-1.1.1.tgz#d9ae4c76c3e64956c5d79e6e035d6343bfd62250"
+  integrity sha512-WX7QjiPHhsny7/PQvrhS5VMizXXKoKCS3udaBp8gjlARdbn+XmK300eKBAAN0hGyRaTCtRpOaxK+xFVPUJ3zkw==
+  dependencies:
+    editions "^2.1.2"
+
+error-ex@^1.2.0, error-ex@^1.3.1:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
+  integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
+  dependencies:
+    is-arrayish "^0.2.1"
+
+error@^7.0.2:
+  version "7.0.2"
+  resolved "https://registry.yarnpkg.com/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02"
+  integrity sha1-pfdf/02ZJhJt2sDqXcOOaJFTywI=
+  dependencies:
+    string-template "~0.2.1"
+    xtend "~4.0.0"
+
+es6-promise@^4.0.3, es6-promise@^4.0.5:
+  version "4.2.8"
+  resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
+  integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==
+
+es6-promisify@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
+  integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=
+  dependencies:
+    es6-promise "^4.0.3"
+
+es6-promisify@^6.0.0:
+  version "6.0.2"
+  resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-6.0.2.tgz#525c23725b8510f5f1f2feb5a1fbad93a93e29b4"
+  integrity sha512-eO6vFm0JvqGzjWIQA6QVKjxpmELfhWbDUWHm1rPfIbn55mhKPiAa5xpLmQWJrNa629ZIeQ8ZvMAi13kvrjK6Mg==
+
+escape-html@^1.0.3, escape-html@~1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
+  integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
+
+escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.4, escape-string-regexp@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+  integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
+
+eslint-config-google@^0.13.0:
+  version "0.13.0"
+  resolved "https://registry.yarnpkg.com/eslint-config-google/-/eslint-config-google-0.13.0.tgz#e277d16d2cb25c1ffd3fd13fb0035ad7421382fe"
+  integrity sha512-ELgMdOIpn0CFdsQS+FuxO+Ttu4p+aLaXHv9wA9yVnzqlUGV7oN/eRRnJekk7TCur6Cu2FXX0fqfIXRBaM14lpQ==
+
+eslint-plugin-html@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-html/-/eslint-plugin-html-6.0.0.tgz#28e5c3e71e6f612e07e73d7c215e469766628c13"
+  integrity sha512-PQcGippOHS+HTbQCStmH5MY1BF2MaU8qW/+Mvo/8xTa/ioeMXdSP+IiaBw2+nh0KEMfYQKuTz1Zo+vHynjwhbg==
+  dependencies:
+    htmlparser2 "^3.10.1"
+
+eslint-plugin-jsdoc@^18.4.3:
+  version "18.11.0"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-18.11.0.tgz#724e6aa35f01c7f80629b2e313b007422cc159af"
+  integrity sha512-24J2+eK2ZHZ1KvpKcoOEir2k4xJKfPzZ1JC9PToi8y8Tn59T8TVVSNRTTRzsDdiaQeIbehApB3KxqIfJG8o7hg==
+  dependencies:
+    comment-parser "^0.7.2"
+    debug "^4.1.1"
+    jsdoctypeparser "^6.1.0"
+    lodash "^4.17.15"
+    object.entries-ponyfill "^1.0.1"
+    regextras "^0.7.0"
+    semver "^6.3.0"
+    spdx-expression-parse "^3.0.0"
+
+eslint-scope@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9"
+  integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==
+  dependencies:
+    esrecurse "^4.1.0"
+    estraverse "^4.1.1"
+
+eslint-utils@^1.4.3:
+  version "1.4.3"
+  resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f"
+  integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==
+  dependencies:
+    eslint-visitor-keys "^1.1.0"
+
+eslint-visitor-keys@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2"
+  integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==
+
+eslint@^6.6.0:
+  version "6.8.0"
+  resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb"
+  integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==
+  dependencies:
+    "@babel/code-frame" "^7.0.0"
+    ajv "^6.10.0"
+    chalk "^2.1.0"
+    cross-spawn "^6.0.5"
+    debug "^4.0.1"
+    doctrine "^3.0.0"
+    eslint-scope "^5.0.0"
+    eslint-utils "^1.4.3"
+    eslint-visitor-keys "^1.1.0"
+    espree "^6.1.2"
+    esquery "^1.0.1"
+    esutils "^2.0.2"
+    file-entry-cache "^5.0.1"
+    functional-red-black-tree "^1.0.1"
+    glob-parent "^5.0.0"
+    globals "^12.1.0"
+    ignore "^4.0.6"
+    import-fresh "^3.0.0"
+    imurmurhash "^0.1.4"
+    inquirer "^7.0.0"
+    is-glob "^4.0.0"
+    js-yaml "^3.13.1"
+    json-stable-stringify-without-jsonify "^1.0.1"
+    levn "^0.3.0"
+    lodash "^4.17.14"
+    minimatch "^3.0.4"
+    mkdirp "^0.5.1"
+    natural-compare "^1.4.0"
+    optionator "^0.8.3"
+    progress "^2.0.0"
+    regexpp "^2.0.1"
+    semver "^6.1.2"
+    strip-ansi "^5.2.0"
+    strip-json-comments "^3.0.1"
+    table "^5.2.3"
+    text-table "^0.2.0"
+    v8-compile-cache "^2.0.3"
+
+espree@^3.5.2:
+  version "3.5.4"
+  resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7"
+  integrity sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==
+  dependencies:
+    acorn "^5.5.0"
+    acorn-jsx "^3.0.0"
+
+espree@^6.1.2:
+  version "6.1.2"
+  resolved "https://registry.yarnpkg.com/espree/-/espree-6.1.2.tgz#6c272650932b4f91c3714e5e7b5f5e2ecf47262d"
+  integrity sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==
+  dependencies:
+    acorn "^7.1.0"
+    acorn-jsx "^5.1.0"
+    eslint-visitor-keys "^1.1.0"
+
+esprima@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
+  integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
+
+esquery@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708"
+  integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==
+  dependencies:
+    estraverse "^4.0.0"
+
+esrecurse@^4.1.0:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf"
+  integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==
+  dependencies:
+    estraverse "^4.1.0"
+
+estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
+  integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
+
+esutils@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
+  integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=
+
+etag@~1.8.1:
+  version "1.8.1"
+  resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
+  integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
+
+eventemitter3@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb"
+  integrity sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==
+
+execa@^0.7.0:
+  version "0.7.0"
+  resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
+  integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=
+  dependencies:
+    cross-spawn "^5.0.1"
+    get-stream "^3.0.0"
+    is-stream "^1.1.0"
+    npm-run-path "^2.0.0"
+    p-finally "^1.0.0"
+    signal-exit "^3.0.0"
+    strip-eof "^1.0.0"
+
+execa@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8"
+  integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==
+  dependencies:
+    cross-spawn "^6.0.0"
+    get-stream "^4.0.0"
+    is-stream "^1.1.0"
+    npm-run-path "^2.0.0"
+    p-finally "^1.0.0"
+    signal-exit "^3.0.0"
+    strip-eof "^1.0.0"
+
+exit-hook@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8"
+  integrity sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=
+
+expand-brackets@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
+  integrity sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=
+  dependencies:
+    is-posix-bracket "^0.1.0"
+
+expand-brackets@^2.1.4:
+  version "2.1.4"
+  resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622"
+  integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI=
+  dependencies:
+    debug "^2.3.3"
+    define-property "^0.2.5"
+    extend-shallow "^2.0.1"
+    posix-character-classes "^0.1.0"
+    regex-not "^1.0.0"
+    snapdragon "^0.8.1"
+    to-regex "^3.0.1"
+
+expand-range@^1.8.1:
+  version "1.8.2"
+  resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337"
+  integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=
+  dependencies:
+    fill-range "^2.1.0"
+
+expand-tilde@^1.2.2:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449"
+  integrity sha1-C4HrqJflo9MdHD0QL48BRB5VlEk=
+  dependencies:
+    os-homedir "^1.0.1"
+
+expand-tilde@^2.0.0, expand-tilde@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502"
+  integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=
+  dependencies:
+    homedir-polyfill "^1.0.1"
+
+express@^4.15.3, express@^4.8.5:
+  version "4.17.1"
+  resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
+  integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==
+  dependencies:
+    accepts "~1.3.7"
+    array-flatten "1.1.1"
+    body-parser "1.19.0"
+    content-disposition "0.5.3"
+    content-type "~1.0.4"
+    cookie "0.4.0"
+    cookie-signature "1.0.6"
+    debug "2.6.9"
+    depd "~1.1.2"
+    encodeurl "~1.0.2"
+    escape-html "~1.0.3"
+    etag "~1.8.1"
+    finalhandler "~1.1.2"
+    fresh "0.5.2"
+    merge-descriptors "1.0.1"
+    methods "~1.1.2"
+    on-finished "~2.3.0"
+    parseurl "~1.3.3"
+    path-to-regexp "0.1.7"
+    proxy-addr "~2.0.5"
+    qs "6.7.0"
+    range-parser "~1.2.1"
+    safe-buffer "5.1.2"
+    send "0.17.1"
+    serve-static "1.14.1"
+    setprototypeof "1.1.1"
+    statuses "~1.5.0"
+    type-is "~1.6.18"
+    utils-merge "1.0.1"
+    vary "~1.1.2"
+
+ext-list@^2.0.0:
+  version "2.2.2"
+  resolved "https://registry.yarnpkg.com/ext-list/-/ext-list-2.2.2.tgz#0b98e64ed82f5acf0f2931babf69212ef52ddd37"
+  integrity sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==
+  dependencies:
+    mime-db "^1.28.0"
+
+ext-name@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/ext-name/-/ext-name-3.0.0.tgz#07e4418737cb1f513c32c6ea48d8b8c8e0471abb"
+  integrity sha1-B+RBhzfLH1E8MsbqSNi4yOBHGrs=
+  dependencies:
+    ends-with "^0.2.0"
+    ext-list "^2.0.0"
+    meow "^3.1.0"
+    sort-keys-length "^1.0.0"
+
+extend-shallow@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
+  integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=
+  dependencies:
+    is-extendable "^0.1.0"
+
+extend-shallow@^3.0.0, extend-shallow@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8"
+  integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=
+  dependencies:
+    assign-symbols "^1.0.0"
+    is-extendable "^1.0.1"
+
+extend@^3.0.0, extend@~3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
+  integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
+
+external-editor@^1.1.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b"
+  integrity sha1-Etew24UPf/fnCBuvQAVwAGDEYAs=
+  dependencies:
+    extend "^3.0.0"
+    spawn-sync "^1.0.15"
+    tmp "^0.0.29"
+
+external-editor@^3.0.3:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
+  integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==
+  dependencies:
+    chardet "^0.7.0"
+    iconv-lite "^0.4.24"
+    tmp "^0.0.33"
+
+extglob@^0.3.1:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
+  integrity sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=
+  dependencies:
+    is-extglob "^1.0.0"
+
+extglob@^2.0.4:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543"
+  integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==
+  dependencies:
+    array-unique "^0.3.2"
+    define-property "^1.0.0"
+    expand-brackets "^2.1.4"
+    extend-shallow "^2.0.1"
+    fragment-cache "^0.2.1"
+    regex-not "^1.0.0"
+    snapdragon "^0.8.1"
+    to-regex "^3.0.1"
+
+extsprintf@1.3.0, extsprintf@^1.2.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
+  integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=
+
+fast-deep-equal@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
+  integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
+
+fast-glob@^2.0.2:
+  version "2.2.7"
+  resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d"
+  integrity sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==
+  dependencies:
+    "@mrmlnc/readdir-enhanced" "^2.2.1"
+    "@nodelib/fs.stat" "^1.1.2"
+    glob-parent "^3.1.0"
+    is-glob "^4.0.0"
+    merge2 "^1.2.3"
+    micromatch "^3.1.10"
+
+fast-json-stable-stringify@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
+  integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I=
+
+fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6:
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+  integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
+
+fast-safe-stringify@^2.0.4:
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz#04b26106cc56681f51a044cfc0d76cf0008ac2c2"
+  integrity sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg==
+
+fd-slicer@~1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e"
+  integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=
+  dependencies:
+    pend "~1.2.0"
+
+fecha@^2.3.3:
+  version "2.3.3"
+  resolved "https://registry.yarnpkg.com/fecha/-/fecha-2.3.3.tgz#948e74157df1a32fd1b12c3a3c3cdcb6ec9d96cd"
+  integrity sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==
+
+figures@^1.3.5:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e"
+  integrity sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=
+  dependencies:
+    escape-string-regexp "^1.0.5"
+    object-assign "^4.1.0"
+
+figures@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962"
+  integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=
+  dependencies:
+    escape-string-regexp "^1.0.5"
+
+figures@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/figures/-/figures-3.1.0.tgz#4b198dd07d8d71530642864af2d45dd9e459c4ec"
+  integrity sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg==
+  dependencies:
+    escape-string-regexp "^1.0.5"
+
+file-entry-cache@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c"
+  integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==
+  dependencies:
+    flat-cache "^2.0.1"
+
+filename-regex@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
+  integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=
+
+fill-range@^2.1.0:
+  version "2.2.4"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565"
+  integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==
+  dependencies:
+    is-number "^2.1.0"
+    isobject "^2.0.0"
+    randomatic "^3.0.0"
+    repeat-element "^1.1.2"
+    repeat-string "^1.5.2"
+
+fill-range@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"
+  integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=
+  dependencies:
+    extend-shallow "^2.0.1"
+    is-number "^3.0.0"
+    repeat-string "^1.6.1"
+    to-regex-range "^2.1.0"
+
+filled-array@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/filled-array/-/filled-array-1.1.0.tgz#c3c4f6c663b923459a9aa29912d2d031f1507f84"
+  integrity sha1-w8T2xmO5I0WamqKZEtLQMfFQf4Q=
+
+finalhandler@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
+  integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
+  dependencies:
+    debug "2.6.9"
+    encodeurl "~1.0.2"
+    escape-html "~1.0.3"
+    on-finished "~2.3.0"
+    parseurl "~1.3.3"
+    statuses "~1.5.0"
+    unpipe "~1.0.0"
+
+find-port@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/find-port/-/find-port-1.0.1.tgz#db084a6cbf99564d99869ae79fbdecf66e8a185c"
+  integrity sha1-2whKbL+ZVk2Zhprnn73s9m6KGFw=
+  dependencies:
+    async "~0.2.9"
+
+find-replace@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-3.0.0.tgz#3e7e23d3b05167a76f770c9fbd5258b0def68c38"
+  integrity sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==
+  dependencies:
+    array-back "^3.0.1"
+
+find-up@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
+  integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=
+  dependencies:
+    path-exists "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+find-up@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
+  integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==
+  dependencies:
+    locate-path "^3.0.0"
+
+findup-sync@^0.4.2:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12"
+  integrity sha1-QAQ5Kee8YK3wt/SCfExudaDeyhI=
+  dependencies:
+    detect-file "^0.1.0"
+    is-glob "^2.0.1"
+    micromatch "^2.3.7"
+    resolve-dir "^0.1.0"
+
+findup-sync@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc"
+  integrity sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=
+  dependencies:
+    detect-file "^1.0.0"
+    is-glob "^3.1.0"
+    micromatch "^3.0.4"
+    resolve-dir "^1.0.1"
+
+first-chunk-stream@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz#59bfb50cd905f60d7c394cd3d9acaab4e6ad934e"
+  integrity sha1-Wb+1DNkF9g18OUzT2ayqtOatk04=
+
+first-chunk-stream@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz#1bdecdb8e083c0664b91945581577a43a9f31d70"
+  integrity sha1-G97NuOCDwGZLkZRVgVd6Q6nzHXA=
+  dependencies:
+    readable-stream "^2.0.2"
+
+flat-cache@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0"
+  integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==
+  dependencies:
+    flatted "^2.0.0"
+    rimraf "2.6.3"
+    write "1.0.3"
+
+flatted@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08"
+  integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==
+
+follow-redirects@^1.0.0:
+  version "1.9.0"
+  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.9.0.tgz#8d5bcdc65b7108fe1508649c79c12d732dcedb4f"
+  integrity sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A==
+  dependencies:
+    debug "^3.0.0"
+
+for-in@^1.0.1, for-in@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
+  integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=
+
+for-own@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce"
+  integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=
+  dependencies:
+    for-in "^1.0.1"
+
+forever-agent@~0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
+  integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
+
+fork-stream@^0.0.4:
+  version "0.0.4"
+  resolved "https://registry.yarnpkg.com/fork-stream/-/fork-stream-0.0.4.tgz#db849fce77f6708a5f8f386ae533a0907b54ae70"
+  integrity sha1-24Sfznf2cIpfjzhq5TOgkHtUrnA=
+
+form-data@~2.3.2:
+  version "2.3.3"
+  resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
+  integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==
+  dependencies:
+    asynckit "^0.4.0"
+    combined-stream "^1.0.6"
+    mime-types "^2.1.12"
+
+formatio@1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/formatio/-/formatio-1.2.0.tgz#f3b2167d9068c4698a8d51f4f760a39a54d818eb"
+  integrity sha1-87IWfZBoxGmKjVH092CjmlTYGOs=
+  dependencies:
+    samsam "1.x"
+
+forwarded@~0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
+  integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=
+
+fragment-cache@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
+  integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=
+  dependencies:
+    map-cache "^0.2.2"
+
+freeport@^1.0.4:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/freeport/-/freeport-1.0.5.tgz#255e8ab84170c33ba85d990e821ae5f4a1a9bc5d"
+  integrity sha1-JV6KuEFwwzuoXZkOghrl9KGpvF0=
+
+fresh@0.5.2:
+  version "0.5.2"
+  resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
+  integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
+
+fried-twinkie@^0.2.2:
+  version "0.2.2"
+  resolved "https://registry.yarnpkg.com/fried-twinkie/-/fried-twinkie-0.2.2.tgz#fafa52b3b7957dc78d7867b28f74b6e01bdb2aee"
+  integrity sha512-rb/i+7VXEToBjrYZ2jSew4bI9znWF15P52dAGuoJcxpaBibWz2PI5tRx0ZSjDM+a/gZI2Pgr2XHT6wwNVZQ7/g==
+  dependencies:
+    "@types/cheerio" "^0.22.2"
+    chalk "^2.1.0"
+    google-closure-compiler-js "^20170626.0.0"
+    tmp "^0.0.31"
+    tsickle "^0.23.4"
+    twinkie "0.0.11"
+    typescript "^2.4.1"
+
+fs-constants@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
+  integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
+
+fs-exists-sync@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add"
+  integrity sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=
+
+fs-minipass@^1.2.5:
+  version "1.2.5"
+  resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d"
+  integrity sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==
+  dependencies:
+    minipass "^2.2.1"
+
+fs.realpath@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+  integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
+
+fsevents@^1.0.0:
+  version "1.2.9"
+  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f"
+  integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==
+  dependencies:
+    nan "^2.12.1"
+    node-pre-gyp "^0.12.0"
+
+function-bind@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
+  integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
+
+functional-red-black-tree@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
+  integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
+
+gauge@~2.7.3:
+  version "2.7.4"
+  resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
+  integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=
+  dependencies:
+    aproba "^1.0.3"
+    console-control-strings "^1.0.0"
+    has-unicode "^2.0.0"
+    object-assign "^4.1.0"
+    signal-exit "^3.0.0"
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+    wide-align "^1.1.0"
+
+get-stdin@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
+  integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=
+
+get-stream@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
+  integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
+
+get-stream@^4.0.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
+  integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==
+  dependencies:
+    pump "^3.0.0"
+
+get-value@^2.0.3, get-value@^2.0.6:
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
+  integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=
+
+getpass@^0.1.1:
+  version "0.1.7"
+  resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
+  integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=
+  dependencies:
+    assert-plus "^1.0.0"
+
+gh-got@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/gh-got/-/gh-got-6.0.0.tgz#d74353004c6ec466647520a10bd46f7299d268d0"
+  integrity sha512-F/mS+fsWQMo1zfgG9MD8KWvTWPPzzhuVwY++fhQ5Ggd+0P+CAMHtzMZhNxG+TqGfHDChJKsbh6otfMGqO2AKBw==
+  dependencies:
+    got "^7.0.0"
+    is-plain-obj "^1.1.0"
+
+github-username@^4.0.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/github-username/-/github-username-4.1.0.tgz#cbe280041883206da4212ae9e4b5f169c30bf417"
+  integrity sha1-y+KABBiDIG2kISrp5LXxacML9Bc=
+  dependencies:
+    gh-got "^6.0.0"
+
+glob-base@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
+  integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=
+  dependencies:
+    glob-parent "^2.0.0"
+    is-glob "^2.0.0"
+
+glob-parent@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28"
+  integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=
+  dependencies:
+    is-glob "^2.0.0"
+
+glob-parent@^3.0.0, glob-parent@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
+  integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=
+  dependencies:
+    is-glob "^3.1.0"
+    path-dirname "^1.0.0"
+
+glob-parent@^5.0.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2"
+  integrity sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==
+  dependencies:
+    is-glob "^4.0.1"
+
+glob-stream@^5.3.2:
+  version "5.3.5"
+  resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-5.3.5.tgz#a55665a9a8ccdc41915a87c701e32d4e016fad22"
+  integrity sha1-pVZlqajM3EGRWofHAeMtTgFvrSI=
+  dependencies:
+    extend "^3.0.0"
+    glob "^5.0.3"
+    glob-parent "^3.0.0"
+    micromatch "^2.3.7"
+    ordered-read-streams "^0.3.0"
+    through2 "^0.6.0"
+    to-absolute-glob "^0.1.1"
+    unique-stream "^2.0.2"
+
+glob-to-regexp@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
+  integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=
+
+glob@^5.0.3:
+  version "5.0.15"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1"
+  integrity sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=
+  dependencies:
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "2 || 3"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+glob@^6.0.1:
+  version "6.0.4"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22"
+  integrity sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=
+  dependencies:
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "2 || 3"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2:
+  version "7.1.4"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255"
+  integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==
+  dependencies:
+    fs.realpath "^1.0.0"
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "^3.0.4"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+glob@^7.1.3, glob@^7.1.4:
+  version "7.1.6"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
+  integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
+  dependencies:
+    fs.realpath "^1.0.0"
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "^3.0.4"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+global-dirs@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445"
+  integrity sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=
+  dependencies:
+    ini "^1.3.4"
+
+global-modules@^0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d"
+  integrity sha1-6lo77ULG1s6ZWk+KEmm12uIjgo0=
+  dependencies:
+    global-prefix "^0.1.4"
+    is-windows "^0.2.0"
+
+global-modules@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea"
+  integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==
+  dependencies:
+    global-prefix "^1.0.1"
+    is-windows "^1.0.1"
+    resolve-dir "^1.0.0"
+
+global-prefix@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f"
+  integrity sha1-jTvGuNo8qBEqFg2NSW/wRiv+948=
+  dependencies:
+    homedir-polyfill "^1.0.0"
+    ini "^1.3.4"
+    is-windows "^0.2.0"
+    which "^1.2.12"
+
+global-prefix@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe"
+  integrity sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=
+  dependencies:
+    expand-tilde "^2.0.2"
+    homedir-polyfill "^1.0.1"
+    ini "^1.3.4"
+    is-windows "^1.0.1"
+    which "^1.2.14"
+
+globals@^11.1.0:
+  version "11.12.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
+  integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
+
+globals@^12.1.0:
+  version "12.3.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-12.3.0.tgz#1e564ee5c4dded2ab098b0f88f24702a3c56be13"
+  integrity sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw==
+  dependencies:
+    type-fest "^0.8.1"
+
+globals@^9.18.0:
+  version "9.18.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a"
+  integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==
+
+globby@^4.0.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/globby/-/globby-4.1.0.tgz#080f54549ec1b82a6c60e631fc82e1211dbe95f8"
+  integrity sha1-CA9UVJ7BuCpsYOYx/ILhIR2+lfg=
+  dependencies:
+    array-union "^1.0.1"
+    arrify "^1.0.0"
+    glob "^6.0.1"
+    object-assign "^4.0.1"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+globby@^6.1.0:
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c"
+  integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=
+  dependencies:
+    array-union "^1.0.1"
+    glob "^7.0.3"
+    object-assign "^4.0.1"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+globby@^8.0.1:
+  version "8.0.2"
+  resolved "https://registry.yarnpkg.com/globby/-/globby-8.0.2.tgz#5697619ccd95c5275dbb2d6faa42087c1a941d8d"
+  integrity sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==
+  dependencies:
+    array-union "^1.0.1"
+    dir-glob "2.0.0"
+    fast-glob "^2.0.2"
+    glob "^7.1.2"
+    ignore "^3.3.5"
+    pify "^3.0.0"
+    slash "^1.0.0"
+
+google-closure-compiler-js@^20170626.0.0:
+  version "20170626.0.0"
+  resolved "https://registry.yarnpkg.com/google-closure-compiler-js/-/google-closure-compiler-js-20170626.0.0.tgz#5df265b277d1ec6fdea12eed131d1491cd8a8d71"
+  integrity sha512-LQvWXN3yS2l88TsXiHZ0aWtGR51tep/bNvS7cuUldnKkppgknTo35jThYwE+JOU9lviERZjMHhiqxz2CXzIRuw==
+  dependencies:
+    minimist "^1.2.0"
+    vinyl "^2.0.1"
+    webpack-core "^0.6.8"
+
+got@^5.0.0:
+  version "5.7.1"
+  resolved "https://registry.yarnpkg.com/got/-/got-5.7.1.tgz#5f81635a61e4a6589f180569ea4e381680a51f35"
+  integrity sha1-X4FjWmHkplifGAVp6k44FoClHzU=
+  dependencies:
+    create-error-class "^3.0.1"
+    duplexer2 "^0.1.4"
+    is-redirect "^1.0.0"
+    is-retry-allowed "^1.0.0"
+    is-stream "^1.0.0"
+    lowercase-keys "^1.0.0"
+    node-status-codes "^1.0.0"
+    object-assign "^4.0.1"
+    parse-json "^2.1.0"
+    pinkie-promise "^2.0.0"
+    read-all-stream "^3.0.0"
+    readable-stream "^2.0.5"
+    timed-out "^3.0.0"
+    unzip-response "^1.0.2"
+    url-parse-lax "^1.0.0"
+
+got@^6.7.1:
+  version "6.7.1"
+  resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0"
+  integrity sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=
+  dependencies:
+    create-error-class "^3.0.0"
+    duplexer3 "^0.1.4"
+    get-stream "^3.0.0"
+    is-redirect "^1.0.0"
+    is-retry-allowed "^1.0.0"
+    is-stream "^1.0.0"
+    lowercase-keys "^1.0.0"
+    safe-buffer "^5.0.1"
+    timed-out "^4.0.0"
+    unzip-response "^2.0.1"
+    url-parse-lax "^1.0.0"
+
+got@^7.0.0:
+  version "7.1.0"
+  resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a"
+  integrity sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==
+  dependencies:
+    decompress-response "^3.2.0"
+    duplexer3 "^0.1.4"
+    get-stream "^3.0.0"
+    is-plain-obj "^1.1.0"
+    is-retry-allowed "^1.0.0"
+    is-stream "^1.0.0"
+    isurl "^1.0.0-alpha5"
+    lowercase-keys "^1.0.0"
+    p-cancelable "^0.3.0"
+    p-timeout "^1.1.1"
+    safe-buffer "^5.0.1"
+    timed-out "^4.0.0"
+    url-parse-lax "^1.0.0"
+    url-to-options "^1.0.1"
+
+graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.0.tgz#8d8fdc73977cb04104721cb53666c1ca64cd328b"
+  integrity sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==
+
+graceful-fs@^4.2.0:
+  version "4.2.3"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423"
+  integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==
+
+grouped-queue@^0.3.0, grouped-queue@^0.3.3:
+  version "0.3.3"
+  resolved "https://registry.yarnpkg.com/grouped-queue/-/grouped-queue-0.3.3.tgz#c167d2a5319c5a0e0964ef6a25b7c2df8996c85c"
+  integrity sha1-wWfSpTGcWg4JZO9qJbfC34mWyFw=
+  dependencies:
+    lodash "^4.17.2"
+
+gulp-if@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/gulp-if/-/gulp-if-2.0.2.tgz#a497b7e7573005041caa2bc8b7dda3c80444d629"
+  integrity sha1-pJe351cwBQQcqivIt92jyARE1ik=
+  dependencies:
+    gulp-match "^1.0.3"
+    ternary-stream "^2.0.1"
+    through2 "^2.0.1"
+
+gulp-match@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/gulp-match/-/gulp-match-1.0.3.tgz#91c7c0d7f29becd6606d57d80a7f8776a87aba8e"
+  integrity sha1-kcfA1/Kb7NZgbVfYCn+Hdqh6uo4=
+  dependencies:
+    minimatch "^3.0.3"
+
+gulp-sourcemaps@1.6.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/gulp-sourcemaps/-/gulp-sourcemaps-1.6.0.tgz#b86ff349d801ceb56e1d9e7dc7bbcb4b7dee600c"
+  integrity sha1-uG/zSdgBzrVuHZ59x7vLS33uYAw=
+  dependencies:
+    convert-source-map "^1.1.1"
+    graceful-fs "^4.1.2"
+    strip-bom "^2.0.0"
+    through2 "^2.0.0"
+    vinyl "^1.0.0"
+
+gunzip-maybe@^1.3.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/gunzip-maybe/-/gunzip-maybe-1.4.1.tgz#39c72ed89d1b49ba708e18776500488902a52027"
+  integrity sha512-qtutIKMthNJJgeHQS7kZ9FqDq59/Wn0G2HYCRNjpup7yKfVI6/eqwpmroyZGFoCYaG+sW6psNVb4zoLADHpp2g==
+  dependencies:
+    browserify-zlib "^0.1.4"
+    is-deflate "^1.0.0"
+    is-gzip "^1.0.0"
+    peek-stream "^1.1.0"
+    pumpify "^1.3.3"
+    through2 "^2.0.3"
+
+handle-thing@^1.2.5:
+  version "1.2.5"
+  resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4"
+  integrity sha1-/Xqtcmvxpf0W38KbL3pmAdJxOcQ=
+
+har-schema@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
+  integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
+
+har-validator@~5.1.0:
+  version "5.1.3"
+  resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080"
+  integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==
+  dependencies:
+    ajv "^6.5.5"
+    har-schema "^2.0.0"
+
+has-ansi@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
+  integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=
+  dependencies:
+    ansi-regex "^2.0.0"
+
+has-binary2@~1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d"
+  integrity sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==
+  dependencies:
+    isarray "2.0.1"
+
+has-color@~0.1.0:
+  version "0.1.7"
+  resolved "https://registry.yarnpkg.com/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f"
+  integrity sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=
+
+has-cors@1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39"
+  integrity sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=
+
+has-flag@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+  integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
+
+has-symbol-support-x@^1.4.1:
+  version "1.4.2"
+  resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455"
+  integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==
+
+has-symbols@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44"
+  integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=
+
+has-to-string-tag-x@^1.2.0:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d"
+  integrity sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==
+  dependencies:
+    has-symbol-support-x "^1.4.1"
+
+has-unicode@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
+  integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=
+
+has-value@^0.3.1:
+  version "0.3.1"
+  resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
+  integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=
+  dependencies:
+    get-value "^2.0.3"
+    has-values "^0.1.4"
+    isobject "^2.0.0"
+
+has-value@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177"
+  integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=
+  dependencies:
+    get-value "^2.0.6"
+    has-values "^1.0.0"
+    isobject "^3.0.0"
+
+has-values@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771"
+  integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E=
+
+has-values@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f"
+  integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=
+  dependencies:
+    is-number "^3.0.0"
+    kind-of "^4.0.0"
+
+he@1.2.x:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
+  integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
+
+homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8"
+  integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==
+  dependencies:
+    parse-passwd "^1.0.0"
+
+hosted-git-info@^2.1.4:
+  version "2.7.1"
+  resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047"
+  integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==
+
+hpack.js@^2.1.6:
+  version "2.1.6"
+  resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2"
+  integrity sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=
+  dependencies:
+    inherits "^2.0.1"
+    obuf "^1.0.0"
+    readable-stream "^2.0.1"
+    wbuf "^1.1.0"
+
+html-minifier@^3.5.10:
+  version "3.5.21"
+  resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.21.tgz#d0040e054730e354db008463593194015212d20c"
+  integrity sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==
+  dependencies:
+    camel-case "3.0.x"
+    clean-css "4.2.x"
+    commander "2.17.x"
+    he "1.2.x"
+    param-case "2.1.x"
+    relateurl "0.2.x"
+    uglify-js "3.4.x"
+
+htmlparser2@^3.10.1, htmlparser2@^3.9.1:
+  version "3.10.1"
+  resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f"
+  integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==
+  dependencies:
+    domelementtype "^1.3.1"
+    domhandler "^2.3.0"
+    domutils "^1.5.1"
+    entities "^1.1.1"
+    inherits "^2.0.1"
+    readable-stream "^3.1.1"
+
+http-deceiver@^1.2.7:
+  version "1.2.7"
+  resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87"
+  integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=
+
+http-errors@1.7.2, http-errors@~1.7.2:
+  version "1.7.2"
+  resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f"
+  integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==
+  dependencies:
+    depd "~1.1.2"
+    inherits "2.0.3"
+    setprototypeof "1.1.1"
+    statuses ">= 1.5.0 < 2"
+    toidentifier "1.0.0"
+
+http-errors@~1.6.2:
+  version "1.6.3"
+  resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
+  integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=
+  dependencies:
+    depd "~1.1.2"
+    inherits "2.0.3"
+    setprototypeof "1.1.0"
+    statuses ">= 1.4.0 < 2"
+
+http-proxy-middleware@^0.17.2:
+  version "0.17.4"
+  resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.17.4.tgz#642e8848851d66f09d4f124912846dbaeb41b833"
+  integrity sha1-ZC6ISIUdZvCdTxJJEoRtuutBuDM=
+  dependencies:
+    http-proxy "^1.16.2"
+    is-glob "^3.1.0"
+    lodash "^4.17.2"
+    micromatch "^2.3.11"
+
+http-proxy@^1.16.2:
+  version "1.18.0"
+  resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.0.tgz#dbe55f63e75a347db7f3d99974f2692a314a6a3a"
+  integrity sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==
+  dependencies:
+    eventemitter3 "^4.0.0"
+    follow-redirects "^1.0.0"
+    requires-port "^1.0.0"
+
+http-signature@~1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
+  integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=
+  dependencies:
+    assert-plus "^1.0.0"
+    jsprim "^1.2.2"
+    sshpk "^1.7.0"
+
+https-proxy-agent@^2.2.1:
+  version "2.2.4"
+  resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b"
+  integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==
+  dependencies:
+    agent-base "^4.3.0"
+    debug "^3.1.0"
+
+https-proxy-agent@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz#b8c286433e87602311b01c8ea34413d856a4af81"
+  integrity sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==
+  dependencies:
+    agent-base "^4.3.0"
+    debug "^3.1.0"
+
+iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4:
+  version "0.4.24"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
+  integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
+  dependencies:
+    safer-buffer ">= 2.1.2 < 3"
+
+ieee754@^1.1.4:
+  version "1.1.13"
+  resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84"
+  integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==
+
+ignore-walk@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8"
+  integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==
+  dependencies:
+    minimatch "^3.0.4"
+
+ignore@^3.3.5:
+  version "3.3.10"
+  resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043"
+  integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==
+
+ignore@^4.0.6:
+  version "4.0.6"
+  resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
+  integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
+
+import-fresh@^3.0.0:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66"
+  integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==
+  dependencies:
+    parent-module "^1.0.0"
+    resolve-from "^4.0.0"
+
+import-lazy@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
+  integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=
+
+imurmurhash@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
+  integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
+
+indent-string@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80"
+  integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=
+  dependencies:
+    repeating "^2.0.0"
+
+indent@0.0.2:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/indent/-/indent-0.0.2.tgz#8c79f080190559b687034b84c7aefa97d5a911d9"
+  integrity sha1-jHnwgBkFWbaHA0uEx676l9WpEdk=
+
+indexof@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
+  integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=
+
+inflight@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+  integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
+  dependencies:
+    once "^1.3.0"
+    wrappy "1"
+
+inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+  integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+
+inherits@2.0.3:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+  integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
+
+ini@^1.3.4, ini@~1.3.0:
+  version "1.3.5"
+  resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
+  integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
+
+inquirer@^1.0.2:
+  version "1.2.3"
+  resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-1.2.3.tgz#4dec6f32f37ef7bb0b2ed3f1d1a5c3f545074918"
+  integrity sha1-TexvMvN+97sLLtPx0aXD9UUHSRg=
+  dependencies:
+    ansi-escapes "^1.1.0"
+    chalk "^1.0.0"
+    cli-cursor "^1.0.1"
+    cli-width "^2.0.0"
+    external-editor "^1.1.0"
+    figures "^1.3.5"
+    lodash "^4.3.0"
+    mute-stream "0.0.6"
+    pinkie-promise "^2.0.0"
+    run-async "^2.2.0"
+    rx "^4.1.0"
+    string-width "^1.0.1"
+    strip-ansi "^3.0.0"
+    through "^2.3.6"
+
+inquirer@^6.0.0:
+  version "6.4.1"
+  resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.4.1.tgz#7bd9e5ab0567cd23b41b0180b68e0cfa82fc3c0b"
+  integrity sha512-/Jw+qPZx4EDYsaT6uz7F4GJRNFMRdKNeUZw3ZnKV8lyuUgz/YWRCSUAJMZSVhSq4Ec0R2oYnyi6b3d4JXcL5Nw==
+  dependencies:
+    ansi-escapes "^3.2.0"
+    chalk "^2.4.2"
+    cli-cursor "^2.1.0"
+    cli-width "^2.0.0"
+    external-editor "^3.0.3"
+    figures "^2.0.0"
+    lodash "^4.17.11"
+    mute-stream "0.0.7"
+    run-async "^2.2.0"
+    rxjs "^6.4.0"
+    string-width "^2.1.0"
+    strip-ansi "^5.1.0"
+    through "^2.3.6"
+
+inquirer@^7.0.0:
+  version "7.0.3"
+  resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.0.3.tgz#f9b4cd2dff58b9f73e8d43759436ace15bed4567"
+  integrity sha512-+OiOVeVydu4hnCGLCSX+wedovR/Yzskv9BFqUNNKq9uU2qg7LCcCo3R86S2E7WLo0y/x2pnEZfZe1CoYnORUAw==
+  dependencies:
+    ansi-escapes "^4.2.1"
+    chalk "^2.4.2"
+    cli-cursor "^3.1.0"
+    cli-width "^2.0.0"
+    external-editor "^3.0.3"
+    figures "^3.0.0"
+    lodash "^4.17.15"
+    mute-stream "0.0.8"
+    run-async "^2.2.0"
+    rxjs "^6.5.3"
+    string-width "^4.1.0"
+    strip-ansi "^5.1.0"
+    through "^2.3.6"
+
+interpret@^1.0.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296"
+  integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==
+
+intersect@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/intersect/-/intersect-1.0.1.tgz#332650e10854d8c0ac58c192bdc27a8bf7e7a30c"
+  integrity sha1-MyZQ4QhU2MCsWMGSvcJ6i/fnoww=
+
+invariant@^2.2.2:
+  version "2.2.4"
+  resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
+  integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
+  dependencies:
+    loose-envify "^1.0.0"
+
+ipaddr.js@1.9.0:
+  version "1.9.0"
+  resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65"
+  integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==
+
+is-accessor-descriptor@^0.1.6:
+  version "0.1.6"
+  resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"
+  integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=
+  dependencies:
+    kind-of "^3.0.2"
+
+is-accessor-descriptor@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656"
+  integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==
+  dependencies:
+    kind-of "^6.0.0"
+
+is-arrayish@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+  integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
+
+is-arrayish@^0.3.1:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
+  integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==
+
+is-binary-path@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
+  integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=
+  dependencies:
+    binary-extensions "^1.0.0"
+
+is-buffer@^1.1.5, is-buffer@~1.1.1:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
+  integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
+
+is-ci@^1.0.10:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c"
+  integrity sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==
+  dependencies:
+    ci-info "^1.5.0"
+
+is-data-descriptor@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
+  integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=
+  dependencies:
+    kind-of "^3.0.2"
+
+is-data-descriptor@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7"
+  integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==
+  dependencies:
+    kind-of "^6.0.0"
+
+is-deflate@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-deflate/-/is-deflate-1.0.0.tgz#c862901c3c161fb09dac7cdc7e784f80e98f2f14"
+  integrity sha1-yGKQHDwWH7CdrHzcfnhPgOmPLxQ=
+
+is-descriptor@^0.1.0:
+  version "0.1.6"
+  resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca"
+  integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==
+  dependencies:
+    is-accessor-descriptor "^0.1.6"
+    is-data-descriptor "^0.1.4"
+    kind-of "^5.0.0"
+
+is-descriptor@^1.0.0, is-descriptor@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec"
+  integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==
+  dependencies:
+    is-accessor-descriptor "^1.0.0"
+    is-data-descriptor "^1.0.0"
+    kind-of "^6.0.2"
+
+is-dotfile@^1.0.0:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1"
+  integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=
+
+is-equal-shallow@^0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534"
+  integrity sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=
+  dependencies:
+    is-primitive "^2.0.0"
+
+is-extendable@^0.1.0, is-extendable@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
+  integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=
+
+is-extendable@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4"
+  integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==
+  dependencies:
+    is-plain-object "^2.0.4"
+
+is-extglob@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
+  integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=
+
+is-extglob@^2.1.0, is-extglob@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+  integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
+
+is-finite@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
+  integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=
+  dependencies:
+    number-is-nan "^1.0.0"
+
+is-fullwidth-code-point@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
+  integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs=
+  dependencies:
+    number-is-nan "^1.0.0"
+
+is-fullwidth-code-point@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
+  integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
+
+is-fullwidth-code-point@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
+  integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
+
+is-glob@^2.0.0, is-glob@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
+  integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=
+  dependencies:
+    is-extglob "^1.0.0"
+
+is-glob@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
+  integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=
+  dependencies:
+    is-extglob "^2.1.0"
+
+is-glob@^4.0.0, is-glob@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
+  integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
+  dependencies:
+    is-extglob "^2.1.1"
+
+is-gzip@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-gzip/-/is-gzip-1.0.0.tgz#6ca8b07b99c77998025900e555ced8ed80879a83"
+  integrity sha1-bKiwe5nHeZgCWQDlVc7Y7YCHmoM=
+
+is-installed-globally@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80"
+  integrity sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=
+  dependencies:
+    global-dirs "^0.1.0"
+    is-path-inside "^1.0.0"
+
+is-npm@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4"
+  integrity sha1-8vtjpl5JBbQGyGBydloaTceTufQ=
+
+is-number@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
+  integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=
+  dependencies:
+    kind-of "^3.0.2"
+
+is-number@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
+  integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=
+  dependencies:
+    kind-of "^3.0.2"
+
+is-number@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff"
+  integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==
+
+is-obj@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
+  integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8=
+
+is-object@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470"
+  integrity sha1-iVJojF7C/9awPsyF52ngKQMINHA=
+
+is-path-cwd@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d"
+  integrity sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=
+
+is-path-in-cwd@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52"
+  integrity sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==
+  dependencies:
+    is-path-inside "^1.0.0"
+
+is-path-inside@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036"
+  integrity sha1-jvW33lBDej/cprToZe96pVy0gDY=
+  dependencies:
+    path-is-inside "^1.0.1"
+
+is-plain-obj@^1.0.0, is-plain-obj@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
+  integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4=
+
+is-plain-object@^2.0.3, is-plain-object@^2.0.4:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
+  integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==
+  dependencies:
+    isobject "^3.0.1"
+
+is-plain-object@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-3.0.0.tgz#47bfc5da1b5d50d64110806c199359482e75a928"
+  integrity sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==
+  dependencies:
+    isobject "^4.0.0"
+
+is-posix-bracket@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
+  integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=
+
+is-potential-custom-element-name@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz#0c52e54bcca391bb2c494b21e8626d7336c6e397"
+  integrity sha1-DFLlS8yjkbssSUsh6GJtczbG45c=
+
+is-primitive@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
+  integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU=
+
+is-promise@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa"
+  integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=
+
+is-redirect@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24"
+  integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=
+
+is-retry-allowed@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34"
+  integrity sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=
+
+is-scoped@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-scoped/-/is-scoped-1.0.0.tgz#449ca98299e713038256289ecb2b540dc437cb30"
+  integrity sha1-RJypgpnnEwOCViieyytUDcQ3yzA=
+  dependencies:
+    scoped-regex "^1.0.0"
+
+is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
+  integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
+
+is-typedarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
+  integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
+
+is-utf8@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
+  integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=
+
+is-valid-glob@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-0.3.0.tgz#d4b55c69f51886f9b65c70d6c2622d37e29f48fe"
+  integrity sha1-1LVcafUYhvm2XHDWwmItN+KfSP4=
+
+is-windows@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c"
+  integrity sha1-3hqm1j6indJIc3tp8f+LgALSEIw=
+
+is-windows@^1.0.1, is-windows@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
+  integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
+
+isarray@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
+  integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
+
+isarray@1.0.0, isarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+  integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
+
+isarray@2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e"
+  integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=
+
+isbinaryfile@^3.0.2:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.3.tgz#5d6def3edebf6e8ca8cae9c30183a804b5f8be80"
+  integrity sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==
+  dependencies:
+    buffer-alloc "^1.2.0"
+
+isexe@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+  integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
+
+isobject@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
+  integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=
+  dependencies:
+    isarray "1.0.0"
+
+isobject@^3.0.0, isobject@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
+  integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
+
+isobject@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/isobject/-/isobject-4.0.0.tgz#3f1c9155e73b192022a80819bacd0343711697b0"
+  integrity sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==
+
+isstream@~0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
+  integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
+
+istextorbinary@^2.2.1:
+  version "2.5.1"
+  resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.5.1.tgz#14a33824cf6b9d5d7743eac1be2bd2c310d0ccbd"
+  integrity sha512-pv/JNPWnfpwGjPx7JrtWTwsWsxkrK3fNzcEVnt92YKEIErps4Fsk49+qzCe9iQF2hjqK8Naqf8P9kzoeCuQI1g==
+  dependencies:
+    binaryextensions "^2.1.2"
+    editions "^2.1.3"
+    textextensions "^2.4.0"
+
+isurl@^1.0.0-alpha5:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67"
+  integrity sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==
+  dependencies:
+    has-to-string-tag-x "^1.2.0"
+    is-object "^1.0.1"
+
+"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+  integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
+
+js-tokens@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
+  integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls=
+
+js-yaml@^3.13.1:
+  version "3.13.1"
+  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
+  integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
+  dependencies:
+    argparse "^1.0.7"
+    esprima "^4.0.0"
+
+jsbn@~0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
+  integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
+
+jsdoctypeparser@^6.1.0:
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/jsdoctypeparser/-/jsdoctypeparser-6.1.0.tgz#acfb936c26300d98f1405cb03e20b06748e512a8"
+  integrity sha512-UCQBZ3xCUBv/PLfwKAJhp6jmGOSLFNKzrotXGNgbKhWvz27wPsCsVeP7gIcHPElQw2agBmynAitXqhxR58XAmA==
+
+jsesc@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b"
+  integrity sha1-RsP+yMGJKxKwgz25vHYiF226s0s=
+
+jsesc@^2.5.1:
+  version "2.5.2"
+  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
+  integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
+
+jsesc@~0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
+  integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=
+
+json-parse-better-errors@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
+  integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
+
+json-schema-traverse@^0.4.1:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
+  integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
+
+json-schema@0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
+  integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
+
+json-stable-stringify-without-jsonify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
+  integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
+
+json-stringify-safe@~5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
+  integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
+
+json5@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.0.tgz#e7a0c62c48285c628d20a10b85c89bb807c32850"
+  integrity sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==
+  dependencies:
+    minimist "^1.2.0"
+
+jsonschema@^1.1.0, jsonschema@^1.1.1:
+  version "1.2.4"
+  resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.2.4.tgz#a46bac5d3506a254465bc548876e267c6d0d6464"
+  integrity sha512-lz1nOH69GbsVHeVgEdvyavc/33oymY1AZwtePMiMj4HZPMbP5OIKK3zT9INMWjwua/V4Z4yq7wSlBbSG+g4AEw==
+
+jsprim@^1.2.2:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
+  integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=
+  dependencies:
+    assert-plus "1.0.0"
+    extsprintf "1.3.0"
+    json-schema "0.2.3"
+    verror "1.10.0"
+
+kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
+  version "3.2.2"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
+  integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=
+  dependencies:
+    is-buffer "^1.1.5"
+
+kind-of@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57"
+  integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc=
+  dependencies:
+    is-buffer "^1.1.5"
+
+kind-of@^5.0.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d"
+  integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==
+
+kind-of@^6.0.0, kind-of@^6.0.2:
+  version "6.0.2"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051"
+  integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==
+
+kuler@1.0.x:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/kuler/-/kuler-1.0.1.tgz#ef7c784f36c9fb6e16dd3150d152677b2b0228a6"
+  integrity sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==
+  dependencies:
+    colornames "^1.1.1"
+
+latest-version@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-2.0.0.tgz#56f8d6139620847b8017f8f1f4d78e211324168b"
+  integrity sha1-VvjWE5YghHuAF/jx9NeOIRMkFos=
+  dependencies:
+    package-json "^2.0.0"
+
+latest-version@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15"
+  integrity sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=
+  dependencies:
+    package-json "^4.0.0"
+
+launchpad@^0.7.0:
+  version "0.7.4"
+  resolved "https://registry.yarnpkg.com/launchpad/-/launchpad-0.7.4.tgz#08a7a38f48b963e73dc68be84f9f8f974c46c26b"
+  integrity sha512-3KDFHbvXm52CEA4vSQ9kz4vwAxH7SANj2k6SJcE6LCpmMJFOu6wCpZwXb+pq9kSDknl5XInBWeOl40i00P6wTQ==
+  dependencies:
+    async "^2.0.1"
+    browserstack "^1.2.0"
+    debug "^2.2.0"
+    mkdirp "^0.5.1"
+    plist "^2.0.1"
+    q "^1.4.1"
+    rimraf "^3.0.0"
+    underscore "^1.8.3"
+
+lazy-req@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/lazy-req/-/lazy-req-1.1.0.tgz#bdaebead30f8d824039ce0ce149d4daa07ba1fac"
+  integrity sha1-va6+rTD42CQDnODOFJ1Nqge6H6w=
+
+lazystream@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4"
+  integrity sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=
+  dependencies:
+    readable-stream "^2.0.5"
+
+levn@^0.3.0, levn@~0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
+  integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=
+  dependencies:
+    prelude-ls "~1.1.2"
+    type-check "~0.3.2"
+
+load-json-file@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
+  integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=
+  dependencies:
+    graceful-fs "^4.1.2"
+    parse-json "^2.2.0"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+    strip-bom "^2.0.0"
+
+load-json-file@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b"
+  integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs=
+  dependencies:
+    graceful-fs "^4.1.2"
+    parse-json "^4.0.0"
+    pify "^3.0.0"
+    strip-bom "^3.0.0"
+
+locate-path@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
+  integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==
+  dependencies:
+    p-locate "^3.0.0"
+    path-exists "^3.0.0"
+
+lodash._reinterpolate@~3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
+  integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=
+
+lodash.camelcase@^4.3.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
+  integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY=
+
+lodash.defaults@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
+  integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=
+
+lodash.difference@^4.5.0:
+  version "4.5.0"
+  resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c"
+  integrity sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=
+
+lodash.flatten@^4.4.0:
+  version "4.4.0"
+  resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f"
+  integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=
+
+lodash.get@^4.4.2:
+  version "4.4.2"
+  resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
+  integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=
+
+lodash.isequal@^4.0.0:
+  version "4.5.0"
+  resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
+  integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
+
+lodash.isplainobject@^4.0.6:
+  version "4.0.6"
+  resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
+  integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=
+
+lodash.padend@^4.6.1:
+  version "4.6.1"
+  resolved "https://registry.yarnpkg.com/lodash.padend/-/lodash.padend-4.6.1.tgz#53ccba047d06e158d311f45da625f4e49e6f166e"
+  integrity sha1-U8y6BH0G4VjTEfRdpiX05J5vFm4=
+
+lodash.set@^4.3.2:
+  version "4.3.2"
+  resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23"
+  integrity sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=
+
+lodash.some@^4.6.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d"
+  integrity sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=
+
+lodash.sortby@^4.7.0:
+  version "4.7.0"
+  resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
+  integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
+
+lodash.template@^4.4.0:
+  version "4.4.0"
+  resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0"
+  integrity sha1-5zoDhcg1VZF0bgILmWecaQ5o+6A=
+  dependencies:
+    lodash._reinterpolate "~3.0.0"
+    lodash.templatesettings "^4.0.0"
+
+lodash.templatesettings@^4.0.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316"
+  integrity sha1-K01OlbpEDZFf8IvImeRVNmZxMxY=
+  dependencies:
+    lodash._reinterpolate "~3.0.0"
+
+lodash.union@^4.6.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88"
+  integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=
+
+lodash.uniq@^4.5.0:
+  version "4.5.0"
+  resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
+  integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
+
+lodash@^3.0.0, lodash@^3.10.1:
+  version "3.10.1"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
+  integrity sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=
+
+lodash@^4.0.0, lodash@^4.15.0, lodash@^4.16.6, lodash@^4.17.14, lodash@^4.17.15:
+  version "4.17.15"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
+  integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
+
+lodash@^4.11.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.3.0:
+  version "4.17.12"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.12.tgz#a712c74fdc31f7ecb20fe44f157d802d208097ef"
+  integrity sha512-+CiwtLnsJhX03p20mwXuvhoebatoh5B3tt+VvYlrPgZC1g36y+RRbkufX95Xa+X4I59aWEacDFYwnJZiyBh9gA==
+
+log-symbols@^1.0.0, log-symbols@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18"
+  integrity sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=
+  dependencies:
+    chalk "^1.0.0"
+
+log-symbols@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a"
+  integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==
+  dependencies:
+    chalk "^2.0.1"
+
+logform@^1.9.1:
+  version "1.10.0"
+  resolved "https://registry.yarnpkg.com/logform/-/logform-1.10.0.tgz#c9d5598714c92b546e23f4e78147c40f1e02012e"
+  integrity sha512-em5ojIhU18fIMOw/333mD+ZLE2fis0EzXl1ZwHx4iQzmpQi6odNiY/t+ITNr33JZhT9/KEaH+UPIipr6a9EjWg==
+  dependencies:
+    colors "^1.2.1"
+    fast-safe-stringify "^2.0.4"
+    fecha "^2.3.3"
+    ms "^2.1.1"
+    triple-beam "^1.2.0"
+
+logform@^2.1.1:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/logform/-/logform-2.1.2.tgz#957155ebeb67a13164069825ce67ddb5bb2dd360"
+  integrity sha512-+lZh4OpERDBLqjiwDLpAWNQu6KMjnlXH2ByZwCuSqVPJletw0kTWJf5CgSNAUKn1KUkv3m2cUz/LK8zyEy7wzQ==
+  dependencies:
+    colors "^1.2.1"
+    fast-safe-stringify "^2.0.4"
+    fecha "^2.3.3"
+    ms "^2.1.1"
+    triple-beam "^1.3.0"
+
+lolex@^1.6.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/lolex/-/lolex-1.6.0.tgz#3a9a0283452a47d7439e72731b9e07d7386e49f6"
+  integrity sha1-OpoCg0UqR9dDnnJzG54H1zhuSfY=
+
+long@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28"
+  integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==
+
+loose-envify@^1.0.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
+  integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
+  dependencies:
+    js-tokens "^3.0.0 || ^4.0.0"
+
+loud-rejection@^1.0.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
+  integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=
+  dependencies:
+    currently-unhandled "^0.4.1"
+    signal-exit "^3.0.0"
+
+lower-case@^1.1.1:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac"
+  integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw=
+
+lowercase-keys@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
+  integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==
+
+lru-cache@^4.0.1, lru-cache@^4.0.2:
+  version "4.1.5"
+  resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
+  integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
+  dependencies:
+    pseudomap "^1.0.2"
+    yallist "^2.1.2"
+
+macos-release@^2.2.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.3.0.tgz#eb1930b036c0800adebccd5f17bc4c12de8bb71f"
+  integrity sha512-OHhSbtcviqMPt7yfw5ef5aghS2jzFVKEFyCJndQt2YpSQ9qRVSEv2axSJI1paVThEu+FFGs584h/1YhxjVqajA==
+
+magic-string@^0.22.4:
+  version "0.22.5"
+  resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.22.5.tgz#8e9cf5afddf44385c1da5bc2a6a0dbd10b03657e"
+  integrity sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==
+  dependencies:
+    vlq "^0.2.2"
+
+make-dir@^1.0.0, make-dir@^1.1.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c"
+  integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==
+  dependencies:
+    pify "^3.0.0"
+
+map-cache@^0.2.2:
+  version "0.2.2"
+  resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
+  integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=
+
+map-obj@^1.0.0, map-obj@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
+  integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=
+
+map-visit@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f"
+  integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=
+  dependencies:
+    object-visit "^1.0.0"
+
+matcher@^1.1.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/matcher/-/matcher-1.1.1.tgz#51d8301e138f840982b338b116bb0c09af62c1c2"
+  integrity sha512-+BmqxWIubKTRKNWx/ahnCkk3mG8m7OturVlqq6HiojGJTd5hVYbgZm6WzcYPCoB+KBT4Vd6R7WSRG2OADNaCjg==
+  dependencies:
+    escape-string-regexp "^1.0.4"
+
+math-random@^1.0.1:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c"
+  integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==
+
+md5@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9"
+  integrity sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=
+  dependencies:
+    charenc "~0.0.1"
+    crypt "~0.0.1"
+    is-buffer "~1.1.1"
+
+media-typer@0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
+  integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
+
+mem-fs-editor@^5.0.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/mem-fs-editor/-/mem-fs-editor-5.1.0.tgz#51972241640be8567680a04f7adaffe5fc603667"
+  integrity sha512-2Yt2GCYEbcotYbIJagmow4gEtHDqzpq5XN94+yAx/NT5+bGqIjkXnm3KCUQfE6kRfScGp9IZknScoGRKu8L78w==
+  dependencies:
+    commondir "^1.0.1"
+    deep-extend "^0.6.0"
+    ejs "^2.5.9"
+    glob "^7.0.3"
+    globby "^8.0.1"
+    isbinaryfile "^3.0.2"
+    mkdirp "^0.5.0"
+    multimatch "^2.0.0"
+    rimraf "^2.2.8"
+    through2 "^2.0.0"
+    vinyl "^2.0.1"
+
+mem-fs@^1.1.0:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/mem-fs/-/mem-fs-1.1.3.tgz#b8ae8d2e3fcb6f5d3f9165c12d4551a065d989cc"
+  integrity sha1-uK6NLj/Lb10/kWXBLUVRoGXZicw=
+  dependencies:
+    through2 "^2.0.0"
+    vinyl "^1.1.0"
+    vinyl-file "^2.0.0"
+
+meow@^3.1.0, meow@^3.7.0:
+  version "3.7.0"
+  resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb"
+  integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=
+  dependencies:
+    camelcase-keys "^2.0.0"
+    decamelize "^1.1.2"
+    loud-rejection "^1.0.0"
+    map-obj "^1.0.1"
+    minimist "^1.1.3"
+    normalize-package-data "^2.3.4"
+    object-assign "^4.0.1"
+    read-pkg-up "^1.0.1"
+    redent "^1.0.0"
+    trim-newlines "^1.0.0"
+
+merge-descriptors@1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
+  integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
+
+merge-stream@^1.0.0, merge-stream@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1"
+  integrity sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=
+  dependencies:
+    readable-stream "^2.0.1"
+
+merge2@^1.2.3:
+  version "1.2.3"
+  resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.3.tgz#7ee99dbd69bb6481689253f018488a1b902b0ed5"
+  integrity sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA==
+
+methods@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
+  integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
+
+micromatch@^2.1.5, micromatch@^2.3.11, micromatch@^2.3.7:
+  version "2.3.11"
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
+  integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=
+  dependencies:
+    arr-diff "^2.0.0"
+    array-unique "^0.2.1"
+    braces "^1.8.2"
+    expand-brackets "^0.1.4"
+    extglob "^0.3.1"
+    filename-regex "^2.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.1"
+    kind-of "^3.0.2"
+    normalize-path "^2.0.1"
+    object.omit "^2.0.0"
+    parse-glob "^3.0.4"
+    regex-cache "^0.4.2"
+
+micromatch@^3.0.4, micromatch@^3.1.10:
+  version "3.1.10"
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
+  integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==
+  dependencies:
+    arr-diff "^4.0.0"
+    array-unique "^0.3.2"
+    braces "^2.3.1"
+    define-property "^2.0.2"
+    extend-shallow "^3.0.2"
+    extglob "^2.0.4"
+    fragment-cache "^0.2.1"
+    kind-of "^6.0.2"
+    nanomatch "^1.2.9"
+    object.pick "^1.3.0"
+    regex-not "^1.0.0"
+    snapdragon "^0.8.1"
+    to-regex "^3.0.2"
+
+mime-db@1.40.0, mime-db@^1.28.0:
+  version "1.40.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32"
+  integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==
+
+mime-db@1.43.0, "mime-db@>= 1.43.0 < 2":
+  version "1.43.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58"
+  integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==
+
+mime-types@^2.1.12, mime-types@~2.1.19:
+  version "2.1.24"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81"
+  integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==
+  dependencies:
+    mime-db "1.40.0"
+
+mime-types@~2.1.24:
+  version "2.1.26"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06"
+  integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==
+  dependencies:
+    mime-db "1.43.0"
+
+mime@1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
+  integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==
+
+mime@1.6.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
+  integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
+
+mime@^2.3.1:
+  version "2.4.4"
+  resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5"
+  integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==
+
+mimic-fn@^1.0.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
+  integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
+
+mimic-fn@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
+  integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
+
+mimic-response@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
+  integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
+
+minimalistic-assert@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
+  integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
+
+minimatch-all@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/minimatch-all/-/minimatch-all-1.1.0.tgz#40c496a27a2e128d19bf758e76bb01a0c7145787"
+  integrity sha1-QMSWonouEo0Zv3WOdrsBoMcUV4c=
+  dependencies:
+    minimatch "^3.0.2"
+
+"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
+  integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
+  dependencies:
+    brace-expansion "^1.1.7"
+
+minimist@0.0.8, minimist@~0.0.1:
+  version "0.0.8"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
+  integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
+
+minimist@^1.1.3, minimist@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
+  integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
+
+minipass@^2.2.1, minipass@^2.3.4:
+  version "2.3.5"
+  resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848"
+  integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==
+  dependencies:
+    safe-buffer "^5.1.2"
+    yallist "^3.0.0"
+
+minizlib@^1.1.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614"
+  integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==
+  dependencies:
+    minipass "^2.2.1"
+
+mixin-deep@^1.2.0:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
+  integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==
+  dependencies:
+    for-in "^1.0.2"
+    is-extendable "^1.0.1"
+
+mkdirp@^0.5.0, mkdirp@^0.5.1:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
+  integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
+  dependencies:
+    minimist "0.0.8"
+
+mout@^1.0.0:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/mout/-/mout-1.2.2.tgz#c9b718a499806a0632cede178e80f436259e777d"
+  integrity sha512-w0OUxFEla6z3d7sVpMZGBCpQvYh8PHS1wZ6Wu9GNKHMpAHWJ0if0LsQZh3DlOqw55HlhJEOMLpFnwtxp99Y5GA==
+
+ms@2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+  integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
+
+ms@2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
+  integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
+
+ms@^2.1.1:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
+  integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+
+multer@^1.3.0:
+  version "1.4.2"
+  resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.2.tgz#2f1f4d12dbaeeba74cb37e623f234bf4d3d2057a"
+  integrity sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg==
+  dependencies:
+    append-field "^1.0.0"
+    busboy "^0.2.11"
+    concat-stream "^1.5.2"
+    mkdirp "^0.5.1"
+    object-assign "^4.1.1"
+    on-finished "^2.3.0"
+    type-is "^1.6.4"
+    xtend "^4.0.0"
+
+multimatch@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-2.1.0.tgz#9c7906a22fb4c02919e2f5f75161b4cdbd4b2a2b"
+  integrity sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=
+  dependencies:
+    array-differ "^1.0.0"
+    array-union "^1.0.1"
+    arrify "^1.0.0"
+    minimatch "^3.0.0"
+
+multipipe@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-1.0.2.tgz#cc13efd833c9cda99f224f868461b8e1a3fd939d"
+  integrity sha1-zBPv2DPJzamfIk+GhGG44aP9k50=
+  dependencies:
+    duplexer2 "^0.1.2"
+    object-assign "^4.1.0"
+
+mute-stream@0.0.6:
+  version "0.0.6"
+  resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db"
+  integrity sha1-SJYrGeFp/R38JAs/HnMXYnu8R9s=
+
+mute-stream@0.0.7:
+  version "0.0.7"
+  resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
+  integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=
+
+mute-stream@0.0.8:
+  version "0.0.8"
+  resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
+  integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
+
+mz@^2.4.0, mz@^2.6.0:
+  version "2.7.0"
+  resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32"
+  integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==
+  dependencies:
+    any-promise "^1.0.0"
+    object-assign "^4.0.1"
+    thenify-all "^1.0.0"
+
+nan@^2.12.1:
+  version "2.14.0"
+  resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
+  integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
+
+nanomatch@^1.2.9:
+  version "1.2.13"
+  resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
+  integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==
+  dependencies:
+    arr-diff "^4.0.0"
+    array-unique "^0.3.2"
+    define-property "^2.0.2"
+    extend-shallow "^3.0.2"
+    fragment-cache "^0.2.1"
+    is-windows "^1.0.2"
+    kind-of "^6.0.2"
+    object.pick "^1.3.0"
+    regex-not "^1.0.0"
+    snapdragon "^0.8.1"
+    to-regex "^3.0.1"
+
+native-promise-only@^0.8.1:
+  version "0.8.1"
+  resolved "https://registry.yarnpkg.com/native-promise-only/-/native-promise-only-0.8.1.tgz#20a318c30cb45f71fe7adfbf7b21c99c1472ef11"
+  integrity sha1-IKMYwwy0X3H+et+/eyHJnBRy7xE=
+
+natural-compare@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+  integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
+
+needle@^2.2.1:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/needle/-/needle-2.3.0.tgz#ce3fea21197267bacb310705a7bbe24f2a3a3492"
+  integrity sha512-QBZu7aAFR0522EyaXZM0FZ9GLpq6lvQ3uq8gteiDUp7wKdy0lSd2hPlgFwVuW1CBkfEs9PfDQsQzZghLs/psdg==
+  dependencies:
+    debug "^4.1.0"
+    iconv-lite "^0.4.4"
+    sax "^1.2.4"
+
+negotiator@0.6.2:
+  version "0.6.2"
+  resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
+  integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
+
+nice-try@^1.0.4:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
+  integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
+
+no-case@^2.2.0:
+  version "2.3.2"
+  resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac"
+  integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==
+  dependencies:
+    lower-case "^1.1.1"
+
+node-fetch@^2.3.0:
+  version "2.6.0"
+  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
+  integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
+
+node-pre-gyp@^0.12.0:
+  version "0.12.0"
+  resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149"
+  integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==
+  dependencies:
+    detect-libc "^1.0.2"
+    mkdirp "^0.5.1"
+    needle "^2.2.1"
+    nopt "^4.0.1"
+    npm-packlist "^1.1.6"
+    npmlog "^4.0.2"
+    rc "^1.2.7"
+    rimraf "^2.6.1"
+    semver "^5.3.0"
+    tar "^4"
+
+node-status-codes@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/node-status-codes/-/node-status-codes-1.0.0.tgz#5ae5541d024645d32a58fcddc9ceecea7ae3ac2f"
+  integrity sha1-WuVUHQJGRdMqWPzdyc7s6nrjrC8=
+
+nomnom@^1.8.1:
+  version "1.8.1"
+  resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.8.1.tgz#2151f722472ba79e50a76fc125bb8c8f2e4dc2a7"
+  integrity sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=
+  dependencies:
+    chalk "~0.4.0"
+    underscore "~1.6.0"
+
+nopt@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
+  integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=
+  dependencies:
+    abbrev "1"
+    osenv "^0.1.4"
+
+normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
+  version "2.5.0"
+  resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
+  integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
+  dependencies:
+    hosted-git-info "^2.1.4"
+    resolve "^1.10.0"
+    semver "2 || 3 || 4 || 5"
+    validate-npm-package-license "^3.0.1"
+
+normalize-path@^2.0.0, normalize-path@^2.0.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
+  integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=
+  dependencies:
+    remove-trailing-separator "^1.0.1"
+
+normalize-path@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
+  integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
+
+npm-bundled@^1.0.1:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd"
+  integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==
+
+npm-packlist@^1.1.6:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.1.tgz#19064cdf988da80ea3cee45533879d90192bbfbc"
+  integrity sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==
+  dependencies:
+    ignore-walk "^3.0.1"
+    npm-bundled "^1.0.1"
+
+npm-run-path@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
+  integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=
+  dependencies:
+    path-key "^2.0.0"
+
+npmlog@^4.0.2:
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
+  integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==
+  dependencies:
+    are-we-there-yet "~1.1.2"
+    console-control-strings "~1.1.0"
+    gauge "~2.7.3"
+    set-blocking "~2.0.0"
+
+nth-check@~1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c"
+  integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==
+  dependencies:
+    boolbase "~1.0.0"
+
+number-is-nan@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
+  integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
+
+oauth-sign@~0.9.0:
+  version "0.9.0"
+  resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
+  integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
+
+object-assign@^4, object-assign@^4.0.0, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+  integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
+
+object-component@0.0.3:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291"
+  integrity sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=
+
+object-copy@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
+  integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw=
+  dependencies:
+    copy-descriptor "^0.1.0"
+    define-property "^0.2.5"
+    kind-of "^3.0.3"
+
+object-keys@^1.0.11, object-keys@^1.0.12:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
+  integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
+
+object-visit@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
+  integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=
+  dependencies:
+    isobject "^3.0.0"
+
+object.assign@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da"
+  integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==
+  dependencies:
+    define-properties "^1.1.2"
+    function-bind "^1.1.1"
+    has-symbols "^1.0.0"
+    object-keys "^1.0.11"
+
+object.entries-ponyfill@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/object.entries-ponyfill/-/object.entries-ponyfill-1.0.1.tgz#29abdf77cbfbd26566dd1aa24e9d88f65433d256"
+  integrity sha1-Kavfd8v70mVm3RqiTp2I9lQz0lY=
+
+object.omit@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
+  integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=
+  dependencies:
+    for-own "^0.1.4"
+    is-extendable "^0.1.1"
+
+object.pick@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
+  integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=
+  dependencies:
+    isobject "^3.0.1"
+
+obuf@^1.0.0, obuf@^1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e"
+  integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==
+
+octokit-pagination-methods@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz#cf472edc9d551055f9ef73f6e42b4dbb4c80bea4"
+  integrity sha512-fZ4qZdQ2nxJvtcasX7Ghl+WlWS/d9IgnBIwFZXVNNZUmzpno91SX5bc5vuxiuKoCtK78XxGGNuSCrDC7xYB3OQ==
+
+on-finished@^2.3.0, on-finished@~2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
+  integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=
+  dependencies:
+    ee-first "1.1.1"
+
+on-headers@~1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
+  integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
+
+once@^1.3.0, once@^1.3.1, once@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+  integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
+  dependencies:
+    wrappy "1"
+
+one-time@0.0.4:
+  version "0.0.4"
+  resolved "https://registry.yarnpkg.com/one-time/-/one-time-0.0.4.tgz#f8cdf77884826fe4dff93e3a9cc37b1e4480742e"
+  integrity sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=
+
+onetime@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789"
+  integrity sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=
+
+onetime@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4"
+  integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=
+  dependencies:
+    mimic-fn "^1.0.0"
+
+onetime@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.0.tgz#fff0f3c91617fe62bb50189636e99ac8a6df7be5"
+  integrity sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==
+  dependencies:
+    mimic-fn "^2.1.0"
+
+opn@^3.0.2:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/opn/-/opn-3.0.3.tgz#b6d99e7399f78d65c3baaffef1fb288e9b85243a"
+  integrity sha1-ttmec5n3jWXDuq/+8fsojpuFJDo=
+  dependencies:
+    object-assign "^4.0.1"
+
+optimist@^0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
+  integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY=
+  dependencies:
+    minimist "~0.0.1"
+    wordwrap "~0.0.2"
+
+optionator@^0.8.3:
+  version "0.8.3"
+  resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495"
+  integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==
+  dependencies:
+    deep-is "~0.1.3"
+    fast-levenshtein "~2.0.6"
+    levn "~0.3.0"
+    prelude-ls "~1.1.2"
+    type-check "~0.3.2"
+    word-wrap "~1.2.3"
+
+ordered-read-streams@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz#7137e69b3298bb342247a1bbee3881c80e2fd78b"
+  integrity sha1-cTfmmzKYuzQiR6G77jiByA4v14s=
+  dependencies:
+    is-stream "^1.0.1"
+    readable-stream "^2.0.1"
+
+os-homedir@^1.0.0, os-homedir@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
+  integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
+
+os-name@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/os-name/-/os-name-3.1.0.tgz#dec19d966296e1cd62d701a5a66ee1ddeae70801"
+  integrity sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg==
+  dependencies:
+    macos-release "^2.2.0"
+    windows-release "^3.1.0"
+
+os-shim@^0.1.2:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917"
+  integrity sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=
+
+os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+  integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
+
+osenv@^0.1.0, osenv@^0.1.3, osenv@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
+  integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==
+  dependencies:
+    os-homedir "^1.0.0"
+    os-tmpdir "^1.0.0"
+
+p-cancelable@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa"
+  integrity sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==
+
+p-finally@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
+  integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
+
+p-limit@^2.0.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2"
+  integrity sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==
+  dependencies:
+    p-try "^2.0.0"
+
+p-locate@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
+  integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==
+  dependencies:
+    p-limit "^2.0.0"
+
+p-map@^1.1.1:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b"
+  integrity sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==
+
+p-timeout@^1.1.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386"
+  integrity sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=
+  dependencies:
+    p-finally "^1.0.0"
+
+p-try@^2.0.0, p-try@^2.1.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
+  integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
+
+package-json@^2.0.0:
+  version "2.4.0"
+  resolved "https://registry.yarnpkg.com/package-json/-/package-json-2.4.0.tgz#0d15bd67d1cbbddbb2ca222ff2edb86bcb31a8bb"
+  integrity sha1-DRW9Z9HLvduyyiIv8u24a8sxqLs=
+  dependencies:
+    got "^5.0.0"
+    registry-auth-token "^3.0.1"
+    registry-url "^3.0.3"
+    semver "^5.1.0"
+
+package-json@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed"
+  integrity sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=
+  dependencies:
+    got "^6.7.1"
+    registry-auth-token "^3.0.1"
+    registry-url "^3.0.3"
+    semver "^5.1.0"
+
+pako@~0.2.0:
+  version "0.2.9"
+  resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
+  integrity sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=
+
+param-case@2.1.x:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247"
+  integrity sha1-35T9jPZTHs915r75oIWPvHK+Ikc=
+  dependencies:
+    no-case "^2.2.0"
+
+parent-module@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
+  integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
+  dependencies:
+    callsites "^3.0.0"
+
+parse-glob@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
+  integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw=
+  dependencies:
+    glob-base "^0.3.0"
+    is-dotfile "^1.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.0"
+
+parse-json@^2.1.0, parse-json@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
+  integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=
+  dependencies:
+    error-ex "^1.2.0"
+
+parse-json@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
+  integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=
+  dependencies:
+    error-ex "^1.3.1"
+    json-parse-better-errors "^1.0.1"
+
+parse-passwd@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
+  integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=
+
+parse5@^3.0.1:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c"
+  integrity sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==
+  dependencies:
+    "@types/node" "*"
+
+parse5@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608"
+  integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==
+
+parseqs@0.0.5:
+  version "0.0.5"
+  resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d"
+  integrity sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=
+  dependencies:
+    better-assert "~1.0.0"
+
+parseuri@0.0.5:
+  version "0.0.5"
+  resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a"
+  integrity sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=
+  dependencies:
+    better-assert "~1.0.0"
+
+parseurl@~1.3.3:
+  version "1.3.3"
+  resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
+  integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
+
+pascalcase@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
+  integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=
+
+path-dirname@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
+  integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=
+
+path-exists@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
+  integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=
+  dependencies:
+    pinkie-promise "^2.0.0"
+
+path-exists@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
+  integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=
+
+path-is-absolute@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+  integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
+
+path-is-inside@^1.0.1, path-is-inside@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
+  integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=
+
+path-key@^2.0.0, path-key@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
+  integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
+
+path-parse@^1.0.6:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
+  integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
+
+path-to-regexp@0.1.7:
+  version "0.1.7"
+  resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
+  integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
+
+path-to-regexp@^1.0.1:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d"
+  integrity sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=
+  dependencies:
+    isarray "0.0.1"
+
+path-to-regexp@^1.7.0:
+  version "1.8.0"
+  resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a"
+  integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==
+  dependencies:
+    isarray "0.0.1"
+
+path-type@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
+  integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=
+  dependencies:
+    graceful-fs "^4.1.2"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+path-type@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
+  integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==
+  dependencies:
+    pify "^3.0.0"
+
+peek-stream@^1.1.0:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/peek-stream/-/peek-stream-1.1.3.tgz#3b35d84b7ccbbd262fff31dc10da56856ead6d67"
+  integrity sha512-FhJ+YbOSBb9/rIl2ZeE/QHEsWn7PqNYt8ARAY3kIgNGOk13g9FGyIY6JIl/xB/3TFRVoTv5as0l11weORrTekA==
+  dependencies:
+    buffer-from "^1.0.0"
+    duplexify "^3.5.0"
+    through2 "^2.0.3"
+
+pem@^1.8.3:
+  version "1.14.3"
+  resolved "https://registry.yarnpkg.com/pem/-/pem-1.14.3.tgz#347e5a5c194a5f7612b88083e45042fcc4fb4901"
+  integrity sha512-Q+AMVMD3fzeVvZs5PHeI+pVt0hgZY2fjhkliBW43qyONLgCXPVk1ryim43F9eupHlNGLJNT5T/NNrzhUdiC5Zg==
+  dependencies:
+    es6-promisify "^6.0.0"
+    md5 "^2.2.1"
+    os-tmpdir "^1.0.1"
+    which "^1.3.1"
+
+pend@~1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
+  integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA=
+
+performance-now@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
+  integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
+
+pify@^2.0.0, pify@^2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
+  integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
+
+pify@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
+  integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
+
+pify@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
+  integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==
+
+pinkie-promise@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
+  integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o=
+  dependencies:
+    pinkie "^2.0.0"
+
+pinkie@^2.0.0:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
+  integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
+
+plist@^2.0.1:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/plist/-/plist-2.1.0.tgz#57ccdb7a0821df21831217a3cad54e3e146a1025"
+  integrity sha1-V8zbeggh3yGDEhejytVOPhRqECU=
+  dependencies:
+    base64-js "1.2.0"
+    xmlbuilder "8.2.2"
+    xmldom "0.1.x"
+
+plylog@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/plylog/-/plylog-1.1.0.tgz#f6f354e2ae0b01f6db4ed111f4b3855da9c37417"
+  integrity sha512-/QnY5aSVaP54va6hruzNtAj02HpsLlAt7V5EndMrtq6ZUTZJKUja43rgiUtGXqm95yrSJjbZoPW0yQQQwLpoJA==
+  dependencies:
+    logform "^1.9.1"
+    winston "^3.0.0"
+    winston-transport "^4.2.0"
+
+polymer-analyzer@^3.0.0, polymer-analyzer@^3.1.3, polymer-analyzer@^3.2.2:
+  version "3.2.4"
+  resolved "https://registry.yarnpkg.com/polymer-analyzer/-/polymer-analyzer-3.2.4.tgz#7d76356620a2328e8bc9e30e47069f9729260ca1"
+  integrity sha512-JmxUhMajTuC18tLXbTtu2+aN2x9bTX+4MvCD4IZKJ0rtAL8jWi1iRLfogpHJB4Ig9Dc8EEEuEYipLuzPFl3vqA==
+  dependencies:
+    "@babel/generator" "^7.0.0-beta.42"
+    "@babel/traverse" "^7.0.0-beta.42"
+    "@babel/types" "^7.0.0-beta.42"
+    "@types/babel-generator" "^6.25.1"
+    "@types/babel-traverse" "^6.25.2"
+    "@types/babel-types" "^6.25.1"
+    "@types/babylon" "^6.16.2"
+    "@types/chai-subset" "^1.3.0"
+    "@types/chalk" "^0.4.30"
+    "@types/clone" "^0.1.30"
+    "@types/cssbeautify" "^0.3.1"
+    "@types/doctrine" "^0.0.1"
+    "@types/is-windows" "^0.2.0"
+    "@types/minimatch" "^3.0.1"
+    "@types/parse5" "^2.2.34"
+    "@types/path-is-inside" "^1.0.0"
+    "@types/resolve" "0.0.6"
+    "@types/whatwg-url" "^6.4.0"
+    babylon "^7.0.0-beta.42"
+    cancel-token "^0.1.1"
+    chalk "^1.1.3"
+    clone "^2.0.0"
+    cssbeautify "^0.3.1"
+    doctrine "^2.0.2"
+    dom5 "^3.0.0"
+    indent "0.0.2"
+    is-windows "^1.0.2"
+    jsonschema "^1.1.0"
+    minimatch "^3.0.4"
+    parse5 "^4.0.0"
+    path-is-inside "^1.0.2"
+    resolve "^1.5.0"
+    shady-css-parser "^0.1.0"
+    stable "^0.1.6"
+    strip-indent "^2.0.0"
+    vscode-uri "=1.0.6"
+    whatwg-url "^6.4.0"
+
+polymer-build@^3.1.0, polymer-build@^3.1.4:
+  version "3.1.4"
+  resolved "https://registry.yarnpkg.com/polymer-build/-/polymer-build-3.1.4.tgz#ab539f1a13d803518b13b73ffd09198431d98142"
+  integrity sha512-OhTOPG5Y/tK2HqGZ5XA/CVDh+TuOaDv7wTZWXDCg6hxeMgNKuljDMn2coyGU5NLM0pLbS+gwFAc2ZJ5cWHCHNg==
+  dependencies:
+    "@babel/core" "^7.0.0"
+    "@babel/plugin-external-helpers" "^7.0.0"
+    "@babel/plugin-proposal-async-generator-functions" "^7.0.0"
+    "@babel/plugin-proposal-object-rest-spread" "^7.0.0"
+    "@babel/plugin-syntax-async-generators" "^7.0.0"
+    "@babel/plugin-syntax-dynamic-import" "^7.0.0"
+    "@babel/plugin-syntax-import-meta" "^7.0.0"
+    "@babel/plugin-syntax-object-rest-spread" "^7.0.0"
+    "@babel/plugin-transform-arrow-functions" "^7.0.0"
+    "@babel/plugin-transform-async-to-generator" "^7.0.0"
+    "@babel/plugin-transform-block-scoped-functions" "^7.0.0"
+    "@babel/plugin-transform-block-scoping" "^7.0.0"
+    "@babel/plugin-transform-classes" "^7.0.0"
+    "@babel/plugin-transform-computed-properties" "^7.0.0"
+    "@babel/plugin-transform-destructuring" "^7.0.0"
+    "@babel/plugin-transform-duplicate-keys" "^7.0.0"
+    "@babel/plugin-transform-exponentiation-operator" "^7.0.0"
+    "@babel/plugin-transform-for-of" "^7.0.0"
+    "@babel/plugin-transform-function-name" "^7.0.0"
+    "@babel/plugin-transform-instanceof" "^7.0.0"
+    "@babel/plugin-transform-literals" "^7.0.0"
+    "@babel/plugin-transform-modules-amd" "^7.0.0"
+    "@babel/plugin-transform-object-super" "^7.0.0"
+    "@babel/plugin-transform-parameters" "^7.0.0"
+    "@babel/plugin-transform-regenerator" "^7.0.0"
+    "@babel/plugin-transform-shorthand-properties" "^7.0.0"
+    "@babel/plugin-transform-spread" "^7.0.0"
+    "@babel/plugin-transform-sticky-regex" "^7.0.0"
+    "@babel/plugin-transform-template-literals" "^7.0.0"
+    "@babel/plugin-transform-typeof-symbol" "^7.0.0"
+    "@babel/plugin-transform-unicode-regex" "^7.0.0"
+    "@babel/traverse" "^7.0.0"
+    "@polymer/esm-amd-loader" "^1.0.0"
+    "@types/babel-types" "^6.25.1"
+    "@types/babylon" "^6.16.2"
+    "@types/gulp-if" "0.0.33"
+    "@types/html-minifier" "^3.5.1"
+    "@types/is-windows" "^0.2.0"
+    "@types/mz" "0.0.31"
+    "@types/parse5" "^2.2.34"
+    "@types/resolve" "0.0.7"
+    "@types/uuid" "^3.4.3"
+    "@types/vinyl" "^2.0.0"
+    "@types/vinyl-fs" "^2.4.8"
+    babel-plugin-minify-guarded-expressions "^0.4.3"
+    babel-preset-minify "^0.5.0"
+    babylon "^7.0.0-beta.42"
+    css-slam "^2.1.2"
+    dom5 "^3.0.0"
+    gulp-if "^2.0.2"
+    html-minifier "^3.5.10"
+    matcher "^1.1.0"
+    multipipe "^1.0.2"
+    mz "^2.6.0"
+    parse5 "^4.0.0"
+    plylog "^1.0.0"
+    polymer-analyzer "^3.1.3"
+    polymer-bundler "^4.0.9"
+    polymer-project-config "^4.0.3"
+    regenerator-runtime "^0.11.1"
+    stream "0.0.2"
+    sw-precache "^5.1.1"
+    uuid "^3.2.1"
+    vinyl "^1.2.0"
+    vinyl-fs "^2.4.4"
+
+polymer-bundler@^4.0.9:
+  version "4.0.10"
+  resolved "https://registry.yarnpkg.com/polymer-bundler/-/polymer-bundler-4.0.10.tgz#abc8d33977652f031068d034c8104841e80d4cbb"
+  integrity sha512-nwlN3LQlQDqbZ2sUH3394C/dHZUDHq8tpdS5HARvPDb0Q9IXWD+znOR1cr7wSjF0EZN4LiUH5hWyUoV4QSjhpQ==
+  dependencies:
+    "@types/babel-generator" "^6.25.1"
+    "@types/babel-traverse" "^6.25.3"
+    babel-generator "^6.26.1"
+    babel-traverse "^6.26.0"
+    babel-types "^6.26.0"
+    clone "^2.1.0"
+    command-line-args "^5.0.2"
+    command-line-usage "^5.0.5"
+    dom5 "^3.0.0"
+    espree "^3.5.2"
+    magic-string "^0.22.4"
+    mkdirp "^0.5.1"
+    parse5 "^4.0.0"
+    polymer-analyzer "^3.2.2"
+    rollup "^1.3.0"
+    source-map "^0.5.6"
+    vscode-uri "=1.0.6"
+
+polymer-cli@^1.9.11:
+  version "1.9.11"
+  resolved "https://registry.yarnpkg.com/polymer-cli/-/polymer-cli-1.9.11.tgz#0b5310732b787e07b811af96627ef0fd1263f5da"
+  integrity sha512-tiURjHDCOUUtDVPuVYvrfFI9PXe4OOUmBbn6Sg5GJNQ2POtP7r7hv+I5yI8P9qsxmalHTa19chVtf5/t9IBXDg==
+  dependencies:
+    "@octokit/rest" "^16.2.0"
+    "@types/chalk" "^2.2.0"
+    "@types/del" "^3.0.0"
+    "@types/findup-sync" "^0.3.29"
+    "@types/globby" "^6.1.0"
+    "@types/inquirer" "0.0.32"
+    "@types/merge-stream" "^1.0.28"
+    "@types/mz" "^0.0.31"
+    "@types/request" "2.0.3"
+    "@types/resolve" "0.0.4"
+    "@types/rimraf" "^0.0.28"
+    "@types/semver" "^5.3.30"
+    "@types/temp" "^0.8.28"
+    "@types/update-notifier" "^1.0.0"
+    "@types/vinyl" "^2.0.0"
+    "@types/vinyl-fs" "0.0.28"
+    "@types/yeoman-generator" "^2.0.3"
+    bower "^1.8.8"
+    bower-json "^0.8.1"
+    bower-logger "^0.2.2"
+    chalk "^2.4.2"
+    chokidar "^1.7.0"
+    command-line-args "^5.0.2"
+    command-line-commands "^2.0.1"
+    command-line-usage "^5.0.5"
+    del "^3.0.0"
+    findup-sync "^0.4.2"
+    globby "^8.0.1"
+    gunzip-maybe "^1.3.1"
+    inquirer "^1.0.2"
+    merge-stream "^1.0.1"
+    mz "^2.6.0"
+    plylog "^1.0.0"
+    polymer-analyzer "^3.2.2"
+    polymer-build "^3.1.4"
+    polymer-bundler "^4.0.9"
+    polymer-linter "^3.0.0"
+    polymer-project-config "^4.0.3"
+    polyserve "^0.27.15"
+    request "^2.72.0"
+    rimraf "^2.6.1"
+    semver "^5.3.0"
+    tar-fs "^1.12.0"
+    temp "^0.8.3"
+    update-notifier "^1.0.0"
+    validate-element-name "^2.1.1"
+    vinyl "^1.1.1"
+    vinyl-fs "^2.4.3"
+    web-component-tester "^6.9.0"
+    yeoman-environment "^1.5.2"
+    yeoman-generator "^3.1.1"
+
+polymer-linter@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/polymer-linter/-/polymer-linter-3.0.1.tgz#8804e1705fa2a7c263467b8a22da11bb764ee26b"
+  integrity sha512-eDh2CeswZz4Rwf8gfYXpMN66pieq4qJvP9bH3m39LLGm81hRePo4N5OHoQzR5unen1PUdmtjDv0Iicz3dTYEZQ==
+  dependencies:
+    "@types/fast-levenshtein" "0.0.1"
+    "@types/parse5" "^2.2.34"
+    babel-traverse "^6.26.0"
+    babel-types "^6.26.0"
+    cancel-token "^0.1.1"
+    css-what "^2.1.0"
+    dom5 "^3.0.0"
+    fast-levenshtein "^2.0.6"
+    parse5 "^4.0.0"
+    polymer-analyzer "^3.0.0"
+    shady-css-parser "^0.1.0"
+    stable "^0.1.6"
+    strip-indent "^2.0.0"
+    validate-element-name "^2.1.1"
+
+polymer-project-config@^4.0.0, polymer-project-config@^4.0.3:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/polymer-project-config/-/polymer-project-config-4.0.3.tgz#ef0c1a676ce4809907986c8e910745660de8024f"
+  integrity sha512-Drr+Imq+znhBC8XSt9pMlmPixoGnIOmleV5SD6mto1zOGC5oCDbSNsQL2v89DWOk+9aSUO79vnWwOmEPDSvYfw==
+  dependencies:
+    "@types/parse5" "^2.2.34"
+    browser-capabilities "^1.0.0"
+    jsonschema "^1.1.1"
+    minimatch-all "^1.1.0"
+    plylog "^1.0.0"
+    winston "^3.0.0"
+
+polyserve@^0.27.13, polyserve@^0.27.15:
+  version "0.27.15"
+  resolved "https://registry.yarnpkg.com/polyserve/-/polyserve-0.27.15.tgz#261fa5a0873c8d95fd7068598f44c9dac20cf9c4"
+  integrity sha512-AaFgANt+tUUVgHLw+BnaVYcn649JiwL1ru0TOZUKj1gGGn/Bq2S16gxql+1muGpRaAsgFu13Zu7k5XkwatwwSg==
+  dependencies:
+    "@types/compression" "^0.0.33"
+    "@types/content-type" "^1.1.0"
+    "@types/escape-html" "0.0.20"
+    "@types/express" "^4.0.36"
+    "@types/mime" "^2.0.0"
+    "@types/mz" "0.0.29"
+    "@types/opn" "^3.0.28"
+    "@types/parse5" "^2.2.34"
+    "@types/pem" "^1.8.1"
+    "@types/resolve" "0.0.6"
+    "@types/serve-static" "^1.7.31"
+    "@types/spdy" "^3.4.1"
+    bower-config "^1.4.1"
+    browser-capabilities "^1.0.0"
+    command-line-args "^5.0.2"
+    command-line-usage "^5.0.5"
+    compression "^1.6.2"
+    content-type "^1.0.2"
+    cors "^2.8.4"
+    escape-html "^1.0.3"
+    express "^4.8.5"
+    find-port "^1.0.1"
+    http-proxy-middleware "^0.17.2"
+    lru-cache "^4.0.2"
+    mime "^2.3.1"
+    mz "^2.4.0"
+    opn "^3.0.2"
+    pem "^1.8.3"
+    polymer-build "^3.1.0"
+    polymer-project-config "^4.0.0"
+    requirejs "^2.3.4"
+    resolve "^1.5.0"
+    send "^0.16.2"
+    spdy "^3.3.3"
+
+posix-character-classes@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
+  integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
+
+prelude-ls@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
+  integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=
+
+prepend-http@^1.0.1:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
+  integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=
+
+preserve@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
+  integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=
+
+pretty-bytes@^4.0.2:
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-4.0.2.tgz#b2bf82e7350d65c6c33aa95aaa5a4f6327f61cd9"
+  integrity sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk=
+
+pretty-bytes@^5.1.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.2.0.tgz#96c92c6e95a0b35059253fb33c03e260d40f5a1f"
+  integrity sha512-ujANBhiUsl9AhREUDUEY1GPOharMGm8x8juS7qOHybcLi7XsKfrYQ88hSly1l2i0klXHTDYrlL8ihMCG55Dc3w==
+
+private@^0.1.6:
+  version "0.1.8"
+  resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"
+  integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==
+
+process-nextick-args@^2.0.0, process-nextick-args@~2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
+  integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
+
+progress@2.0.3, progress@^2.0.0:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
+  integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
+
+protobufjs@6.8.8:
+  version "6.8.8"
+  resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.8.8.tgz#c8b4f1282fd7a90e6f5b109ed11c84af82908e7c"
+  integrity sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==
+  dependencies:
+    "@protobufjs/aspromise" "^1.1.2"
+    "@protobufjs/base64" "^1.1.2"
+    "@protobufjs/codegen" "^2.0.4"
+    "@protobufjs/eventemitter" "^1.1.0"
+    "@protobufjs/fetch" "^1.1.0"
+    "@protobufjs/float" "^1.0.2"
+    "@protobufjs/inquire" "^1.1.0"
+    "@protobufjs/path" "^1.1.2"
+    "@protobufjs/pool" "^1.1.0"
+    "@protobufjs/utf8" "^1.1.0"
+    "@types/long" "^4.0.0"
+    "@types/node" "^10.1.0"
+    long "^4.0.0"
+
+proxy-addr@~2.0.5:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34"
+  integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==
+  dependencies:
+    forwarded "~0.1.2"
+    ipaddr.js "1.9.0"
+
+pseudomap@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
+  integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
+
+psl@^1.1.24:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/psl/-/psl-1.2.0.tgz#df12b5b1b3a30f51c329eacbdef98f3a6e136dc6"
+  integrity sha512-GEn74ZffufCmkDDLNcl3uuyF/aSD6exEyh1v/ZSdAomB82t6G9hzJVRx0jBmLDW+VfZqks3aScmMw9DszwUalA==
+
+pump@^1.0.0:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954"
+  integrity sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==
+  dependencies:
+    end-of-stream "^1.1.0"
+    once "^1.3.1"
+
+pump@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909"
+  integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==
+  dependencies:
+    end-of-stream "^1.1.0"
+    once "^1.3.1"
+
+pump@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
+  integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
+  dependencies:
+    end-of-stream "^1.1.0"
+    once "^1.3.1"
+
+pumpify@^1.3.3:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce"
+  integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==
+  dependencies:
+    duplexify "^3.6.0"
+    inherits "^2.0.3"
+    pump "^2.0.0"
+
+punycode@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
+  integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
+
+punycode@^2.1.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
+  integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
+
+q@^1.4.1, q@^1.5.1:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
+  integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
+
+qs@6.7.0:
+  version "6.7.0"
+  resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
+  integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
+
+qs@~6.5.2:
+  version "6.5.2"
+  resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
+  integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
+
+randomatic@^3.0.0:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed"
+  integrity sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==
+  dependencies:
+    is-number "^4.0.0"
+    kind-of "^6.0.0"
+    math-random "^1.0.1"
+
+range-parser@~1.2.0, range-parser@~1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
+  integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
+
+raw-body@2.4.0:
+  version "2.4.0"
+  resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332"
+  integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==
+  dependencies:
+    bytes "3.1.0"
+    http-errors "1.7.2"
+    iconv-lite "0.4.24"
+    unpipe "1.0.0"
+
+rc@^1.0.1, rc@^1.1.6, rc@^1.2.7:
+  version "1.2.8"
+  resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
+  integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
+  dependencies:
+    deep-extend "^0.6.0"
+    ini "~1.3.0"
+    minimist "^1.2.0"
+    strip-json-comments "~2.0.1"
+
+read-all-stream@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/read-all-stream/-/read-all-stream-3.1.0.tgz#35c3e177f2078ef789ee4bfafa4373074eaef4fa"
+  integrity sha1-NcPhd/IHjveJ7kv6+kNzB06u9Po=
+  dependencies:
+    pinkie-promise "^2.0.0"
+    readable-stream "^2.0.0"
+
+read-chunk@^3.0.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/read-chunk/-/read-chunk-3.2.0.tgz#2984afe78ca9bfbbdb74b19387bf9e86289c16ca"
+  integrity sha512-CEjy9LCzhmD7nUpJ1oVOE6s/hBkejlcJEgLQHVnQznOSilOPb+kpKktlLfFDK3/WP43+F80xkUTM2VOkYoSYvQ==
+  dependencies:
+    pify "^4.0.1"
+    with-open-file "^0.1.6"
+
+read-pkg-up@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
+  integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=
+  dependencies:
+    find-up "^1.0.0"
+    read-pkg "^1.0.0"
+
+read-pkg-up@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-4.0.0.tgz#1b221c6088ba7799601c808f91161c66e58f8978"
+  integrity sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==
+  dependencies:
+    find-up "^3.0.0"
+    read-pkg "^3.0.0"
+
+read-pkg@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
+  integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=
+  dependencies:
+    load-json-file "^1.0.0"
+    normalize-package-data "^2.3.2"
+    path-type "^1.0.0"
+
+read-pkg@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389"
+  integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=
+  dependencies:
+    load-json-file "^4.0.0"
+    normalize-package-data "^2.3.2"
+    path-type "^3.0.0"
+
+readable-stream@1.1.x:
+  version "1.1.14"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
+  integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk=
+  dependencies:
+    core-util-is "~1.0.0"
+    inherits "~2.0.1"
+    isarray "0.0.1"
+    string_decoder "~0.10.x"
+
+"readable-stream@2 || 3", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6:
+  version "2.3.6"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
+  integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
+  dependencies:
+    core-util-is "~1.0.0"
+    inherits "~2.0.3"
+    isarray "~1.0.0"
+    process-nextick-args "~2.0.0"
+    safe-buffer "~5.1.1"
+    string_decoder "~1.1.1"
+    util-deprecate "~1.0.1"
+
+"readable-stream@>=1.0.33-1 <1.1.0-0":
+  version "1.0.34"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c"
+  integrity sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=
+  dependencies:
+    core-util-is "~1.0.0"
+    inherits "~2.0.1"
+    isarray "0.0.1"
+    string_decoder "~0.10.x"
+
+readable-stream@^2.2.2, readable-stream@^2.2.9:
+  version "2.3.7"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
+  integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
+  dependencies:
+    core-util-is "~1.0.0"
+    inherits "~2.0.3"
+    isarray "~1.0.0"
+    process-nextick-args "~2.0.0"
+    safe-buffer "~5.1.1"
+    string_decoder "~1.1.1"
+    util-deprecate "~1.0.1"
+
+readable-stream@^3.0.1, readable-stream@^3.1.1, readable-stream@^3.4.0:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.4.0.tgz#a51c26754658e0a3c21dbf59163bd45ba6f447fc"
+  integrity sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==
+  dependencies:
+    inherits "^2.0.3"
+    string_decoder "^1.1.1"
+    util-deprecate "^1.0.1"
+
+readdirp@^2.0.0:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525"
+  integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==
+  dependencies:
+    graceful-fs "^4.1.11"
+    micromatch "^3.1.10"
+    readable-stream "^2.0.2"
+
+rechoir@^0.6.2:
+  version "0.6.2"
+  resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
+  integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=
+  dependencies:
+    resolve "^1.1.6"
+
+redent@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"
+  integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=
+  dependencies:
+    indent-string "^2.1.0"
+    strip-indent "^1.0.1"
+
+reduce-flatten@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-1.0.1.tgz#258c78efd153ddf93cb561237f61184f3696e327"
+  integrity sha1-JYx479FT3fk8tWEjf2EYTzaW4yc=
+
+regenerate-unicode-properties@^8.0.2:
+  version "8.1.0"
+  resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e"
+  integrity sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==
+  dependencies:
+    regenerate "^1.4.0"
+
+regenerate@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
+  integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==
+
+regenerator-runtime@^0.11.0, regenerator-runtime@^0.11.1:
+  version "0.11.1"
+  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
+  integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
+
+regenerator-transform@^0.14.0:
+  version "0.14.0"
+  resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.0.tgz#2ca9aaf7a2c239dd32e4761218425b8c7a86ecaf"
+  integrity sha512-rtOelq4Cawlbmq9xuMR5gdFmv7ku/sFoB7sRiywx7aq53bc52b4j6zvH7Te1Vt/X2YveDKnCGUbioieU7FEL3w==
+  dependencies:
+    private "^0.1.6"
+
+regex-cache@^0.4.2:
+  version "0.4.4"
+  resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd"
+  integrity sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==
+  dependencies:
+    is-equal-shallow "^0.1.3"
+
+regex-not@^1.0.0, regex-not@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
+  integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==
+  dependencies:
+    extend-shallow "^3.0.2"
+    safe-regex "^1.1.0"
+
+regexpp@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f"
+  integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==
+
+regexpu-core@^4.5.4:
+  version "4.5.4"
+  resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.5.4.tgz#080d9d02289aa87fe1667a4f5136bc98a6aebaae"
+  integrity sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ==
+  dependencies:
+    regenerate "^1.4.0"
+    regenerate-unicode-properties "^8.0.2"
+    regjsgen "^0.5.0"
+    regjsparser "^0.6.0"
+    unicode-match-property-ecmascript "^1.0.4"
+    unicode-match-property-value-ecmascript "^1.1.0"
+
+regextras@^0.7.0:
+  version "0.7.0"
+  resolved "https://registry.yarnpkg.com/regextras/-/regextras-0.7.0.tgz#2298bef8cfb92b1b7e3b9b12aa8f69547b7d71e4"
+  integrity sha512-ds+fL+Vhl918gbAUb0k2gVKbTZLsg84Re3DI6p85Et0U0tYME3hyW4nMK8Px4dtDaBA2qNjvG5uWyW7eK5gfmw==
+
+registry-auth-token@^3.0.1:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.4.0.tgz#d7446815433f5d5ed6431cd5dca21048f66b397e"
+  integrity sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==
+  dependencies:
+    rc "^1.1.6"
+    safe-buffer "^5.0.1"
+
+registry-url@^3.0.3:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942"
+  integrity sha1-PU74cPc93h138M+aOBQyRE4XSUI=
+  dependencies:
+    rc "^1.0.1"
+
+regjsgen@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.0.tgz#a7634dc08f89209c2049adda3525711fb97265dd"
+  integrity sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA==
+
+regjsparser@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.0.tgz#f1e6ae8b7da2bae96c99399b868cd6c933a2ba9c"
+  integrity sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==
+  dependencies:
+    jsesc "~0.5.0"
+
+relateurl@0.2.x:
+  version "0.2.7"
+  resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
+  integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=
+
+remove-trailing-separator@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
+  integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8=
+
+repeat-element@^1.1.2:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce"
+  integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==
+
+repeat-string@^1.5.2, repeat-string@^1.6.1:
+  version "1.6.1"
+  resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
+  integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
+
+repeating@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
+  integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=
+  dependencies:
+    is-finite "^1.0.0"
+
+replace-ext@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924"
+  integrity sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=
+
+replace-ext@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb"
+  integrity sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=
+
+request@2.88.0, request@^2.72.0, request@^2.85.0:
+  version "2.88.0"
+  resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
+  integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
+  dependencies:
+    aws-sign2 "~0.7.0"
+    aws4 "^1.8.0"
+    caseless "~0.12.0"
+    combined-stream "~1.0.6"
+    extend "~3.0.2"
+    forever-agent "~0.6.1"
+    form-data "~2.3.2"
+    har-validator "~5.1.0"
+    http-signature "~1.2.0"
+    is-typedarray "~1.0.0"
+    isstream "~0.1.2"
+    json-stringify-safe "~5.0.1"
+    mime-types "~2.1.19"
+    oauth-sign "~0.9.0"
+    performance-now "^2.1.0"
+    qs "~6.5.2"
+    safe-buffer "^5.1.2"
+    tough-cookie "~2.4.3"
+    tunnel-agent "^0.6.0"
+    uuid "^3.3.2"
+
+requirejs@^2.3.4:
+  version "2.3.6"
+  resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.3.6.tgz#e5093d9601c2829251258c0b9445d4d19fa9e7c9"
+  integrity sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg==
+
+requires-port@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
+  integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
+
+resolve-dir@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e"
+  integrity sha1-shklmlYC+sXFxJatiUpujMQwJh4=
+  dependencies:
+    expand-tilde "^1.2.2"
+    global-modules "^0.2.3"
+
+resolve-dir@^1.0.0, resolve-dir@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43"
+  integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=
+  dependencies:
+    expand-tilde "^2.0.0"
+    global-modules "^1.0.0"
+
+resolve-from@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
+  integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
+
+resolve-url@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
+  integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
+
+resolve@^1.1.6, resolve@^1.10.0, resolve@^1.3.2:
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.1.tgz#ea10d8110376982fef578df8fc30b9ac30a07a3e"
+  integrity sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==
+  dependencies:
+    path-parse "^1.0.6"
+
+resolve@^1.5.0:
+  version "1.14.2"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.14.2.tgz#dbf31d0fa98b1f29aa5169783b9c290cb865fea2"
+  integrity sha512-EjlOBLBO1kxsUxsKjLt7TAECyKW6fOh1VRkykQkKGzcBbjjPIxBqGh0jf7GJ3k/f5mxMqW3htMD3WdTUVtW8HQ==
+  dependencies:
+    path-parse "^1.0.6"
+
+restore-cursor@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541"
+  integrity sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=
+  dependencies:
+    exit-hook "^1.0.0"
+    onetime "^1.0.0"
+
+restore-cursor@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
+  integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368=
+  dependencies:
+    onetime "^2.0.0"
+    signal-exit "^3.0.2"
+
+restore-cursor@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
+  integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==
+  dependencies:
+    onetime "^5.1.0"
+    signal-exit "^3.0.2"
+
+ret@~0.1.10:
+  version "0.1.15"
+  resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
+  integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
+
+rimraf@2.6.3, rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@~2.6.2:
+  version "2.6.3"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
+  integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
+  dependencies:
+    glob "^7.1.3"
+
+rimraf@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.0.tgz#614176d4b3010b75e5c390eb0ee96f6dc0cebb9b"
+  integrity sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==
+  dependencies:
+    glob "^7.1.3"
+
+rimraf@~2.2.6:
+  version "2.2.8"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582"
+  integrity sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=
+
+rollup@^1.3.0:
+  version "1.16.7"
+  resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.16.7.tgz#4b539ca22465df39f6c963d2001d95f6527e97e1"
+  integrity sha512-P3GVcbVSLLjHWFLKGerYRe3Q/yggRXmTZFx/4WZf4wzGwO6hAg5jyMAFMQKc0dts8rFID4BQngfoz6yQbI7iMQ==
+  dependencies:
+    "@types/estree" "0.0.39"
+    "@types/node" "^12.0.10"
+    acorn "^6.1.1"
+
+run-async@^2.0.0, run-async@^2.2.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0"
+  integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA=
+  dependencies:
+    is-promise "^2.1.0"
+
+rx@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782"
+  integrity sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=
+
+rxjs@^6.4.0:
+  version "6.5.2"
+  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.2.tgz#2e35ce815cd46d84d02a209fb4e5921e051dbec7"
+  integrity sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==
+  dependencies:
+    tslib "^1.9.0"
+
+rxjs@^6.5.3:
+  version "6.5.4"
+  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c"
+  integrity sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==
+  dependencies:
+    tslib "^1.9.0"
+
+safe-buffer@5.1.2, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
+  integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
+
+safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.2.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
+  integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
+
+safe-regex@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
+  integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4=
+  dependencies:
+    ret "~0.1.10"
+
+"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
+  integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+
+samsam@1.x, samsam@^1.1.3:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.3.0.tgz#8d1d9350e25622da30de3e44ba692b5221ab7c50"
+  integrity sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==
+
+sauce-connect-launcher@^1.0.0:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/sauce-connect-launcher/-/sauce-connect-launcher-1.3.1.tgz#31137f57b0f7176e1c0525b7fb09c6da746647cf"
+  integrity sha512-vIf9qDol3q2FlYzrKt0dr3kvec6LSjX2WS+/mVnAJIhqh1evSkPKCR2AzcJrnSmx9Xt9PtV0tLY7jYh0wsQi8A==
+  dependencies:
+    adm-zip "~0.4.3"
+    async "^2.1.2"
+    https-proxy-agent "^3.0.0"
+    lodash "^4.16.6"
+    rimraf "^2.5.4"
+
+sax@^1.2.4:
+  version "1.2.4"
+  resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
+  integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
+
+scoped-regex@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/scoped-regex/-/scoped-regex-1.0.0.tgz#a346bb1acd4207ae70bd7c0c7ca9e566b6baddb8"
+  integrity sha1-o0a7Gs1CB65wvXwMfKnlZra63bg=
+
+select-hose@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
+  integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=
+
+selenium-standalone@^6.7.0:
+  version "6.17.0"
+  resolved "https://registry.yarnpkg.com/selenium-standalone/-/selenium-standalone-6.17.0.tgz#0f24b691836205ee9bc3d7a6f207ebcb28170cd9"
+  integrity sha512-5PSnDHwMiq+OCiAGlhwQ8BM9xuwFfvBOZ7Tfbw+ifkTnOy0PWbZmI1B9gPGuyGHpbQ/3J3CzIK7BYwrQ7EjtWQ==
+  dependencies:
+    async "^2.6.2"
+    commander "^2.19.0"
+    cross-spawn "^6.0.5"
+    debug "^4.1.1"
+    lodash "^4.17.11"
+    minimist "^1.2.0"
+    mkdirp "^0.5.1"
+    progress "2.0.3"
+    request "2.88.0"
+    tar-stream "2.0.0"
+    urijs "^1.19.1"
+    which "^1.3.1"
+    yauzl "^2.10.0"
+
+semver-diff@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36"
+  integrity sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=
+  dependencies:
+    semver "^5.0.3"
+
+"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.6.0:
+  version "5.7.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b"
+  integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==
+
+semver@5.6.0, semver@^5.0.3, semver@^5.1.0, semver@^5.5.0:
+  version "5.6.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
+  integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==
+
+semver@^6.1.2, semver@^6.3.0:
+  version "6.3.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
+  integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
+
+send@0.17.1:
+  version "0.17.1"
+  resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
+  integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==
+  dependencies:
+    debug "2.6.9"
+    depd "~1.1.2"
+    destroy "~1.0.4"
+    encodeurl "~1.0.2"
+    escape-html "~1.0.3"
+    etag "~1.8.1"
+    fresh "0.5.2"
+    http-errors "~1.7.2"
+    mime "1.6.0"
+    ms "2.1.1"
+    on-finished "~2.3.0"
+    range-parser "~1.2.1"
+    statuses "~1.5.0"
+
+send@^0.16.1, send@^0.16.2:
+  version "0.16.2"
+  resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1"
+  integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==
+  dependencies:
+    debug "2.6.9"
+    depd "~1.1.2"
+    destroy "~1.0.4"
+    encodeurl "~1.0.2"
+    escape-html "~1.0.3"
+    etag "~1.8.1"
+    fresh "0.5.2"
+    http-errors "~1.6.2"
+    mime "1.4.1"
+    ms "2.0.0"
+    on-finished "~2.3.0"
+    range-parser "~1.2.0"
+    statuses "~1.4.0"
+
+serve-static@1.14.1:
+  version "1.14.1"
+  resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9"
+  integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==
+  dependencies:
+    encodeurl "~1.0.2"
+    escape-html "~1.0.3"
+    parseurl "~1.3.3"
+    send "0.17.1"
+
+server-destroy@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/server-destroy/-/server-destroy-1.0.1.tgz#f13bf928e42b9c3e79383e61cc3998b5d14e6cdd"
+  integrity sha1-8Tv5KOQrnD55OD5hzDmYtdFObN0=
+
+serviceworker-cache-polyfill@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/serviceworker-cache-polyfill/-/serviceworker-cache-polyfill-4.0.0.tgz#de19ee73bef21ab3c0740a37b33db62464babdeb"
+  integrity sha1-3hnuc77yGrPAdAo3sz22JGS6ves=
+
+set-blocking@~2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
+  integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
+
+set-value@^2.0.0, set-value@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
+  integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==
+  dependencies:
+    extend-shallow "^2.0.1"
+    is-extendable "^0.1.1"
+    is-plain-object "^2.0.3"
+    split-string "^3.0.1"
+
+setprototypeof@1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
+  integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==
+
+setprototypeof@1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
+  integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==
+
+shady-css-parser@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/shady-css-parser/-/shady-css-parser-0.1.0.tgz#534dc79c8ca5884c5ed92a4e5a13d6d863bca428"
+  integrity sha512-irfJUUkEuDlNHKZNAp2r7zOyMlmbfVJ+kWSfjlCYYUx/7dJnANLCyTzQZsuxy5NJkvtNwSxY5Gj8MOlqXUQPyA==
+
+shebang-command@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
+  integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=
+  dependencies:
+    shebang-regex "^1.0.0"
+
+shebang-regex@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
+  integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
+
+shelljs@^0.8.0:
+  version "0.8.3"
+  resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.3.tgz#a7f3319520ebf09ee81275b2368adb286659b097"
+  integrity sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==
+  dependencies:
+    glob "^7.0.0"
+    interpret "^1.0.0"
+    rechoir "^0.6.2"
+
+signal-exit@^3.0.0, signal-exit@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
+  integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
+
+simple-swizzle@^0.2.2:
+  version "0.2.2"
+  resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
+  integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=
+  dependencies:
+    is-arrayish "^0.3.1"
+
+sinon-chai@^2.10.0:
+  version "2.14.0"
+  resolved "https://registry.yarnpkg.com/sinon-chai/-/sinon-chai-2.14.0.tgz#da7dd4cc83cd6a260b67cca0f7a9fdae26a1205d"
+  integrity sha512-9stIF1utB0ywNHNT7RgiXbdmen8QDCRsrTjw+G9TgKt1Yexjiv8TOWZ6WHsTPz57Yky3DIswZvEqX8fpuHNDtQ==
+
+sinon@^2.3.5:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/sinon/-/sinon-2.4.1.tgz#021fd64b54cb77d9d2fb0d43cdedfae7629c3a36"
+  integrity sha512-vFTrO9Wt0ECffDYIPSP/E5bBugt0UjcBQOfQUMh66xzkyPEnhl/vM2LRZi2ajuTdkH07sA6DzrM6KvdvGIH8xw==
+  dependencies:
+    diff "^3.1.0"
+    formatio "1.2.0"
+    lolex "^1.6.0"
+    native-promise-only "^0.8.1"
+    path-to-regexp "^1.7.0"
+    samsam "^1.1.3"
+    text-encoding "0.6.4"
+    type-detect "^4.0.0"
+
+slash@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
+  integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=
+
+slice-ansi@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636"
+  integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==
+  dependencies:
+    ansi-styles "^3.2.0"
+    astral-regex "^1.0.0"
+    is-fullwidth-code-point "^2.0.0"
+
+slide@^1.1.5:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707"
+  integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=
+
+snapdragon-node@^2.0.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
+  integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==
+  dependencies:
+    define-property "^1.0.0"
+    isobject "^3.0.0"
+    snapdragon-util "^3.0.1"
+
+snapdragon-util@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2"
+  integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==
+  dependencies:
+    kind-of "^3.2.0"
+
+snapdragon@^0.8.1:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d"
+  integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==
+  dependencies:
+    base "^0.11.1"
+    debug "^2.2.0"
+    define-property "^0.2.5"
+    extend-shallow "^2.0.1"
+    map-cache "^0.2.2"
+    source-map "^0.5.6"
+    source-map-resolve "^0.5.0"
+    use "^3.1.0"
+
+socket.io-adapter@~1.1.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz#ab3f0d6f66b8fc7fca3959ab5991f82221789be9"
+  integrity sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==
+
+socket.io-client@2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.3.0.tgz#14d5ba2e00b9bcd145ae443ab96b3f86cbcc1bb4"
+  integrity sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==
+  dependencies:
+    backo2 "1.0.2"
+    base64-arraybuffer "0.1.5"
+    component-bind "1.0.0"
+    component-emitter "1.2.1"
+    debug "~4.1.0"
+    engine.io-client "~3.4.0"
+    has-binary2 "~1.0.2"
+    has-cors "1.1.0"
+    indexof "0.0.1"
+    object-component "0.0.3"
+    parseqs "0.0.5"
+    parseuri "0.0.5"
+    socket.io-parser "~3.3.0"
+    to-array "0.1.4"
+
+socket.io-parser@~3.3.0:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.0.tgz#2b52a96a509fdf31440ba40fed6094c7d4f1262f"
+  integrity sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==
+  dependencies:
+    component-emitter "1.2.1"
+    debug "~3.1.0"
+    isarray "2.0.1"
+
+socket.io-parser@~3.4.0:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.4.0.tgz#370bb4a151df2f77ce3345ff55a7072cc6e9565a"
+  integrity sha512-/G/VOI+3DBp0+DJKW4KesGnQkQPFmUCbA/oO2QGT6CWxU7hLGWqU3tyuzeSK/dqcyeHsQg1vTe9jiZI8GU9SCQ==
+  dependencies:
+    component-emitter "1.2.1"
+    debug "~4.1.0"
+    isarray "2.0.1"
+
+socket.io@^2.0.3:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.3.0.tgz#cd762ed6a4faeca59bc1f3e243c0969311eb73fb"
+  integrity sha512-2A892lrj0GcgR/9Qk81EaY2gYhCBxurV0PfmmESO6p27QPrUK1J3zdns+5QPqvUYK2q657nSj0guoIil9+7eFg==
+  dependencies:
+    debug "~4.1.0"
+    engine.io "~3.4.0"
+    has-binary2 "~1.0.2"
+    socket.io-adapter "~1.1.0"
+    socket.io-client "2.3.0"
+    socket.io-parser "~3.4.0"
+
+sort-keys-length@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/sort-keys-length/-/sort-keys-length-1.0.1.tgz#9cb6f4f4e9e48155a6aa0671edd336ff1479a188"
+  integrity sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=
+  dependencies:
+    sort-keys "^1.0.0"
+
+sort-keys@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad"
+  integrity sha1-RBttTTRnmPG05J6JIK37oOVD+a0=
+  dependencies:
+    is-plain-obj "^1.0.0"
+
+source-list-map@~0.1.7:
+  version "0.1.8"
+  resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.8.tgz#c550b2ab5427f6b3f21f5afead88c4f5587b2106"
+  integrity sha1-xVCyq1Qn9rPyH1r+rYjE9Vh7IQY=
+
+source-map-resolve@^0.5.0:
+  version "0.5.3"
+  resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a"
+  integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==
+  dependencies:
+    atob "^2.1.2"
+    decode-uri-component "^0.2.0"
+    resolve-url "^0.2.1"
+    source-map-url "^0.4.0"
+    urix "^0.1.0"
+
+source-map-support@0.5.9:
+  version "0.5.9"
+  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.9.tgz#41bc953b2534267ea2d605bccfa7bfa3111ced5f"
+  integrity sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==
+  dependencies:
+    buffer-from "^1.0.0"
+    source-map "^0.6.0"
+
+source-map-support@^0.4.2:
+  version "0.4.18"
+  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f"
+  integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==
+  dependencies:
+    source-map "^0.5.6"
+
+source-map-url@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
+  integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=
+
+source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7:
+  version "0.5.7"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
+  integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
+
+source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
+  integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+
+source-map@~0.4.1:
+  version "0.4.4"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
+  integrity sha1-66T12pwNyZneaAMti092FzZSA2s=
+  dependencies:
+    amdefine ">=0.0.4"
+
+spawn-sync@^1.0.15:
+  version "1.0.15"
+  resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476"
+  integrity sha1-sAeZVX63+wyDdsKdROih6mfldHY=
+  dependencies:
+    concat-stream "^1.4.7"
+    os-shim "^0.1.2"
+
+spdx-correct@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4"
+  integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==
+  dependencies:
+    spdx-expression-parse "^3.0.0"
+    spdx-license-ids "^3.0.0"
+
+spdx-exceptions@^2.1.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977"
+  integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==
+
+spdx-expression-parse@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0"
+  integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==
+  dependencies:
+    spdx-exceptions "^2.1.0"
+    spdx-license-ids "^3.0.0"
+
+spdx-license-ids@^3.0.0:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz#75ecd1a88de8c184ef015eafb51b5b48bfd11bb1"
+  integrity sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==
+
+spdy-transport@^2.0.18:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-2.1.1.tgz#c54815d73858aadd06ce63001e7d25fa6441623b"
+  integrity sha512-q7D8c148escoB3Z7ySCASadkegMmUZW8Wb/Q1u0/XBgDKMO880rLQDj8Twiew/tYi7ghemKUi/whSYOwE17f5Q==
+  dependencies:
+    debug "^2.6.8"
+    detect-node "^2.0.3"
+    hpack.js "^2.1.6"
+    obuf "^1.1.1"
+    readable-stream "^2.2.9"
+    safe-buffer "^5.0.1"
+    wbuf "^1.7.2"
+
+spdy@^3.3.3:
+  version "3.4.7"
+  resolved "https://registry.yarnpkg.com/spdy/-/spdy-3.4.7.tgz#42ff41ece5cc0f99a3a6c28aabb73f5c3b03acbc"
+  integrity sha1-Qv9B7OXMD5mjpsKKq7c/XDsDrLw=
+  dependencies:
+    debug "^2.6.8"
+    handle-thing "^1.2.5"
+    http-deceiver "^1.2.7"
+    safe-buffer "^5.0.1"
+    select-hose "^2.0.0"
+    spdy-transport "^2.0.18"
+
+split-string@^3.0.1, split-string@^3.0.2:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
+  integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==
+  dependencies:
+    extend-shallow "^3.0.0"
+
+sprintf-js@~1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+  integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
+
+sshpk@^1.7.0:
+  version "1.16.1"
+  resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
+  integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==
+  dependencies:
+    asn1 "~0.2.3"
+    assert-plus "^1.0.0"
+    bcrypt-pbkdf "^1.0.0"
+    dashdash "^1.12.0"
+    ecc-jsbn "~0.1.1"
+    getpass "^0.1.1"
+    jsbn "~0.1.0"
+    safer-buffer "^2.0.2"
+    tweetnacl "~0.14.0"
+
+stable@^0.1.6:
+  version "0.1.8"
+  resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
+  integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==
+
+stack-trace@0.0.x:
+  version "0.0.10"
+  resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
+  integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=
+
+stacky@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/stacky/-/stacky-1.3.1.tgz#3f117e5187b9a73d23f876d69f05c85b11804a12"
+  integrity sha1-PxF+UYe5pz0j+HbWnwXIWxGAShI=
+  dependencies:
+    chalk "^1.1.1"
+    lodash "^3.0.0"
+
+static-extend@^0.1.1:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
+  integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=
+  dependencies:
+    define-property "^0.2.5"
+    object-copy "^0.1.0"
+
+"statuses@>= 1.4.0 < 2", statuses@~1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
+  integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==
+
+"statuses@>= 1.5.0 < 2", statuses@~1.5.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
+  integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
+
+stream-shift@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952"
+  integrity sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=
+
+stream@0.0.2:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/stream/-/stream-0.0.2.tgz#7f5363f057f6592c5595f00bc80a27f5cec1f0ef"
+  integrity sha1-f1Nj8Ff2WSxVlfALyAon9c7B8O8=
+  dependencies:
+    emitter-component "^1.1.1"
+
+streamsearch@0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a"
+  integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=
+
+string-template@~0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add"
+  integrity sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=
+
+string-width@^1.0.1, "string-width@^1.0.2 || 2":
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
+  integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=
+  dependencies:
+    code-point-at "^1.0.0"
+    is-fullwidth-code-point "^1.0.0"
+    strip-ansi "^3.0.0"
+
+string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
+  integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
+  dependencies:
+    is-fullwidth-code-point "^2.0.0"
+    strip-ansi "^4.0.0"
+
+string-width@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
+  integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==
+  dependencies:
+    emoji-regex "^7.0.1"
+    is-fullwidth-code-point "^2.0.0"
+    strip-ansi "^5.1.0"
+
+string-width@^4.1.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5"
+  integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==
+  dependencies:
+    emoji-regex "^8.0.0"
+    is-fullwidth-code-point "^3.0.0"
+    strip-ansi "^6.0.0"
+
+string_decoder@^1.1.1:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
+  integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
+  dependencies:
+    safe-buffer "~5.2.0"
+
+string_decoder@~0.10.x:
+  version "0.10.31"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
+  integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=
+
+string_decoder@~1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
+  integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
+  dependencies:
+    safe-buffer "~5.1.0"
+
+strip-ansi@^3.0.0, strip-ansi@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+  integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
+  dependencies:
+    ansi-regex "^2.0.0"
+
+strip-ansi@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
+  integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
+  dependencies:
+    ansi-regex "^3.0.0"
+
+strip-ansi@^5.1.0, strip-ansi@^5.2.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
+  integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
+  dependencies:
+    ansi-regex "^4.1.0"
+
+strip-ansi@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532"
+  integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==
+  dependencies:
+    ansi-regex "^5.0.0"
+
+strip-ansi@~0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.1.1.tgz#39e8a98d044d150660abe4a6808acf70bb7bc991"
+  integrity sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=
+
+strip-bom-stream@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz#e7144398577d51a6bed0fa1994fa05f43fd988ee"
+  integrity sha1-5xRDmFd9Uaa+0PoZlPoF9D/ZiO4=
+  dependencies:
+    first-chunk-stream "^1.0.0"
+    strip-bom "^2.0.0"
+
+strip-bom-stream@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz#f87db5ef2613f6968aa545abfe1ec728b6a829ca"
+  integrity sha1-+H217yYT9paKpUWr/h7HKLaoKco=
+  dependencies:
+    first-chunk-stream "^2.0.0"
+    strip-bom "^2.0.0"
+
+strip-bom@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
+  integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=
+  dependencies:
+    is-utf8 "^0.2.0"
+
+strip-bom@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
+  integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=
+
+strip-eof@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
+  integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
+
+strip-indent@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2"
+  integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=
+  dependencies:
+    get-stdin "^4.0.1"
+
+strip-indent@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68"
+  integrity sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=
+
+strip-json-comments@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7"
+  integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==
+
+strip-json-comments@~2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+  integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
+
+supports-color@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
+  integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
+
+supports-color@^5.3.0:
+  version "5.5.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
+  integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
+  dependencies:
+    has-flag "^3.0.0"
+
+sw-precache@^5.1.1:
+  version "5.2.1"
+  resolved "https://registry.yarnpkg.com/sw-precache/-/sw-precache-5.2.1.tgz#06134f319eec68f3b9583ce9a7036b1c119f7179"
+  integrity sha512-8FAy+BP/FXE+ILfiVTt+GQJ6UEf4CVHD9OfhzH0JX+3zoy2uFk7Vn9EfXASOtVmmIVbL3jE/W8Z66VgPSZcMhw==
+  dependencies:
+    dom-urls "^1.1.0"
+    es6-promise "^4.0.5"
+    glob "^7.1.1"
+    lodash.defaults "^4.2.0"
+    lodash.template "^4.4.0"
+    meow "^3.7.0"
+    mkdirp "^0.5.1"
+    pretty-bytes "^4.0.2"
+    sw-toolbox "^3.4.0"
+    update-notifier "^2.3.0"
+
+sw-toolbox@^3.4.0:
+  version "3.6.0"
+  resolved "https://registry.yarnpkg.com/sw-toolbox/-/sw-toolbox-3.6.0.tgz#26df1d1c70348658e4dea2884319149b7b3183b5"
+  integrity sha1-Jt8dHHA0hljk3qKIQxkUm3sxg7U=
+  dependencies:
+    path-to-regexp "^1.0.1"
+    serviceworker-cache-polyfill "^4.0.0"
+
+table-layout@^0.4.3:
+  version "0.4.5"
+  resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-0.4.5.tgz#d906de6a25fa09c0c90d1d08ecd833ecedcb7378"
+  integrity sha512-zTvf0mcggrGeTe/2jJ6ECkJHAQPIYEwDoqsiqBjI24mvRmQbInK5jq33fyypaCBxX08hMkfmdOqj6haT33EqWw==
+  dependencies:
+    array-back "^2.0.0"
+    deep-extend "~0.6.0"
+    lodash.padend "^4.6.1"
+    typical "^2.6.1"
+    wordwrapjs "^3.0.0"
+
+table@^5.2.3:
+  version "5.4.6"
+  resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e"
+  integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==
+  dependencies:
+    ajv "^6.10.2"
+    lodash "^4.17.14"
+    slice-ansi "^2.1.0"
+    string-width "^3.0.0"
+
+tar-fs@^1.12.0:
+  version "1.16.3"
+  resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-1.16.3.tgz#966a628841da2c4010406a82167cbd5e0c72d509"
+  integrity sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==
+  dependencies:
+    chownr "^1.0.1"
+    mkdirp "^0.5.1"
+    pump "^1.0.0"
+    tar-stream "^1.1.2"
+
+tar-stream@2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.0.0.tgz#8829bbf83067bc0288a9089db49c56be395b6aea"
+  integrity sha512-n2vtsWshZOVr/SY4KtslPoUlyNh06I2SGgAOCZmquCEjlbV/LjY2CY80rDtdQRHFOYXNlgBDo6Fr3ww2CWPOtA==
+  dependencies:
+    bl "^2.2.0"
+    end-of-stream "^1.4.1"
+    fs-constants "^1.0.0"
+    inherits "^2.0.3"
+    readable-stream "^3.1.1"
+
+tar-stream@^1.1.2:
+  version "1.6.2"
+  resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555"
+  integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==
+  dependencies:
+    bl "^1.0.0"
+    buffer-alloc "^1.2.0"
+    end-of-stream "^1.0.0"
+    fs-constants "^1.0.0"
+    readable-stream "^2.3.0"
+    to-buffer "^1.1.1"
+    xtend "^4.0.0"
+
+tar-stream@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.0.tgz#d1aaa3661f05b38b5acc9b7020efdca5179a2cc3"
+  integrity sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw==
+  dependencies:
+    bl "^3.0.0"
+    end-of-stream "^1.4.1"
+    fs-constants "^1.0.0"
+    inherits "^2.0.3"
+    readable-stream "^3.1.1"
+
+tar@^4:
+  version "4.4.8"
+  resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d"
+  integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==
+  dependencies:
+    chownr "^1.1.1"
+    fs-minipass "^1.2.5"
+    minipass "^2.3.4"
+    minizlib "^1.1.1"
+    mkdirp "^0.5.0"
+    safe-buffer "^5.1.2"
+    yallist "^3.0.2"
+
+temp@^0.8.1:
+  version "0.8.4"
+  resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.4.tgz#8c97a33a4770072e0a05f919396c7665a7dd59f2"
+  integrity sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==
+  dependencies:
+    rimraf "~2.6.2"
+
+temp@^0.8.3:
+  version "0.8.3"
+  resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59"
+  integrity sha1-4Ma8TSa5AxJEEOT+2BEDAU38H1k=
+  dependencies:
+    os-tmpdir "^1.0.0"
+    rimraf "~2.2.6"
+
+term-size@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69"
+  integrity sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=
+  dependencies:
+    execa "^0.7.0"
+
+ternary-stream@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/ternary-stream/-/ternary-stream-2.0.1.tgz#064e489b4b5bf60ba6a6b7bc7f2f5c274ecf8269"
+  integrity sha1-Bk5Im0tb9gumpre8fy9cJ07Pgmk=
+  dependencies:
+    duplexify "^3.5.0"
+    fork-stream "^0.0.4"
+    merge-stream "^1.0.0"
+    through2 "^2.0.1"
+
+text-encoding@0.6.4:
+  version "0.6.4"
+  resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.6.4.tgz#e399a982257a276dae428bb92845cb71bdc26d19"
+  integrity sha1-45mpgiV6J22uQou5KEXLcb3CbRk=
+
+text-hex@1.0.x:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5"
+  integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==
+
+text-table@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
+  integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
+
+textextensions@^2.4.0:
+  version "2.4.0"
+  resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.4.0.tgz#6a143a985464384cc2cff11aea448cd5b018e72b"
+  integrity sha512-qftQXnX1DzpSV8EddtHIT0eDDEiBF8ywhFYR2lI9xrGtxqKN+CvLXhACeCIGbCpQfxxERbrkZEFb8cZcDKbVZA==
+
+thenify-all@^1.0.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726"
+  integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=
+  dependencies:
+    thenify ">= 3.1.0 < 4"
+
+"thenify@>= 3.1.0 < 4":
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.0.tgz#e69e38a1babe969b0108207978b9f62b88604839"
+  integrity sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=
+  dependencies:
+    any-promise "^1.0.0"
+
+through2-filter@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-2.0.0.tgz#60bc55a0dacb76085db1f9dae99ab43f83d622ec"
+  integrity sha1-YLxVoNrLdghdsfna6Zq0P4PWIuw=
+  dependencies:
+    through2 "~2.0.0"
+    xtend "~4.0.0"
+
+through2-filter@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-3.0.0.tgz#700e786df2367c2c88cd8aa5be4cf9c1e7831254"
+  integrity sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==
+  dependencies:
+    through2 "~2.0.0"
+    xtend "~4.0.0"
+
+through2@^0.6.0:
+  version "0.6.5"
+  resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48"
+  integrity sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=
+  dependencies:
+    readable-stream ">=1.0.33-1 <1.1.0-0"
+    xtend ">=4.0.0 <4.1.0-0"
+
+through2@^2.0.0, through2@^2.0.1, through2@^2.0.3, through2@~2.0.0:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
+  integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==
+  dependencies:
+    readable-stream "~2.3.6"
+    xtend "~4.0.1"
+
+through2@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.1.tgz#39276e713c3302edf9e388dd9c812dd3b825bd5a"
+  integrity sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==
+  dependencies:
+    readable-stream "2 || 3"
+
+through@^2.3.6:
+  version "2.3.8"
+  resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
+  integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
+
+timed-out@^3.0.0:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-3.1.3.tgz#95860bfcc5c76c277f8f8326fd0f5b2e20eba217"
+  integrity sha1-lYYL/MXHbCd/j4Mm/Q9bLiDrohc=
+
+timed-out@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f"
+  integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=
+
+tmp@^0.0.29:
+  version "0.0.29"
+  resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0"
+  integrity sha1-8lEl/w3Z2jzLDC3Tce4SiLuRKMA=
+  dependencies:
+    os-tmpdir "~1.0.1"
+
+tmp@^0.0.31:
+  version "0.0.31"
+  resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7"
+  integrity sha1-jzirlDjhcxXl29izZX6L+yd65Kc=
+  dependencies:
+    os-tmpdir "~1.0.1"
+
+tmp@^0.0.33:
+  version "0.0.33"
+  resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
+  integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==
+  dependencies:
+    os-tmpdir "~1.0.2"
+
+to-absolute-glob@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/to-absolute-glob/-/to-absolute-glob-0.1.1.tgz#1cdfa472a9ef50c239ee66999b662ca0eb39937f"
+  integrity sha1-HN+kcqnvUMI57maZm2YsoOs5k38=
+  dependencies:
+    extend-shallow "^2.0.1"
+
+to-array@0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890"
+  integrity sha1-F+bBH3PdTz10zaek/zI46a2b+JA=
+
+to-buffer@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80"
+  integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==
+
+to-fast-properties@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
+  integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=
+
+to-fast-properties@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
+  integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=
+
+to-object-path@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
+  integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=
+  dependencies:
+    kind-of "^3.0.2"
+
+to-regex-range@^2.1.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38"
+  integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=
+  dependencies:
+    is-number "^3.0.0"
+    repeat-string "^1.6.1"
+
+to-regex@^3.0.1, to-regex@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
+  integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==
+  dependencies:
+    define-property "^2.0.2"
+    extend-shallow "^3.0.2"
+    regex-not "^1.0.2"
+    safe-regex "^1.1.0"
+
+toidentifier@1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
+  integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
+
+tough-cookie@~2.4.3:
+  version "2.4.3"
+  resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
+  integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==
+  dependencies:
+    psl "^1.1.24"
+    punycode "^1.4.1"
+
+tr46@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09"
+  integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=
+  dependencies:
+    punycode "^2.1.0"
+
+trim-newlines@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
+  integrity sha1-WIeWa7WCpFA6QetST301ARgVphM=
+
+trim-right@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
+  integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=
+
+triple-beam@^1.2.0, triple-beam@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9"
+  integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==
+
+tsickle@^0.23.4:
+  version "0.23.6"
+  resolved "https://registry.yarnpkg.com/tsickle/-/tsickle-0.23.6.tgz#fcee57a5cb7f92a8c3a9e578ee0a286427dcfacd"
+  integrity sha1-/O5Xpct/kqjDqeV47gooZCfc+s0=
+  dependencies:
+    minimist "^1.2.0"
+    mkdirp "^0.5.1"
+    source-map "^0.5.6"
+    source-map-support "^0.4.2"
+
+tslib@^1.8.1, tslib@^1.9.0:
+  version "1.10.0"
+  resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
+  integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==
+
+tsutils@2.27.2:
+  version "2.27.2"
+  resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.27.2.tgz#60ba88a23d6f785ec4b89c6e8179cac9b431f1c7"
+  integrity sha512-qf6rmT84TFMuxAKez2pIfR8UCai49iQsfB7YWVjV1bKpy/d0PWT5rEOSM6La9PiHZ0k1RRZQiwVdVJfQ3BPHgg==
+  dependencies:
+    tslib "^1.8.1"
+
+tunnel-agent@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
+  integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=
+  dependencies:
+    safe-buffer "^5.0.1"
+
+tweetnacl@^0.14.3, tweetnacl@~0.14.0:
+  version "0.14.5"
+  resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
+  integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
+
+twinkie@0.0.11:
+  version "0.0.11"
+  resolved "https://registry.yarnpkg.com/twinkie/-/twinkie-0.0.11.tgz#013c5e4b6b23ac8dec5d4eb8f9f84858bc143a74"
+  integrity sha1-ATxeS2sjrI3sXU64+fhIWLwUOnQ=
+  dependencies:
+    cheerio "^1.0.0-rc.2"
+
+type-check@~0.3.2:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
+  integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=
+  dependencies:
+    prelude-ls "~1.1.2"
+
+type-detect@^4.0.0:
+  version "4.0.8"
+  resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
+  integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
+
+type-fest@^0.8.1:
+  version "0.8.1"
+  resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
+  integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
+
+type-is@^1.6.4, type-is@~1.6.17, type-is@~1.6.18:
+  version "1.6.18"
+  resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
+  integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
+  dependencies:
+    media-typer "0.3.0"
+    mime-types "~2.1.24"
+
+typedarray@^0.0.6:
+  version "0.0.6"
+  resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
+  integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
+
+typescript@^2.4.1:
+  version "2.9.2"
+  resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.2.tgz#1cbf61d05d6b96269244eb6a3bce4bd914e0f00c"
+  integrity sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==
+
+typescript@^3.7.4:
+  version "3.7.5"
+  resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae"
+  integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==
+
+typical@^2.6.1:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/typical/-/typical-2.6.1.tgz#5c080e5d661cbbe38259d2e70a3c7253e873881d"
+  integrity sha1-XAgOXWYcu+OCWdLnCjxyU+hziB0=
+
+typical@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4"
+  integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==
+
+ua-parser-js@^0.7.15:
+  version "0.7.21"
+  resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.21.tgz#853cf9ce93f642f67174273cc34565ae6f308777"
+  integrity sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ==
+
+uglify-js@3.4.x:
+  version "3.4.10"
+  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f"
+  integrity sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==
+  dependencies:
+    commander "~2.19.0"
+    source-map "~0.6.1"
+
+underscore@^1.8.3:
+  version "1.9.2"
+  resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.2.tgz#0c8d6f536d6f378a5af264a72f7bec50feb7cf2f"
+  integrity sha512-D39qtimx0c1fI3ya1Lnhk3E9nONswSKhnffBI0gME9C99fYOkNi04xs8K6pePLhvl1frbDemkaBQ5ikWllR2HQ==
+
+underscore@~1.6.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.6.0.tgz#8b38b10cacdef63337b8b24e4ff86d45aea529a8"
+  integrity sha1-izixDKze9jM3uLJOT/htRa6lKag=
+
+unicode-canonical-property-names-ecmascript@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818"
+  integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==
+
+unicode-match-property-ecmascript@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c"
+  integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==
+  dependencies:
+    unicode-canonical-property-names-ecmascript "^1.0.4"
+    unicode-property-aliases-ecmascript "^1.0.4"
+
+unicode-match-property-value-ecmascript@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz#5b4b426e08d13a80365e0d657ac7a6c1ec46a277"
+  integrity sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==
+
+unicode-property-aliases-ecmascript@^1.0.4:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz#a9cc6cc7ce63a0a3023fc99e341b94431d405a57"
+  integrity sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==
+
+union-value@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847"
+  integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==
+  dependencies:
+    arr-union "^3.1.0"
+    get-value "^2.0.6"
+    is-extendable "^0.1.1"
+    set-value "^2.0.1"
+
+unique-stream@^2.0.2:
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-2.3.1.tgz#c65d110e9a4adf9a6c5948b28053d9a8d04cbeac"
+  integrity sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==
+  dependencies:
+    json-stable-stringify-without-jsonify "^1.0.1"
+    through2-filter "^3.0.0"
+
+unique-string@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a"
+  integrity sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=
+  dependencies:
+    crypto-random-string "^1.0.0"
+
+universal-user-agent@^2.0.0, universal-user-agent@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-2.1.0.tgz#5abfbcc036a1ba490cb941f8fd68c46d3669e8e4"
+  integrity sha512-8itiX7G05Tu3mGDTdNY2fB4KJ8MgZLS54RdG6PkkfwMAavrXu1mV/lls/GABx9O3Rw4PnTtasxrvbMQoBYY92Q==
+  dependencies:
+    os-name "^3.0.0"
+
+unpipe@1.0.0, unpipe@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
+  integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=
+
+unset-value@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559"
+  integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=
+  dependencies:
+    has-value "^0.3.1"
+    isobject "^3.0.0"
+
+untildify@^2.0.0, untildify@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/untildify/-/untildify-2.1.0.tgz#17eb2807987f76952e9c0485fc311d06a826a2e0"
+  integrity sha1-F+soB5h/dpUunASF/DEdBqgmouA=
+  dependencies:
+    os-homedir "^1.0.0"
+
+untildify@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/untildify/-/untildify-3.0.3.tgz#1e7b42b140bcfd922b22e70ca1265bfe3634c7c9"
+  integrity sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==
+
+unzip-response@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-1.0.2.tgz#b984f0877fc0a89c2c773cc1ef7b5b232b5b06fe"
+  integrity sha1-uYTwh3/AqJwsdzzB73tbIytbBv4=
+
+unzip-response@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97"
+  integrity sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=
+
+update-notifier@^1.0.0:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-1.0.3.tgz#8f92c515482bd6831b7c93013e70f87552c7cf5a"
+  integrity sha1-j5LFFUgr1oMbfJMBPnD4dVLHz1o=
+  dependencies:
+    boxen "^0.6.0"
+    chalk "^1.0.0"
+    configstore "^2.0.0"
+    is-npm "^1.0.0"
+    latest-version "^2.0.0"
+    lazy-req "^1.1.0"
+    semver-diff "^2.0.0"
+    xdg-basedir "^2.0.0"
+
+update-notifier@^2.2.0, update-notifier@^2.3.0:
+  version "2.5.0"
+  resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.5.0.tgz#d0744593e13f161e406acb1d9408b72cad08aff6"
+  integrity sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==
+  dependencies:
+    boxen "^1.2.1"
+    chalk "^2.0.1"
+    configstore "^3.0.0"
+    import-lazy "^2.1.0"
+    is-ci "^1.0.10"
+    is-installed-globally "^0.1.0"
+    is-npm "^1.0.0"
+    latest-version "^3.0.0"
+    semver-diff "^2.0.0"
+    xdg-basedir "^3.0.0"
+
+upper-case@^1.1.1:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598"
+  integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=
+
+uri-js@^4.2.2:
+  version "4.2.2"
+  resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
+  integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
+  dependencies:
+    punycode "^2.1.0"
+
+urijs@^1.16.1:
+  version "1.19.1"
+  resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.1.tgz#5b0ff530c0cbde8386f6342235ba5ca6e995d25a"
+  integrity sha512-xVrGVi94ueCJNrBSTjWqjvtgvl3cyOTThp2zaMaFNGp3F542TR6sM3f2o8RqZl+AwteClSVmoCyt0ka4RjQOQg==
+
+urijs@^1.19.1:
+  version "1.19.2"
+  resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.2.tgz#f9be09f00c4c5134b7cb3cf475c1dd394526265a"
+  integrity sha512-s/UIq9ap4JPZ7H1EB5ULo/aOUbWqfDi7FKzMC2Nz+0Si8GiT1rIEaprt8hy3Vy2Ex2aJPpOQv4P4DuOZ+K1c6w==
+
+urix@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
+  integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=
+
+url-parse-lax@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73"
+  integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=
+  dependencies:
+    prepend-http "^1.0.1"
+
+url-template@^2.0.8:
+  version "2.0.8"
+  resolved "https://registry.yarnpkg.com/url-template/-/url-template-2.0.8.tgz#fc565a3cccbff7730c775f5641f9555791439f21"
+  integrity sha1-/FZaPMy/93MMd19WQflVV5FDnyE=
+
+url-to-options@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9"
+  integrity sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=
+
+use@^3.1.0:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
+  integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
+
+util-deprecate@^1.0.1, util-deprecate@~1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+  integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
+
+utils-merge@1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
+  integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
+
+uuid@^2.0.1:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a"
+  integrity sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=
+
+uuid@^3.2.1, uuid@^3.3.2:
+  version "3.3.2"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
+  integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
+
+v8-compile-cache@^2.0.3:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e"
+  integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==
+
+vali-date@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/vali-date/-/vali-date-1.0.0.tgz#1b904a59609fb328ef078138420934f6b86709a6"
+  integrity sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=
+
+validate-element-name@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/validate-element-name/-/validate-element-name-2.1.1.tgz#8ff75f7da69f73e7c510588362130508b7ac644e"
+  integrity sha1-j/dffaafc+fFEFiDYhMFCLesZE4=
+  dependencies:
+    is-potential-custom-element-name "^1.0.0"
+    log-symbols "^1.0.0"
+    meow "^3.7.0"
+
+validate-npm-package-license@^3.0.1:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
+  integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==
+  dependencies:
+    spdx-correct "^3.0.0"
+    spdx-expression-parse "^3.0.0"
+
+vargs@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/vargs/-/vargs-0.1.0.tgz#6b6184da6520cc3204ce1b407cac26d92609ebff"
+  integrity sha1-a2GE2mUgzDIEzhtAfKwm2SYJ6/8=
+
+vary@^1, vary@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
+  integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
+
+verror@1.10.0:
+  version "1.10.0"
+  resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
+  integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=
+  dependencies:
+    assert-plus "^1.0.0"
+    core-util-is "1.0.2"
+    extsprintf "^1.2.0"
+
+vinyl-file@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/vinyl-file/-/vinyl-file-2.0.0.tgz#a7ebf5ffbefda1b7d18d140fcb07b223efb6751a"
+  integrity sha1-p+v1/779obfRjRQPyweyI++2dRo=
+  dependencies:
+    graceful-fs "^4.1.2"
+    pify "^2.3.0"
+    pinkie-promise "^2.0.0"
+    strip-bom "^2.0.0"
+    strip-bom-stream "^2.0.0"
+    vinyl "^1.1.0"
+
+vinyl-fs@^2.4.3, vinyl-fs@^2.4.4:
+  version "2.4.4"
+  resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-2.4.4.tgz#be6ff3270cb55dfd7d3063640de81f25d7532239"
+  integrity sha1-vm/zJwy1Xf19MGNkDegfJddTIjk=
+  dependencies:
+    duplexify "^3.2.0"
+    glob-stream "^5.3.2"
+    graceful-fs "^4.0.0"
+    gulp-sourcemaps "1.6.0"
+    is-valid-glob "^0.3.0"
+    lazystream "^1.0.0"
+    lodash.isequal "^4.0.0"
+    merge-stream "^1.0.0"
+    mkdirp "^0.5.0"
+    object-assign "^4.0.0"
+    readable-stream "^2.0.4"
+    strip-bom "^2.0.0"
+    strip-bom-stream "^1.0.0"
+    through2 "^2.0.0"
+    through2-filter "^2.0.0"
+    vali-date "^1.0.0"
+    vinyl "^1.0.0"
+
+vinyl@^1.0.0, vinyl@^1.1.0, vinyl@^1.1.1, vinyl@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884"
+  integrity sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=
+  dependencies:
+    clone "^1.0.0"
+    clone-stats "^0.0.1"
+    replace-ext "0.0.1"
+
+vinyl@^2.0.1:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.2.0.tgz#d85b07da96e458d25b2ffe19fece9f2caa13ed86"
+  integrity sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==
+  dependencies:
+    clone "^2.1.1"
+    clone-buffer "^1.0.0"
+    clone-stats "^1.0.0"
+    cloneable-readable "^1.0.0"
+    remove-trailing-separator "^1.0.1"
+    replace-ext "^1.0.0"
+
+vlq@^0.2.2:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.3.tgz#8f3e4328cf63b1540c0d67e1b2778386f8975b26"
+  integrity sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==
+
+vscode-uri@=1.0.6:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-1.0.6.tgz#6b8f141b0bbc44ad7b07e94f82f168ac7608ad4d"
+  integrity sha512-sLI2L0uGov3wKVb9EB+vIQBl9tVP90nqRvxSoJ35vI3NjxE8jfsE5DSOhWgSunHSZmKS4OCi2jrtfxK7uyp2ww==
+
+wbuf@^1.1.0, wbuf@^1.7.2:
+  version "1.7.3"
+  resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df"
+  integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==
+  dependencies:
+    minimalistic-assert "^1.0.0"
+
+wct-local@^2.1.1:
+  version "2.1.5"
+  resolved "https://registry.yarnpkg.com/wct-local/-/wct-local-2.1.5.tgz#f7986753e3ad9a35d39178a9989350523561fff1"
+  integrity sha512-eqoZhjGy4Xq2tY0uB46Grkw/ztq+/rC0ImbYKl62unFHXtOgal+kkvnxR3SLRFNM8ty9+ItgycPeH0IpTqVL+w==
+  dependencies:
+    "@types/express" "^4.0.30"
+    "@types/freeport" "^1.0.19"
+    "@types/launchpad" "^0.6.0"
+    "@types/which" "^1.3.1"
+    chalk "^2.3.0"
+    cleankill "^2.0.0"
+    freeport "^1.0.4"
+    launchpad "^0.7.0"
+    selenium-standalone "^6.7.0"
+    which "^1.0.8"
+
+wct-sauce@^2.0.2:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/wct-sauce/-/wct-sauce-2.1.0.tgz#67d0be346aabbbc28384e8d143b8d3ca7ba774c0"
+  integrity sha512-c3R4PJcbpS7Gxv2vZ4HDAqpXV6cT9peslAWMU7hHH9PMhKDPbn8RNa6E4DVL0tOmZznB+3cRmtZ6+vJ/aDwu1A==
+  dependencies:
+    chalk "^2.4.1"
+    cleankill "^2.0.0"
+    lodash "^4.17.10"
+    request "^2.85.0"
+    sauce-connect-launcher "^1.0.0"
+    temp "^0.8.1"
+    uuid "^3.2.1"
+
+wd@^1.2.0:
+  version "1.12.0"
+  resolved "https://registry.yarnpkg.com/wd/-/wd-1.12.0.tgz#763ce9ebcaa854ab8e05d0a660f24da839674329"
+  integrity sha512-P8fOXV+FAxR7Pdto4sQ982ud6xUJHzxfY/JYH+NfBJ2EYJhGeO7fLXiVKosZK3YlZK7EQfPmUVqkbEzNlGTGgQ==
+  dependencies:
+    archiver "^3.0.0"
+    async "^2.0.0"
+    lodash "^4.0.0"
+    mkdirp "^0.5.1"
+    q "^1.5.1"
+    request "2.88.0"
+    vargs "^0.1.0"
+
+web-component-tester@^6.5.1, web-component-tester@^6.9.0:
+  version "6.9.2"
+  resolved "https://registry.yarnpkg.com/web-component-tester/-/web-component-tester-6.9.2.tgz#40a7b824f2cf3cbc4305552bdfc3357977ded48a"
+  integrity sha512-s2kB/+IE8XWcnxY1fqSpqTiiHEGHWgUWariAbiRlxmAvWSuvaCVNALHYebsZrLCNCLHKcJR8/sGv/bw0MWMvjw==
+  dependencies:
+    "@polymer/sinonjs" "^1.14.1"
+    "@polymer/test-fixture" "^0.0.3"
+    "@webcomponents/webcomponentsjs" "^1.0.7"
+    accessibility-developer-tools "^2.12.0"
+    async "^2.4.1"
+    body-parser "^1.17.2"
+    bower-config "^1.4.0"
+    chalk "^1.1.3"
+    cleankill "^2.0.0"
+    express "^4.15.3"
+    findup-sync "^2.0.0"
+    glob "^7.1.2"
+    lodash "^3.10.1"
+    multer "^1.3.0"
+    nomnom "^1.8.1"
+    polyserve "^0.27.13"
+    resolve "^1.5.0"
+    semver "^5.3.0"
+    send "^0.16.1"
+    server-destroy "^1.0.1"
+    sinon "^2.3.5"
+    sinon-chai "^2.10.0"
+    socket.io "^2.0.3"
+    stacky "^1.3.1"
+    wd "^1.2.0"
+  optionalDependencies:
+    update-notifier "^2.2.0"
+    wct-local "^2.1.1"
+    wct-sauce "^2.0.2"
+
+webidl-conversions@^4.0.2:
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
+  integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==
+
+webpack-core@^0.6.8:
+  version "0.6.9"
+  resolved "https://registry.yarnpkg.com/webpack-core/-/webpack-core-0.6.9.tgz#fc571588c8558da77be9efb6debdc5a3b172bdc2"
+  integrity sha1-/FcViMhVjad76e+23r3Fo7FyvcI=
+  dependencies:
+    source-list-map "~0.1.7"
+    source-map "~0.4.1"
+
+whatwg-url@^6.4.0:
+  version "6.5.0"
+  resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.5.0.tgz#f2df02bff176fd65070df74ad5ccbb5a199965a8"
+  integrity sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==
+  dependencies:
+    lodash.sortby "^4.7.0"
+    tr46 "^1.0.1"
+    webidl-conversions "^4.0.2"
+
+which@^1.0.8, which@^1.2.12, which@^1.2.14, which@^1.2.9, which@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
+  integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
+  dependencies:
+    isexe "^2.0.0"
+
+wide-align@^1.1.0:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
+  integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==
+  dependencies:
+    string-width "^1.0.2 || 2"
+
+widest-line@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-1.0.0.tgz#0c09c85c2a94683d0d7eaf8ee097d564bf0e105c"
+  integrity sha1-DAnIXCqUaD0Nfq+O4JfVZL8OEFw=
+  dependencies:
+    string-width "^1.0.1"
+
+widest-line@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.1.tgz#7438764730ec7ef4381ce4df82fb98a53142a3fc"
+  integrity sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==
+  dependencies:
+    string-width "^2.1.1"
+
+windows-release@^3.1.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.2.0.tgz#8122dad5afc303d833422380680a79cdfa91785f"
+  integrity sha512-QTlz2hKLrdqukrsapKsINzqMgOUpQW268eJ0OaOpJN32h272waxR9fkB9VoWRtK7uKHG5EHJcTXQBD8XZVJkFA==
+  dependencies:
+    execa "^1.0.0"
+
+winston-transport@^4.2.0, winston-transport@^4.3.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.3.0.tgz#df68c0c202482c448d9b47313c07304c2d7c2c66"
+  integrity sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A==
+  dependencies:
+    readable-stream "^2.3.6"
+    triple-beam "^1.2.0"
+
+winston@^3.0.0:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/winston/-/winston-3.2.1.tgz#63061377976c73584028be2490a1846055f77f07"
+  integrity sha512-zU6vgnS9dAWCEKg/QYigd6cgMVVNwyTzKs81XZtTFuRwJOcDdBg7AU0mXVyNbs7O5RH2zdv+BdNZUlx7mXPuOw==
+  dependencies:
+    async "^2.6.1"
+    diagnostics "^1.1.1"
+    is-stream "^1.1.0"
+    logform "^2.1.1"
+    one-time "0.0.4"
+    readable-stream "^3.1.1"
+    stack-trace "0.0.x"
+    triple-beam "^1.3.0"
+    winston-transport "^4.3.0"
+
+with-open-file@^0.1.6:
+  version "0.1.6"
+  resolved "https://registry.yarnpkg.com/with-open-file/-/with-open-file-0.1.6.tgz#0bc178ecab75f6baac8ae11c85e07445d690ea50"
+  integrity sha512-SQS05JekbtwQSgCYlBsZn/+m2gpn4zWsqpCYIrCHva0+ojXcnmUEPsBN6Ipoz3vmY/81k5PvYEWSxER2g4BTqA==
+  dependencies:
+    p-finally "^1.0.0"
+    p-try "^2.1.0"
+    pify "^4.0.1"
+
+word-wrap@~1.2.3:
+  version "1.2.3"
+  resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
+  integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
+
+wordwrap@~0.0.2:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
+  integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc=
+
+wordwrapjs@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/wordwrapjs/-/wordwrapjs-3.0.0.tgz#c94c372894cadc6feb1a66bff64e1d9af92c5d1e"
+  integrity sha512-mO8XtqyPvykVCsrwj5MlOVWvSnCdT+C+QVbm6blradR7JExAhbkZ7hZ9A+9NUtwzSqrlUo9a67ws0EiILrvRpw==
+  dependencies:
+    reduce-flatten "^1.0.1"
+    typical "^2.6.1"
+
+wrappy@1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+  integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
+
+write-file-atomic@^1.1.2:
+  version "1.3.4"
+  resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f"
+  integrity sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=
+  dependencies:
+    graceful-fs "^4.1.11"
+    imurmurhash "^0.1.4"
+    slide "^1.1.5"
+
+write-file-atomic@^2.0.0:
+  version "2.4.3"
+  resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481"
+  integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==
+  dependencies:
+    graceful-fs "^4.1.11"
+    imurmurhash "^0.1.4"
+    signal-exit "^3.0.2"
+
+write@1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3"
+  integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==
+  dependencies:
+    mkdirp "^0.5.1"
+
+ws@^7.1.2:
+  version "7.2.1"
+  resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.1.tgz#03ed52423cd744084b2cf42ed197c8b65a936b8e"
+  integrity sha512-sucePNSafamSKoOqoNfBd8V0StlkzJKL2ZAhGQinCfNQ+oacw+Pk7lcdAElecBF2VkLNZRiIb5Oi1Q5lVUVt2A==
+
+ws@~6.1.0:
+  version "6.1.4"
+  resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9"
+  integrity sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==
+  dependencies:
+    async-limiter "~1.0.0"
+
+xdg-basedir@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2"
+  integrity sha1-7byQPMOF/ARSPZZqM1UEtVBNG9I=
+  dependencies:
+    os-homedir "^1.0.0"
+
+xdg-basedir@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4"
+  integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=
+
+xmlbuilder@8.2.2:
+  version "8.2.2"
+  resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-8.2.2.tgz#69248673410b4ba42e1a6136551d2922335aa773"
+  integrity sha1-aSSGc0ELS6QuGmE2VR0pIjNap3M=
+
+xmldom@0.1.x:
+  version "0.1.31"
+  resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.31.tgz#b76c9a1bd9f0a9737e5a72dc37231cf38375e2ff"
+  integrity sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==
+
+xmlhttprequest-ssl@~1.5.4:
+  version "1.5.5"
+  resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e"
+  integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=
+
+"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@~4.0.0, xtend@~4.0.1:
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
+  integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
+
+yallist@^2.1.2:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
+  integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
+
+yallist@^3.0.0, yallist@^3.0.2:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9"
+  integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==
+
+yauzl@^2.10.0:
+  version "2.10.0"
+  resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9"
+  integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=
+  dependencies:
+    buffer-crc32 "~0.2.3"
+    fd-slicer "~1.1.0"
+
+yeast@0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"
+  integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk=
+
+yeoman-environment@^1.5.2:
+  version "1.6.6"
+  resolved "https://registry.yarnpkg.com/yeoman-environment/-/yeoman-environment-1.6.6.tgz#cd85fa67d156060e440d7807d7ef7cf0d2d1d671"
+  integrity sha1-zYX6Z9FWBg5EDXgH1+988NLR1nE=
+  dependencies:
+    chalk "^1.0.0"
+    debug "^2.0.0"
+    diff "^2.1.2"
+    escape-string-regexp "^1.0.2"
+    globby "^4.0.0"
+    grouped-queue "^0.3.0"
+    inquirer "^1.0.2"
+    lodash "^4.11.1"
+    log-symbols "^1.0.1"
+    mem-fs "^1.1.0"
+    text-table "^0.2.0"
+    untildify "^2.0.0"
+
+yeoman-environment@^2.0.5:
+  version "2.4.0"
+  resolved "https://registry.yarnpkg.com/yeoman-environment/-/yeoman-environment-2.4.0.tgz#4829445dc1306b02d9f5f7027cd224bf77a8224d"
+  integrity sha512-SsvoL0RNAFIX69eFxkUhwKUN2hG1UwUjxrcP+T2ytwdhqC/kHdnFOH2SXdtSN1Ju4aO4xuimmzfRoheYY88RuA==
+  dependencies:
+    chalk "^2.4.1"
+    cross-spawn "^6.0.5"
+    debug "^3.1.0"
+    diff "^3.5.0"
+    escape-string-regexp "^1.0.2"
+    globby "^8.0.1"
+    grouped-queue "^0.3.3"
+    inquirer "^6.0.0"
+    is-scoped "^1.0.0"
+    lodash "^4.17.10"
+    log-symbols "^2.2.0"
+    mem-fs "^1.1.0"
+    strip-ansi "^4.0.0"
+    text-table "^0.2.0"
+    untildify "^3.0.3"
+
+yeoman-generator@^3.1.1:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/yeoman-generator/-/yeoman-generator-3.2.0.tgz#02077d2d7ff28fedc1ed7dad7f9967fd7c3604cc"
+  integrity sha512-iR/qb2je3GdXtSfxgvOXxUW0Cp8+C6LaZaNlK2BAICzFNzwHtM10t/QBwz5Ea9nk6xVDQNj4Q889TjCXGuIv8w==
+  dependencies:
+    async "^2.6.0"
+    chalk "^2.3.0"
+    cli-table "^0.3.1"
+    cross-spawn "^6.0.5"
+    dargs "^6.0.0"
+    dateformat "^3.0.3"
+    debug "^4.1.0"
+    detect-conflict "^1.0.0"
+    error "^7.0.2"
+    find-up "^3.0.0"
+    github-username "^4.0.0"
+    istextorbinary "^2.2.1"
+    lodash "^4.17.10"
+    make-dir "^1.1.0"
+    mem-fs-editor "^5.0.0"
+    minimist "^1.2.0"
+    pretty-bytes "^5.1.0"
+    read-chunk "^3.0.0"
+    read-pkg-up "^4.0.0"
+    rimraf "^2.6.2"
+    run-async "^2.0.0"
+    shelljs "^0.8.0"
+    text-table "^0.2.0"
+    through2 "^3.0.0"
+    yeoman-environment "^2.0.5"
+
+zip-stream@^2.1.2:
+  version "2.1.3"
+  resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-2.1.3.tgz#26cc4bdb93641a8590dd07112e1f77af1758865b"
+  integrity sha512-EkXc2JGcKhO5N5aZ7TmuNo45budRaFGHOmz24wtJR7znbNqDPmdZtUauKX6et8KAVseAMBOyWJqEpXcHTBsh7Q==
+  dependencies:
+    archiver-utils "^2.1.0"
+    compress-commons "^2.1.1"
+    readable-stream "^3.4.0"