New Upstream Release - impress.js

Ready changes

Summary

Merged new upstream version: 2.0.0 (was: 1.1.0).

Resulting package

Built on 2022-11-30T13:17 (took 3m39s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases libjs-impress

Lintian Result

Diff

diff --git a/.circleci/config.yml b/.circleci/config.yml
index 98ed34d..b74ee4c 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -6,9 +6,6 @@ jobs:
       - image: circleci/node:current-browsers
     steps:
       - checkout
-      - run:
-          name: update-npm
-          command: 'sudo npm install -g npm@latest'
       - restore_cache:
           key: dependency-cache-{{ checksum "package.json" }}
       - run:
diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md
index fabda86..e95a2da 100644
--- a/DOCUMENTATION.md
+++ b/DOCUMENTATION.md
@@ -21,8 +21,12 @@ You need to use pixel values. The pixel values used here correspond to the `data
 given to the `#impress` root element. When the presentation is viewed on a larger or smaller screen, impress.js
 will automatically scale the steps to fit the screen.
 
-**NOTE:** I intend to change the defaults to target HD screens in 2021. So you may want to make a habit
-of explicitly defining these attributes for now, to avoid any disruption when the defaults change.
+**NOTE:** The default width and height have been changed to target HD screens in v1.2.0. If you
+don't set target width and height explicitly, layout and dimensions of your presentations are likely
+to be affected. In order to get back the old target resolution, use:
+
+    <div id="impress" data-width="1024" data-height="768" data-max-scale="1" data-min-scale="0"
+
 
 You can also control the perspective with `data-perspective="500"` giving it a number of pixels.
 It defaults to 1000. You can set it to 0 if you don't want any 3D effects.
@@ -36,9 +40,9 @@ See also [the plugin README](src/plugins/README.md) for documentation on `data-a
 Attribute                | Default   | Explanation
 -------------------------|-----------|------------
 data-transition-duration | 1000 (ms) | Speed of transition between steps.
-data-width               | 1024 (px) | Width of target screen size. When presentation is viewed on a larger or smaller screen, impress.js will scale all content automatically.
-data-height              | 768 (px)  | Height of target screen size.
-data-max-scale           | 1         | Maximum scale factor. (Note that the default 1 will not increase content size on larger screens!)
+data-width               | 1920 (px) | Width of target screen size. When presentation is viewed on a larger or smaller screen, impress.js will scale all content automatically.
+data-height              | 1080 (px) | Height of target screen size.
+data-max-scale           | 3         | Maximum scale factor. (Note that the default 1 will not increase content size on larger screens!)
 data-min-scale           | 0         | Minimum scale factor.
 data-perspective         | 1000      | Perspective for 3D rendering. See https://developer.mozilla.org/en/CSS/perspective
 
diff --git a/build.js b/build.js
index eac7e89..7136042 100644
--- a/build.js
+++ b/build.js
@@ -5,7 +5,7 @@ var Terser = require("terser");
 
 var files = ['src/impress.js'];
 // Libraries from src/lib
-files.push('src/lib/gc.js', 'src/lib/util.js')
+files.push('src/lib/gc.js', 'src/lib/util.js', 'src/lib/rotation.js')
 // Plugins from src/plugins
 files.push('src/plugins/autoplay/autoplay.js',
            'src/plugins/blackout/blackout.js',
@@ -71,4 +71,4 @@ html += '</body>\n</html>'
 
 filename = path.resolve(__dirname, 'examples', 'index.html');
 fs.writeFileSync(filename, html);
-console.log(filename);
\ No newline at end of file
+console.log(filename);
diff --git a/debian/changelog b/debian/changelog
index f43db86..710dfd3 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,8 +1,9 @@
-impress.js (1.1.0-3) UNRELEASED; urgency=medium
+impress.js (2.0.0-1) UNRELEASED; urgency=medium
 
   * Update standards version to 4.6.1, no changes needed.
+  * New upstream release.
 
- -- Debian Janitor <janitor@jelmer.uk>  Sat, 10 Sep 2022 00:18:35 -0000
+ -- Debian Janitor <janitor@jelmer.uk>  Wed, 30 Nov 2022 13:14:12 -0000
 
 impress.js (1.1.0-2) unstable; urgency=medium
 
diff --git a/examples/3D-positions/index.html b/examples/3D-positions/index.html
new file mode 100644
index 0000000..3dedb65
--- /dev/null
+++ b/examples/3D-positions/index.html
@@ -0,0 +1,169 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8" />
+    <title>relative rotations</title>
+    <link href="..\..\css\impress-common.css" rel="stylesheet" />
+    <style type="text/css" media="screen">
+#overview {
+    background: none;
+    border: none;
+    box-shadow: none;
+    width: 1800px;
+    height: 1300px;
+}
+
+#overview div {
+    width: 100%;
+    height: 100%;
+}
+
+.step {
+    position: relative;
+    width: 1000px;
+    height: 1000px;
+    padding: 40px 60px;
+    margin: 20px auto;
+
+    box-sizing:         border-box;
+
+    line-height: 1.5;
+
+    background-color: yellow;
+    border-radius: 10px;
+    box-shadow: 0 2px 6px rgba(0, 0, 0, .1);
+
+    text-shadow: 0 2px 2px rgba(0, 0, 0, .1);
+
+    font-family: 'Open Sans', Arial, sans-serif;
+    font-size: 40pt;
+    letter-spacing: -1px;
+    border: solid 2px red;
+
+    opacity: 40%;
+}
+
+.step.active {
+    opacity: 100%;
+}
+
+.step.ring2 {
+    background-color: cyan;
+}
+
+.step.box {
+    background-color: purple;
+    opacity: 70%;
+}
+
+.step.box1 {
+    background-color: lightblue;
+}
+    </style>
+  </head>
+
+  <body class="impress-not-supported">
+    <div id="impress" data-width="2000" data-height="1500">
+      <div id="overview" class="step overview" data-rel-position="relative" data-x="-1000" data-y="-1500" data-z="100" data-scale="3" data-rotate-x="45" data-rotate-y="10">
+          <div>
+              <h2>Demo of <code>data-rel-position</code></h2>
+              <p>This demo use <code>data-rel-position="relative"</code><br>
+                  and <code>data-rel-rotate-x/y/z</code><br>
+                  to easy 3D positioning of slides.</p>
+          </div>
+      </div>
+
+      <div id="box-front" class="step box" data-x="-3000" data-y="0" data-z="0" data-rotate-x="0" data-rotate-y="0" data-rotate-z="0">Front
+          <p>There's two nested box here.</p>
+      </div>
+      <div id="box-front1" class="step box1" data-rel-reset data-rel-z="-200" data-scale="0.6">Inside Front</div>
+      <div id="box-right1" class="step box1" data-rel-reset data-rel-x="300" data-rel-z="-300" data-rel-rotate-y="90" data-scale="0.6">Inside Right</div>
+      <div id="box-right" class="step box" data-rel-reset data-rel-z="200">Right</div>
+      <div id="box-back" class="step box" data-rel-reset data-rel-x="500" data-rel-z="-500" data-rel-rotate-y="90">Back</div>
+      <div id="box-back1" class="step box1" data-rel-reset data-rel-z="-200" data-scale="0.6">Inside Back</div>
+      <div id="box-top1" class="step box1" data-rel-reset data-rel-y="-300" data-rel-z="-300" data-rel-rotate-x="90" data-scale="0.6">Inside Top</div>
+      <div id="box-top" class="step box" data-rel-reset data-rel-z="200">Top</div>
+      <div id="box-left" class="step box" data-rel-reset data-rel-x="500" data-rel-z="-500" data-rel-rotate-y="90">Left</div>
+      <div id="box-left1" class="step box1" data-rel-reset data-rel-z="-200" data-scale="0.6">Inside Left</div>
+      <div id="box-bottom1" class="step box1" data-rel-reset data-rel-x="300" data-rel-z="-300" data-rel-rotate-y="90" data-scale="0.6">Inside Bottom</div>
+      <div id="box-bottom" class="step box" data-rel-reset data-rel-z="200">Bottom</div>
+
+      <div id="ring1-1" class="step" data-rel-reset="all" data-x="0" data-y="0" data-z="0" data-rotate-y="10">
+        <p>Slide one</p>
+        <p>This is a ring of 8 slides.</p>
+        <p>It's easy constucted with data-rel-position="relative" without calculates the coordinates of all slides.</p>
+      </div>
+
+      <div id="ring1-2" class="step" data-rel-rotate-y="45" data-rel-z="-354" data-rel-x="854">
+        <p>Slide two</p>
+        <p>The position of this slide is calculated as relatived position and rotation of the first slide.</p>
+        <p>The following slides don't need to set any position attributes, they are inherit from this slide.</p>
+      </div>
+
+      <div id="ring1-3" class="step">
+        <p>Slide three</p>
+      </div>
+
+      <div id="ring1-4" class="step">
+        <p>Slide four</p>
+      </div>
+
+      <div id="ring1-5" class="step">
+        <p>Slide five</p>
+      </div>
+
+      <div id="ring1-6" class="step">
+        <p>Slide six</p>
+      </div>
+
+      <div id="ring1-7" class="step">
+        <p>Slide seven</p>
+      </div>
+
+      <div id="ring1-8" class="step">
+        <p>Slide eight</p>
+      </div>
+
+      <div id="ring2-1" class="step ring2" data-rel-reset="all" data-x="-500" data-y="0" data-z="-1514" data-rotate-x="90" data-rotate-y="270" data-rotate-z="0">
+        <p>Slide one</p>
+        <p>This is another ring of slides.</p>
+        <p>Except for the this slide, its code is just cloned from the yellow ring.</p>
+        <p>Just change the position of first slide, all the following slides are position relatived to it.</p>
+      </div>
+
+      <div id="ring2-2" class="step ring2" data-rel-rotate-y="45" data-rel-z="-354" data-rel-x="854" data-rel-y="0">
+        <p>Slide two</p>
+      </div>
+
+      <div id="ring2-3" class="step ring2">
+        <p>Slide three</p>
+      </div>
+
+      <div id="ring2-4" class="step ring2">
+        <p>Slide four</p>
+      </div>
+
+      <div id="ring2-5" class="step ring2">
+        <p>Slide five</p>
+      </div>
+
+      <div id="ring2-6" class="step ring2">
+        <p>Slide six</p>
+      </div>
+
+      <div id="ring2-7" class="step ring2">
+        <p>Slide seven</p>
+      </div>
+
+      <div id="ring2-8" class="step ring2">
+        <p>Slide eight</p>
+      </div>
+    </div>
+
+    <div id="impress-toolbar"></div>
+    <div id="impress-help"></div>
+
+    <script type="text/javascript" src="../../js/impress.js"></script>
+    <script>impress().init();</script>
+  </body>
+<html>
diff --git a/examples/classic-slides/index.html b/examples/classic-slides/index.html
index 50cae1c..95fab95 100644
--- a/examples/classic-slides/index.html
+++ b/examples/classic-slides/index.html
@@ -188,7 +188,7 @@
         Notation shouldn't be a surprise. We use `data-rotate="30"` attribute, meaning that this
         element should be rotated by 30 degrees clockwise.        
     -->
-    <div class="step slide" data-rel-x="2200" data-rel-y="600" data-rotate="30">
+    <div class="step slide" data-rel-position="relative" data-rel-x="2200" data-rel-y="600" data-rel-rotate-z="30">
         <h1>A blockquote &amp; image</h1>
         <img src="images/3476636111_c551295ca4_b.jpg" 
              alt="Mother Teresa holding a newborn baby" 
@@ -200,10 +200,14 @@
         </blockquote>
 
         <div class="notes">
+            We use <code>data-rel-position="relative"</code> to make <code>data-rel-rotate-*</code> work,
+            and make <code>data-rel-x/data-rel-y/data-rel-y</code> be calculated at the coordination related to previous slide.
+            The relative position and rotation will be inherited by following slides,
+            so it's not necessary to repeat it again and again.
         </div>
     </div>
 
-    <div class="step slide" data-rel-x="1600" data-rel-y="1600" data-rotate="60">
+    <div class="step slide">
         <h1>More text styles</h1>
         <p>As usual, use <em>em</em> to emphasize, <br />
            <strong>strong</strong> for strong, <u>u</u> for underline,<br />
@@ -216,7 +220,7 @@
         </div>
     </div>
 
-    <div class="step slide" data-rel-x="600" data-rel-y="2200" data-rotate="90">
+    <div id="motions" class="step slide">
         <h1>Motion effects 101</h1>
         <p>Items on the slide can</p>
         <p class="fly-in fly-out">Fly in</p>
@@ -246,22 +250,32 @@
         </div>
     </div>
 
-    <div id="addons" class="step slide title" data-rel-x="-600" data-rel-y="2200" data-rotate="120">
+    <div id="zoom" class="step" data-rel-reset data-rel-x="-0.25w" data-rel-y="0.5h" data-scale="0.5">
+        <div class="notes">
+            <p>This step zoom in to left bottom of previous slide to see to small text.</p>
+            <p>It's a empty and transparent.</p>
+            <p><code>data-rel-reset</code> is used to prevent this step from inheriting the relative positioning from previous slide.</p>
+        </div>
+    </div>
+
+    <div id="addons" class="step slide title" data-rel-to="motions">
         <h2>Add-ons</h2>
         <div class="notes">
         <p>This version of impress.js includes several add-ons, striving to make this a
            full featured presentation app.</p>
+        <p>The previous step breaks the slide flow, changes the relative position and rotation.</p>
+        <p>This slide use <code>data-rel-to</code> to inherit relative position and rotation from the slide before previous slide.</p>
         </div>
     </div>
 
-    <div class="step slide" data-rel-x="-1600" data-rel-y="1600" data-rotate="150" data-autoplay="3">
+    <div class="step slide" data-autoplay="3">
         <h1>Impress.js plugins</h1>
         <ul>
         <li>A new <a href="https://github.com/impress/impress.js/blob/master/src/plugins/README.md">plugin framework</a> allows for rich extensibility,
             without bloating the core rendering library.
             <ul>
             <li class="substep">Press 'P' to open a presenter console.</li>
-            <li class="substep">When you move the mouse, navigation controls are visible on your bottom left</li>
+            <li class="substep">When you move the mouse, navigation controls are visible on your bottom right</li>
             <li class="substep">Autoplay makes the slides advance after a timeout</li>
             <li class="substep">Relative positioning plugin is often a more convenient way to position your slides when editing. (<a href="https://github.com/impress/impress.js/blob/master/examples/classic-slides/index.html">See html for this presentation.</a>)</li>
             </ul>
@@ -277,7 +291,7 @@
         </div>
     </div>
 
-    <div class="step slide" data-rel-x="-2200" data-rel-y="600" data-rotate="180">
+    <div class="step slide">
         <h1>Highlight.js</h1>
         <pre><code>
         // `init` API function that initializes (and runs) the presentation.
@@ -303,7 +317,7 @@
         </div>
     </div>
 
-    <div class="step slide" data-rel-x="-2200" data-rel-y="-600" data-rotate="210">
+    <div class="step slide">
         <h1>Mermaid.js</h1>
         <div class="mermaid">
         %% This is a comment in mermaid markup
@@ -330,7 +344,7 @@
         </div>
     </div>
 
-    <div id="markdown" class="step slide markdown" data-rel-x="-1600" data-rel-y="-1600" data-rotate="240">
+    <div id="markdown" class="step slide markdown">
 # Markdown.js
         
 * [Markdown.js](https://github.com/evilstreak/markdown-js) integration: for authors in a hurry!
@@ -344,7 +358,7 @@
 * [A more advanced Markdown presentation is here.](../markdown/)
     </div>
 
-    <div id="acme" class="step slide" data-rel-x="-600" data-rel-y="-2200" data-rotate="270">
+    <div id="acme" class="step slide">
         <ul>
         <li>Remember, in <em>impress.js</em> the full power of HTML5, CSS3 &amp; JavaScript is always at your fingertips!</li>
         <li>For example, you can use tables, forms, or dynamic charts as you would on any web page:</li>
diff --git a/examples/cube/css/cube.css b/examples/cube/css/cube.css
index 8239916..d975059 100644
--- a/examples/cube/css/cube.css
+++ b/examples/cube/css/cube.css
@@ -1,5 +1,29 @@
 @import url(fonts.css);
 
+/* Specific to this presentation */
+
+div.step p {
+    border: solid 2px black;
+    border-radius: 120px;
+    width: 170px;
+    height: 110px;
+    text-align: center;
+    padding-top: 65px;
+    background-color: black;
+    color: white;
+}
+
+div.step img {
+    border: solid 2px black;
+    border-radius: 120px;
+    width: 170px;
+    height: 170px;
+    text-align: center;
+    background-color: black;
+    color: white;
+}
+
+
 
 
 /*  Fallback message */
@@ -62,16 +86,6 @@ body {
     border: none;
     box-shadow: none;
 }
-/*
-    Make inactive steps a little bit transparent.
-*/
-.impress-enabled .step {
-    margin: 0;
-    opacity: 0.7;
-    transition:         opacity 1s;
-}
-
-.impress-enabled .step.active { opacity: 1 }
 
 h1, 
 h2, 
@@ -102,21 +116,18 @@ code {
 
 
 a {
-    color: inherit;
-    text-decoration: none;
-    padding: 0 0.1em;
-    background: rgba(200,200,200,0.2);
-    text-shadow: -1px 1px 2px rgba(100,100,100,0.9);
-    border-radius: 0.2em;
-    border-bottom: 1px solid rgba(100,100,100,0.2);
-    border-left:   1px solid rgba(100,100,100,0.2);
-
-    transition:         0.5s;
+    color: #ddd;
+    text-decoration: underline;
 }
 a:hover,
 a:focus {
     background: rgba(200,200,200,1);
     text-shadow: -1px 1px 2px rgba(100,100,100,0.5);
+    padding: 0 0.1em;
+    background: rgba(200,200,200,0.2);
+    border-radius: 0.2em;
+    border-bottom: 1px solid rgba(100,100,100,0.2);
+    border-left:   1px solid rgba(100,100,100,0.2);
 }
 
 blockquote {
@@ -146,4 +157,4 @@ strike {
 
 small {
     font-size: 0.4em;
-}
\ No newline at end of file
+}
diff --git a/examples/cube/img/Henrik_mustache.jpg b/examples/cube/img/Henrik_mustache.jpg
new file mode 100644
index 0000000..8b75d7d
Binary files /dev/null and b/examples/cube/img/Henrik_mustache.jpg differ
diff --git a/examples/cube/index.html b/examples/cube/index.html
index 95a01b0..a13f1e0 100644
--- a/examples/cube/index.html
+++ b/examples/cube/index.html
@@ -19,32 +19,47 @@
 
     <div class="step" data-x="0" data-y="0" data-z="350"
          data-goto-key-list="ArrowUp ArrowDown ArrowRight ArrowLeft o" data-goto-next-list="step-4 step-3 step-2 step-5 overview">
-        <p>Slide one</p>
+        <p style="position: absolute; top: 240px; left: 240px;">Slides</p>
     </div>
 
     <div class="step" data-x="350" data-y="0" data-z="0" data-rotate-y="90"
          data-goto-key-list="ArrowUp ArrowDown ArrowRight ArrowLeft o" data-goto-next-list="step-4 step-3 step-6 step-1 overview">
-        <p>Slide two</p>
+        <p style="position: absolute; top: 50px; left: 50px;">In</p>
+        <p style="position: absolute; bottom: 50px; right: 50px;">3D</p>
     </div>
 
     <div class="step" data-x="0" data-y="350" data-z="0" data-rotate-x="-90" data-rotate-z="90"
          data-goto-key-list="ArrowUp ArrowDown ArrowRight ArrowLeft o" data-goto-next-list="step-2 step-5 step-6 step-1 overview">
-        <p>Slide three</p>
+        <p style="position: absolute; top: 50px; left: 50px;">Check</p>
+        <p style="position: absolute; top: 240px; left: 240px;"><a href="https://impress.js.org">impress.js</a></p>
+        <p style="position: absolute; bottom: 50px; right: 50px;">out</p>
     </div>
 
     <div class="step" data-x="0" data-y="-350" data-z="0" data-rotate-x="90" data-rotate-z="-90"
          data-goto-key-list="ArrowUp ArrowDown ArrowRight ArrowLeft o" data-goto-next-list="step-5 step-2 step-6 step-1 overview">
-        <p>Slide four</p>
+        <p style="position: absolute; top: 50px; left: 50px;">CSS</p>
+        <p style="position: absolute; top: 50px; right: 50px;">Positioning</p>
+        <p style="position: absolute; bottom: 50px; left: 50px;">is</p>
+        <p style="position: absolute; bottom: 50px; right: 50px;">amazing</p>
     </div>
 
     <div class="step" data-x="-350" data-y="0" data-z="0" data-rotate-y="-90" data-rotate-z="-180"
          data-goto-key-list="ArrowUp ArrowDown ArrowRight ArrowLeft o" data-goto-next-list="step-3 step-4 step-6 step-1 overview">
-        <p>Slide five</p>
+        <p style="position: absolute; top: 50px; left: 50px;">By</p>
+        <p style="position: absolute; top: 50px; right: 50px;">hingo</p>
+        <img src="img/Henrik_mustache.jpg" alt="Henrik Ingo portrait, with mustache" style="position: absolute; top: 275px; left: 275px;">
+        <p style="position: absolute; bottom: 50px; left: 50px;">bartaz</p>
+        <p style="position: absolute; bottom: 50px; right: 50px; padding-top: 30px; height: 140px;"><a href="https://github.com/impress/impress.js/graphs/contributors">+70 contributors</a></p>
     </div>
 
     <div class="step" data-x="0" data-y="0" data-z="-350" data-rotate-y="-180" data-rotate-z="-180"
          data-goto-key-list="ArrowUp ArrowDown ArrowRight ArrowLeft o" data-goto-next-list="step-3 step-4 step-2 step-5 overview">
-        <p>Slide six</p>
+        <p style="position: absolute; top: 50px; left: 50px;">Open</p>
+        <p style="position: absolute; top: 50px; right: 50px;">Source</p>
+        <p style="position: absolute; top: 240px; left: 50px;">&amp;</p>
+        <p style="position: absolute; top: 240px; right: 50px;">HTML</p>
+        <p style="position: absolute; bottom: 50px; left: 50px;">CSS</p>
+        <p style="position: absolute; bottom: 50px; right: 50px;">JavaScript</p>
     </div>
 
     <div id="overview" class="step" data-x="700" data-y="-100" data-z="1000" data-scale="1" style="pointer-events: none;">
diff --git a/examples/index.html b/examples/index.html
index 1e5924b..f10ca60 100644
--- a/examples/index.html
+++ b/examples/index.html
@@ -5,6 +5,7 @@
 <body><h1>Example presentations</h1>
 <ul><br />
   <li><a href="2D-navigation/">2D-navigation</a></li>
+  <li><a href="3D-positions/">3D-positions</a></li>
   <li><a href="3D-rotations/">3D-rotations</a></li>
   <li><a href="classic-slides/">classic-slides</a></li>
   <li><a href="cube/">cube</a></li>
diff --git a/index.html b/index.html
index 25ae67a..cd0cb90 100644
--- a/index.html
+++ b/index.html
@@ -458,13 +458,10 @@ if ("ontouchstart" in document.documentElement) {
     
     Are you still reading this?
     
-    For real?
+    For real? I'm impressed! 
     
-    I'm impressed! Feel free to let me know that you got that far (I'm @bartaz on Twitter), 'cause I'd like
-    to congratulate you personally :)
-    
-    But you don't have to do it now. Take my advice and take some time off. Make yourself a cup of coffee, tea,
-    or anything you like to drink. And raise a glass for me ;)
+    But now, take my advice and take some time off. Make yourself a cup of coffee, tea,
+    or anything you like to drink.
     
     Cheers!
     
diff --git a/js/impress.js b/js/impress.js
index 14952c3..e7a0dee 100644
--- a/js/impress.js
+++ b/js/impress.js
@@ -169,9 +169,9 @@
 
     // Some default config values.
     var defaults = {
-        width: 1024,
-        height: 768,
-        maxScale: 1,
+        width: 1920,
+        height: 1080,
+        maxScale: 3,
         minScale: 0,
 
         perspective: 1000,
@@ -179,6 +179,9 @@
         transitionDuration: 1000
     };
 
+    // Configuration options
+    var config = null;
+
     // It's just an empty function ... and a useless comment.
     var empty = function() { return false; };
 
@@ -230,9 +233,6 @@
         // Array of step elements
         var steps = null;
 
-        // Configuration options
-        var config = null;
-
         // Scale factor of the browser window
         var windowScale = null;
 
@@ -283,9 +283,9 @@
             var data = el.dataset,
                 step = {
                     translate: {
-                        x: lib.util.toNumber( data.x ),
-                        y: lib.util.toNumber( data.y ),
-                        z: lib.util.toNumber( data.z )
+                        x: lib.util.toNumberAdvanced( data.x ),
+                        y: lib.util.toNumberAdvanced( data.y ),
+                        z: lib.util.toNumberAdvanced( data.z )
                     },
                     rotate: {
                         x: lib.util.toNumber( data.rotateX ),
@@ -323,9 +323,27 @@
             steps.forEach( initStep );
         };
 
+        // Build configuration from root and defaults
+        var buildConfig = function() {
+            var rootData = root.dataset;
+            return {
+                width: lib.util.toNumber( rootData.width, defaults.width ),
+                height: lib.util.toNumber( rootData.height, defaults.height ),
+                maxScale: lib.util.toNumber( rootData.maxScale, defaults.maxScale ),
+                minScale: lib.util.toNumber( rootData.minScale, defaults.minScale ),
+                perspective: lib.util.toNumber( rootData.perspective, defaults.perspective ),
+                transitionDuration: lib.util.toNumber(
+                    rootData.transitionDuration, defaults.transitionDuration
+                )
+            };
+        };
+
         // `init` API function that initializes (and runs) the presentation.
         var init = function() {
             if ( initialized ) { return; }
+
+            // Initialize the configuration object, so it can be used by pre-init plugins.
+            config = buildConfig();
             execPreInitPlugins( root );
 
             // First we set up the viewport for mobile devices.
@@ -337,19 +355,6 @@
                 document.head.appendChild( meta );
             }
 
-            // Initialize configuration object
-            var rootData = root.dataset;
-            config = {
-                width: lib.util.toNumber( rootData.width, defaults.width ),
-                height: lib.util.toNumber( rootData.height, defaults.height ),
-                maxScale: lib.util.toNumber( rootData.maxScale, defaults.maxScale ),
-                minScale: lib.util.toNumber( rootData.minScale, defaults.minScale ),
-                perspective: lib.util.toNumber( rootData.perspective, defaults.perspective ),
-                transitionDuration: lib.util.toNumber(
-                    rootData.transitionDuration, defaults.transitionDuration
-                )
-            };
-
             windowScale = computeWindowScale( config );
 
             // Wrap steps with "canvas" element
@@ -778,7 +783,7 @@
             // scrolling to element in hash.
             //
             // And it has to be set after animation finishes, because in Chrome it
-            // makes transtion laggy.
+            // makes transition laggy.
             // BUG: http://code.google.com/p/chromium/issues/detail?id=62820
             lib.gc.addEventListener( root, "impress:stepenter", function( event ) {
                 window.location.hash = lastHash = "#/" + event.target.id;
@@ -870,7 +875,7 @@
             var thisLevel = preInitPlugins[ i ];
             if ( thisLevel !== undefined ) {
                 for ( var j = 0; j < thisLevel.length; j++ ) {
-                    thisLevel[ j ]( root );
+                    thisLevel[ j ]( root, roots[ "impress-root-" + root.id ] );
                 }
             }
         }
@@ -890,6 +895,10 @@
         preStepLeavePlugins[ weight ].push( plugin );
     };
 
+    impress.getConfig = function() {
+        return config;
+    };
+
     // Called at beginning of goto(), to execute all preStepLeave plugins.
     var execPreStepLeavePlugins = function( event ) { //jshint ignore:line
         for ( var i = 0; i < preStepLeavePlugins.length; i++ ) {
@@ -1204,7 +1213,8 @@
 
             // Get id from url # by removing `#` or `#/` from the beginning,
             // so both "fallback" `#slide-id` and "enhanced" `#/slide-id` will work
-            return byId( window.location.hash.replace( /^#\/?/, "" ) );
+            var encoded = window.location.hash.replace( /^#\/?/, "" );
+            return byId( decodeURIComponent( encoded ) );
         };
 
         // `getUrlParamValue` return a given URL parameter value if it exists
@@ -1238,6 +1248,26 @@
             return isNaN( numeric ) ? ( fallback || 0 ) : Number( numeric );
         };
 
+        /**
+         * Extends toNumber() to correctly compute also relative-to-screen-size values 5w and 5h.
+         *
+         * Returns the computed value in pixels with w/h postfix removed.
+         */
+        var toNumberAdvanced = function( numeric, fallback ) {
+            if ( typeof numeric !== "string" ) {
+                return toNumber( numeric, fallback );
+            }
+            var ratio = numeric.match( /^([+-]*[\d\.]+)([wh])$/ );
+            if ( ratio == null ) {
+                return toNumber( numeric, fallback );
+            } else {
+                var value = parseFloat( ratio[ 1 ] );
+                var config = window.impress.getConfig();
+                var multiplier = ratio[ 2 ] === "w" ? config.width : config.height;
+                return value * multiplier;
+            }
+        };
+
         // `triggerEvent` builds a custom DOM event with given `eventName` and `detail` data
         // and triggers it on element given as `el`.
         var triggerEvent = function( el, eventName, detail ) {
@@ -1254,6 +1284,7 @@
             getElementFromHash: getElementFromHash,
             throttle: throttle,
             toNumber: toNumber,
+            toNumberAdvanced: toNumberAdvanced,
             triggerEvent: triggerEvent,
             getUrlParamValue: getUrlParamValue
         };
@@ -1266,6 +1297,436 @@
 
 } )( document, window );
 
+/**
+ * Helper functions for rotation.
+ *
+ * Tommy Tam (c) 2021
+ * MIT License
+ */
+( function( document, window ) {
+    "use strict";
+
+    // Singleton library variables
+    var roots = [];
+
+    var libraryFactory = function( rootId ) {
+        if ( roots[ "impress-root-" + rootId ] ) {
+            return roots[ "impress-root-" + rootId ];
+        }
+
+        /**
+         * Round the number to 2 decimals, it's enough for use
+         */
+        var roundNumber = function( num ) {
+            return Math.round( ( num + Number.EPSILON ) * 100 ) / 100;
+        };
+
+        /**
+         * Get the length/norm of a vector.
+         *
+         * https://en.wikipedia.org/wiki/Norm_(mathematics)
+         */
+        var vectorLength = function( vec ) {
+            return Math.sqrt( vec.x * vec.x + vec.y * vec.y + vec.z * vec.z );
+        };
+
+        /**
+         * Dot product of two vectors.
+         *
+         * https://en.wikipedia.org/wiki/Dot_product
+         */
+        var vectorDotProd = function( vec1, vec2 ) {
+            return vec1.x * vec2.x + vec1.y * vec2.y + vec1.z * vec2.z;
+        };
+
+        /**
+         * Cross product of two vectors.
+         *
+         * https://en.wikipedia.org/wiki/Cross_product
+         */
+        var vectorCrossProd = function( vec1, vec2 ) {
+            return {
+                x: vec1.y * vec2.z - vec1.z * vec2.y,
+                y: vec1.z * vec2.x - vec1.x * vec2.z,
+                z: vec1.x * vec2.y - vec1.y * vec2.x
+            };
+        };
+
+        /**
+         * Determine wheter a vector is a zero vector
+         */
+        var isZeroVector = function( vec ) {
+            return !roundNumber( vec.x ) && !roundNumber( vec.y ) && !roundNumber( vec.z );
+        };
+
+        /**
+         * Scalar triple product of three vectors.
+         *
+         * It can be used to determine the handness of vectors.
+         *
+         * https://en.wikipedia.org/wiki/Triple_product#Scalar_triple_product
+         */
+        var tripleProduct = function( vec1, vec2, vec3 ) {
+            return vectorDotProd( vectorCrossProd( vec1, vec2 ), vec3 );
+        };
+
+        /**
+         * The world/absolute unit coordinates.
+         *
+         * This coordinate is used by browser to position objects.
+         * It will not be affected by object rotations.
+         * All relative positions will finally be converted to this
+         * coordinate to be used.
+         */
+        var worldUnitCoordinate = {
+            x: { x:1, y:0, z:0 },
+            y: { x:0, y:1, z:0 },
+            z: { x:0, y:0, z:1 }
+        };
+
+        /**
+         * Make quaternion from rotation axis and angle.
+         *
+         * q = [ cos(½θ), sin(½θ) axis ]
+         *
+         * If the angle is zero, returns the corresponded quaternion
+         * of axis.
+         *
+         * If the angle is not zero, returns the rotating quaternion
+         * which corresponds to rotation about the axis, by the angle θ.
+         *
+         * https://en.wikipedia.org/wiki/Quaternion
+         * https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation
+         */
+        var makeQuaternion = function( axis, theta = 0 ) {
+            var r = 0;
+            var t = 1;
+
+            if ( theta ) {
+                var radians = theta * Math.PI / 180;
+                r = Math.cos( radians / 2 );
+                t = Math.sin( radians / 2 ) / vectorLength( axis );
+            }
+
+            var q = [ r, axis.x * t, axis.y * t, axis.z * t ];
+
+            return q;
+        };
+
+        /**
+         * Extract vector from quaternion
+         */
+        var quaternionToVector = function( quaternion ) {
+            return {
+                x: roundNumber( quaternion[ 1 ] ),
+                y: roundNumber( quaternion[ 2 ] ),
+                z: roundNumber( quaternion[ 3 ] )
+            };
+        };
+
+        /**
+         * Returns the conjugate quaternion of a quaternion
+         *
+         * https://en.wikipedia.org/wiki/Quaternion#Conjugation,_the_norm,_and_reciprocal
+         */
+        var conjugateQuaternion = function( quaternion ) {
+            return [ quaternion[ 0 ], -quaternion[ 1 ], -quaternion[ 2 ], -quaternion[ 3 ] ];
+        };
+
+        /**
+         * Left multiple two quaternion.
+         *
+         * Is's used to combine two rotating quaternion into one.
+         */
+        var leftMulQuaternion = function( q1, q2 ) {
+            return [
+                ( q1[ 0 ] * q2[ 0 ] - q1[ 1 ] * q2[ 1 ] - q1[ 2 ] * q2[ 2 ] - q1[ 3 ] * q2[ 3 ] ),
+                ( q1[ 1 ] * q2[ 0 ] + q1[ 0 ] * q2[ 1 ] - q1[ 3 ] * q2[ 2 ] + q1[ 2 ] * q2[ 3 ] ),
+                ( q1[ 2 ] * q2[ 0 ] + q1[ 3 ] * q2[ 1 ] + q1[ 0 ] * q2[ 2 ] - q1[ 1 ] * q2[ 3 ] ),
+                ( q1[ 3 ] * q2[ 0 ] - q1[ 2 ] * q2[ 1 ] + q1[ 1 ] * q2[ 2 ] + q1[ 0 ] * q2[ 3 ] )
+            ];
+        };
+
+        /**
+         * Convert a rotation into a quaternion
+         */
+        var rotationToQuaternion = function( baseCoordinate, rotation ) {
+            var order = rotation.order ? rotation.order : "xyz";
+            var axes = order.split( "" );
+            var result = [ 1, 0, 0, 0 ];
+
+            for ( var i = 0; i < axes.length; i++ ) {
+                var deg = rotation[ axes[ i ] ];
+                if ( !deg || ( Math.abs( deg ) < 0.0001 ) ) {
+                    continue;
+                }
+
+                // All CSS rotation is based on the rotated coordinate
+                // So we need to calculate the rotated coordinate first
+                var coordinate = baseCoordinate;
+                if ( i > 0 ) {
+                    coordinate = {
+                        x: rotateByQuaternion( baseCoordinate.x, result ),
+                        y: rotateByQuaternion( baseCoordinate.y, result ),
+                        z: rotateByQuaternion( baseCoordinate.z, result )
+                    };
+                }
+
+                result = leftMulQuaternion(
+                    makeQuaternion( coordinate[ axes[ i ] ], deg ),
+                    result );
+
+            }
+
+            return result;
+        };
+
+        /**
+         * Rotate a vector by a quaternion.
+         */
+        var rotateByQuaternion = function( vec, quaternion ) {
+            var q = makeQuaternion( vec );
+
+            q = leftMulQuaternion(
+                leftMulQuaternion( quaternion, q ),
+                conjugateQuaternion( quaternion ) );
+
+            return quaternionToVector( q );
+        };
+
+        /**
+         * Rotate a vector by rotaion sequence.
+         */
+        var rotateVector = function( baseCoordinate, vec, rotation ) {
+            var quaternion = rotationToQuaternion( baseCoordinate, rotation );
+
+            return rotateByQuaternion( vec, quaternion );
+        };
+
+        /**
+         * Given a rotation, return the rotationed coordinate
+         */
+        var rotateCoordinate = function( coordinate, rotation ) {
+            var quaternion = rotationToQuaternion( coordinate, rotation );
+
+            return {
+                x: rotateByQuaternion( coordinate.x, quaternion ),
+                y: rotateByQuaternion( coordinate.y, quaternion ),
+                z: rotateByQuaternion( coordinate.z, quaternion )
+            };
+        };
+
+        /**
+         * Return the angle between two vector.
+         *
+         * The axis is used to determine the rotation direction.
+         */
+        var angleBetweenTwoVector = function( axis, vec1, vec2 ) {
+            var vecLen1 = vectorLength( vec1 );
+            var vecLen2 = vectorLength( vec2 );
+
+            if ( !vecLen1 || !vecLen2 ) {
+                return 0;
+            }
+
+            var cos = vectorDotProd( vec1, vec2 ) / vecLen1 / vecLen2 ;
+            var angle = Math.acos( cos ) * 180 / Math.PI;
+
+            if ( tripleProduct( vec1, vec2, axis ) > 0 ) {
+                return angle;
+            } else {
+                return -angle;
+            }
+        };
+
+        /**
+         * Return the angle between a vector and a plane.
+         *
+         * The plane is determined by an axis and a vector on the plane.
+         */
+        var angleBetweenPlaneAndVector = function( axis, planeVec, rotatedVec ) {
+            var norm = vectorCrossProd( axis, planeVec );
+
+            if ( isZeroVector( norm ) ) {
+                return 0;
+            }
+
+            return 90 - angleBetweenTwoVector( axis, rotatedVec, norm );
+        };
+
+        /**
+         * Calculated a order specified rotation sequence to
+         * transform from the world coordinate to required coordinate.
+         */
+        var coordinateToOrderedRotation = function( coordinate, order ) {
+            var axis0 = order[ 0 ];
+            var axis1 = order[ 1 ];
+            var axis2 = order[ 2 ];
+            var reversedOrder = order.split( "" ).reverse().join( "" );
+
+            var rotate2 = angleBetweenPlaneAndVector(
+                coordinate[ axis2 ],
+                worldUnitCoordinate[ axis0 ],
+                coordinate[ axis0 ] );
+
+            // The r2 is the reverse of rotate for axis2
+            // The coordinate1 is the coordinate before rotate of axis2
+            var r2 = { order: reversedOrder };
+            r2[ axis2 ] = -rotate2;
+
+            var coordinate1 = rotateCoordinate( coordinate, r2 );
+
+            // Calculate the rotation for axis1
+            var rotate1 = angleBetweenTwoVector(
+                coordinate1[ axis1 ],
+                worldUnitCoordinate[ axis0 ],
+                coordinate1[ axis0 ] );
+
+            // Calculate the rotation for axis0
+            var rotate0 = angleBetweenTwoVector(
+                worldUnitCoordinate[ axis0 ],
+                worldUnitCoordinate[ axis1 ],
+                coordinate1[ axis1 ] );
+
+            var rotation = { };
+            rotation.order = order;
+            rotation[ axis0 ] = roundNumber( rotate0 );
+            rotation[ axis1 ] = roundNumber( rotate1 );
+            rotation[ axis2 ] = roundNumber( rotate2 );
+
+            return rotation;
+        };
+
+        /**
+         * Returns the possible rotations from unit coordinate
+         * to specified coordinate.
+         */
+        var possibleRotations = function( coordinate ) {
+            var orders = [ "xyz", "xzy", "yxz", "yzx", "zxy", "zyx" ];
+            var rotations = [ ];
+
+            for ( var i = 0; i < orders.length; ++i ) {
+                rotations.push(
+                    coordinateToOrderedRotation( coordinate, orders[ i ] )
+                );
+            }
+
+            return rotations;
+        };
+
+        /**
+         * Calculate a degree which in range (-180, 180] of baseDeg
+         */
+        var nearestAngle = function( baseDeg, deg ) {
+            while ( deg > baseDeg + 180 ) {
+                deg -= 360;
+            }
+
+            while ( deg < baseDeg - 180 ) {
+                deg += 360;
+            }
+
+            return deg;
+        };
+
+        /**
+         * Given a base rotation and multiple rotations, return the best one.
+         *
+         * The best one is the one has least rotate from base.
+         */
+        var bestRotation = function( baseRotate, rotations ) {
+            var bestScore;
+            var bestRotation;
+
+            for ( var i = 0; i < rotations.length; ++i ) {
+                var rotation = {
+                    order: rotations[ i ].order,
+                    x: nearestAngle( baseRotate.x, rotations[ i ].x ),
+                    y: nearestAngle( baseRotate.y, rotations[ i ].y ),
+                    z: nearestAngle( baseRotate.z, rotations[ i ].z )
+                };
+
+                var score = Math.abs( rotation.x - baseRotate.x ) +
+                    Math.abs( rotation.y - baseRotate.y ) +
+                    Math.abs( rotation.z - baseRotate.z );
+
+                if ( !i || ( score < bestScore ) ) {
+                    bestScore = score;
+                    bestRotation = rotation;
+                }
+            }
+
+            return bestRotation;
+        };
+
+        /**
+         * Given a coordinate, return the best rotation to achieve it.
+         *
+         * The baseRotate is used to select the near rotation from it.
+         */
+        var coordinateToRotation = function( baseRotate, coordinate ) {
+            var rotations = possibleRotations( coordinate );
+
+            return bestRotation( baseRotate, rotations );
+        };
+
+        /**
+         * Apply a relative rotation to the base rotation.
+         *
+         * Calculate the coordinate after the rotation on each axis,
+         * and finally find out a one step rotation has the effect
+         * of two rotation.
+         *
+         * If there're multiple way to accomplish, select the one
+         * that is nearest to the base.
+         *
+         * Return one rotation has the same effect.
+         */
+        var combineRotations = function( rotations ) {
+
+            // No rotation
+            if ( rotations.length <= 0 ) {
+                return { x:0, y:0, z:0, order:"xyz" };
+            }
+
+            // Find out the base coordinate
+            var coordinate = worldUnitCoordinate;
+
+            // One by one apply rotations in order
+            for ( var i = 0; i < rotations.length; i++ ) {
+                coordinate = rotateCoordinate( coordinate, rotations[ i ] );
+            }
+
+            // Calculate one rotation from unit coordinate to rotated
+            // coordinate.  Because there're multiple possibles,
+            // select the one nearest to the base
+            var rotate = coordinateToRotation( rotations[ 0 ], coordinate );
+
+            return rotate;
+        };
+
+        var translateRelative = function( relative, prevRotation ) {
+            var result = rotateVector(
+                worldUnitCoordinate, relative, prevRotation );
+            result.rotate = combineRotations(
+                [ prevRotation, relative.rotate ] );
+
+            return result;
+        };
+
+        var lib = {
+            translateRelative: translateRelative
+        };
+
+        roots[ "impress-root-" + rootId ] = lib;
+        return lib;
+    };
+
+    // Let impress core know about the existence of this library
+    window.impress.addLibraryFactory( { rotation: libraryFactory } );
+
+} )( document, window );
+
 /**
  * Autoplay plugin - Automatically advance slideshow after N seconds
  *
@@ -1520,7 +1981,6 @@
         root = event.target;
         canvas = root.firstElementChild;
         var gc = api.lib.gc;
-        var util = api.lib.util;
 
         gc.addEventListener( document, "keydown", function( event ) {
 
@@ -1595,7 +2055,7 @@
               i--;
               while ( i >= 0 ) {
                 var newElement = element.cloneNode( false );
-                newElement.innerHTML = markdown.toHTML( slides[ i ] );
+                newElement.innerHTML = markdown.toHTML( slides[ i ], dialect );
                 element.parentNode.insertBefore( newElement, element );
                 element = newElement;
                 i--;
@@ -2081,6 +2541,20 @@
             'useAMPM': false
         };
         break;
+    case 'zh-CN':
+    case 'zh-cn':
+        lang = {
+            'noNotes': '<div class="noNotes">当前帧没有备注</div>',
+            'restart': '重新开始',
+            'clickToOpen': '点击以打开演讲者控制界面',
+            'prev': '上一帧',
+            'next': '下一帧',
+            'loading': '加载中',
+            'ready': '就绪',
+            'moving': '移动中',
+            'useAMPM': false
+        };
+        break;
     case 'en': // jshint ignore:line
     default : // jshint ignore:line
         lang = {
@@ -2211,7 +2685,7 @@
                 var preSrc = baseURL + '#' + nextStep().id;
                 var slideView = consoleWindow.document.getElementById( 'slideView' );
 
-                // Setting them when they are already set causes glithes in Firefox, so check first:
+                // Setting when already set causes glitches in Firefox, so check first:
                 if ( slideView.src !== slideSrc ) {
                     slideView.src = slideSrc;
                 }
@@ -2248,7 +2722,7 @@
                 var preSrc = baseURL + '#' + nextStep().id;
                 var slideView = consoleWindow.document.getElementById( 'slideView' );
 
-                // Setting them when they are already set causes glithes in Firefox, so check first:
+                // Setting when already set causes glitches in Firefox, so check first:
                 if ( slideView.src !== slideSrc ) {
                     slideView.src = slideSrc;
                 }
@@ -3438,7 +3912,9 @@
             // Omit steps that are listed as hidden from select widget
             if ( hideSteps.indexOf( steps[ i ] ) < 0 ) {
                 options = options + '<option value="' + steps[ i ].id + '">' + // jshint ignore:line
-                                    steps[ i ].id + '</option>' + '\n'; // jshint ignore:line
+							(
+								steps[ i ].title ? steps[ i ].title : steps[ i ].id
+							) + '</option>' + '\n';
             }
         }
         return options;
@@ -3624,34 +4100,11 @@
 ( function( document, window ) {
     "use strict";
 
+    var api;
     var startingState = {};
 
-    /**
-     * Copied from core impress.js. We currently lack a library mechanism to
-     * to share utility functions like this.
-     */
-    var toNumber = function( numeric, fallback ) {
-        return isNaN( numeric ) ? ( fallback || 0 ) : Number( numeric );
-    };
-
-    /**
-     * Extends toNumber() to correctly compute also relative-to-screen-size values 5w and 5h.
-     *
-     * Returns the computed value in pixels with w/h postfix removed.
-     */
-    var toNumberAdvanced = function( numeric, fallback ) {
-        if ( typeof numeric !== "string" ) {
-            return toNumber( numeric, fallback );
-        }
-        var ratio = numeric.match( /^([+-]*[\d\.]+)([wh])$/ );
-        if ( ratio == null ) {
-            return toNumber( numeric, fallback );
-        } else {
-            var value = parseFloat( ratio[ 1 ] );
-            var multiplier = ratio[ 2 ] === "w" ? window.innerWidth : window.innerHeight;
-            return value * multiplier;
-        }
-    };
+    var toNumber;
+    var toNumberAdvanced;
 
     var computeRelativePositions = function( el, prev ) {
         var data = el.dataset;
@@ -3659,20 +4112,64 @@
         if ( !prev ) {
 
             // For the first step, inherit these defaults
-            prev = { x:0, y:0, z:0, relative: { x:0, y:0, z:0 } };
+            prev = {
+                x:0, y:0, z:0,
+                rotate: { x:0, y:0, z:0, order:"xyz" },
+                relative: {
+                    position: "absolute",
+                    x:0, y:0, z:0,
+                    rotate: { x:0, y:0, z:0, order:"xyz" }
+                }
+            };
         }
 
+        var ref = prev;
         if ( data.relTo ) {
 
-            var ref = document.getElementById( data.relTo );
+            ref = document.getElementById( data.relTo );
             if ( ref ) {
 
                 // Test, if it is a previous step that already has some assigned position data
                 if ( el.compareDocumentPosition( ref ) & Node.DOCUMENT_POSITION_PRECEDING ) {
-                    prev.x = toNumber( ref.getAttribute( "data-x" ) );
-                    prev.y = toNumber( ref.getAttribute( "data-y" ) );
-                    prev.z = toNumber( ref.getAttribute( "data-z" ) );
-                    prev.relative = {};
+                    prev.x = toNumberAdvanced( ref.getAttribute( "data-x" ) );
+                    prev.y = toNumberAdvanced( ref.getAttribute( "data-y" ) );
+                    prev.z = toNumberAdvanced( ref.getAttribute( "data-z" ) );
+
+                    var prevPosition = ref.getAttribute( "data-rel-position" ) || "absolute";
+
+                    if ( prevPosition !== "relative" ) {
+
+                        // For compatibility with the old behavior, doesn't inherit otherthings,
+                        // just like a reset.
+                        prev.rotate = { x:0, y:0, z:0, order: "xyz" };
+                        prev.relative = {
+                            position: "absolute",
+                            x:0, y:0, z:0,
+                            rotate: { x:0, y:0, z:0, order:"xyz" }
+                        };
+                    } else {
+
+                        // For data-rel-position="relative", inherit all
+                        prev.rotate.y = toNumber( ref.getAttribute( "data-rotate-y" ) );
+                        prev.rotate.x = toNumber( ref.getAttribute( "data-rotate-x" ) );
+                        prev.rotate.z = toNumber(
+                            ref.getAttribute( "data-rotate-z" ) ||
+                            ref.getAttribute( "data-rotate" ) );
+
+                        // We also inherit relatives from relTo slide
+                        prev.relative = {
+                            position: prevPosition,
+                            x: toNumberAdvanced( ref.getAttribute( "data-rel-x" ), 0 ),
+                            y: toNumberAdvanced( ref.getAttribute( "data-rel-y" ), 0 ),
+                            z: toNumberAdvanced( ref.getAttribute( "data-rel-z" ), 0 ),
+                            rotate: {
+                                x: toNumberAdvanced( ref.getAttribute( "data-rel-rotate-x" ), 0 ),
+                                y: toNumberAdvanced( ref.getAttribute( "data-rel-rotate-y" ), 0 ),
+                                z: toNumberAdvanced( ref.getAttribute( "data-rel-rotate-z" ), 0 ),
+                                order: ( ref.getAttribute( "data-rel-rotate-order" ) ||  "xyz" )
+                            }
+                        };
+                    }
                 } else {
                     window.console.error(
                         "impress.js rel plugin: Step \"" + data.relTo + "\" is not defined " +
@@ -3693,39 +4190,104 @@
             }
         }
 
+        // While ``data-rel-reset="relative"`` or just ``data-rel-reset``,
+        // ``data-rel-x/y/z`` and ``data-rel-rotate-x/y/z`` will have default value of 0,
+        // instead of inherit from previous slide.
+        //
+        // If ``data-rel-reset="all"``, ``data-rotate-*`` are not inherited from previous slide too.
+        // So ``data-rel-reset="all" data-rotate-x="90"`` means
+        // ``data-rotate-x="90" data-rotate-y="0" data-rotate-z="0"``, we doesn't need to
+        // bother clearing all unneeded attributes.
+
+        var inheritRotation = true;
+        if ( el.hasAttribute( "data-rel-reset" ) ) {
+
+            // Don't inherit from prev, just use the relative setting for current element
+            prev.relative = {
+                position: prev.relative.position,
+                x:0, y:0, z:0,
+                rotate: { x:0, y:0, z:0, order: "xyz" } };
+
+            if ( data.relReset === "all" ) {
+                inheritRotation = false;
+            }
+        }
+
         var step = {
-                x: toNumber( data.x, prev.x ),
-                y: toNumber( data.y, prev.y ),
-                z: toNumber( data.z, prev.z ),
+                x: toNumberAdvanced( data.x, prev.x ),
+                y: toNumberAdvanced( data.y, prev.y ),
+                z: toNumberAdvanced( data.z, prev.z ),
+                rotate: {
+                    x: toNumber( data.rotateX, 0 ),
+                    y: toNumber( data.rotateY, 0 ),
+                    z: toNumber( data.rotateZ || data.rotate, 0 ),
+                    order: data.rotateOrder || "xyz"
+                },
                 relative: {
+                    position: data.relPosition || prev.relative.position,
                     x: toNumberAdvanced( data.relX, prev.relative.x ),
                     y: toNumberAdvanced( data.relY, prev.relative.y ),
-                    z: toNumberAdvanced( data.relZ, prev.relative.z )
+                    z: toNumberAdvanced( data.relZ, prev.relative.z ),
+                    rotate: {
+                        x: toNumber( data.relRotateX, prev.relative.rotate.x ),
+                        y: toNumber( data.relRotateY, prev.relative.rotate.y ),
+                        z: toNumber( data.relRotateZ, prev.relative.rotate.z ),
+                        order: data.rotateOrder || "xyz"
+                    }
                 }
             };
 
+        // The final relatives maybe or maybe not the same with orignal data-rel-*
+        var relative = step.relative;
+
+        if ( step.relative.position === "relative" && inheritRotation ) {
+
+            // Calculate relatives based on previous slide
+            relative = api.lib.rotation.translateRelative(
+                step.relative, prev.rotate );
+
+            // Convert rotations to values that works with step.rotate
+            relative.rotate.x -= step.rotate.x;
+            relative.rotate.y -= step.rotate.y;
+            relative.rotate.z -= step.rotate.z;
+        }
+
         // Relative position is ignored/zero if absolute is given.
         // Note that this also has the effect of resetting any inherited relative values.
         if ( data.x !== undefined ) {
-            step.relative.x = 0;
+            relative.x = step.relative.x = 0;
         }
         if ( data.y !== undefined ) {
-            step.relative.y = 0;
+            relative.y = step.relative.y = 0;
         }
         if ( data.z !== undefined ) {
-            step.relative.z = 0;
+            relative.z = step.relative.z = 0;
+        }
+        if ( data.rotateX !== undefined || !inheritRotation ) {
+            relative.rotate.x = step.relative.rotate.x = 0;
+        }
+        if ( data.rotateY !== undefined || !inheritRotation ) {
+            relative.rotate.y = step.relative.rotate.y = 0;
+        }
+        if ( data.rotateZ !== undefined || data.rotate !== undefined || !inheritRotation ) {
+            relative.rotate.z = step.relative.rotate.z = 0;
         }
 
-        // Apply relative position to absolute position, if non-zero
-        // Note that at this point, the relative values contain a number value of pixels.
-        step.x = step.x + step.relative.x;
-        step.y = step.y + step.relative.y;
-        step.z = step.z + step.relative.z;
+        step.x = step.x + relative.x;
+        step.y = step.y + relative.y;
+        step.z = step.z + relative.z;
+        step.rotate.x = step.rotate.x + relative.rotate.x;
+        step.rotate.y = step.rotate.y + relative.rotate.y;
+        step.rotate.z = step.rotate.z + relative.rotate.z;
 
         return step;
     };
 
-    var rel = function( root ) {
+    var rel = function( root, impressApi ) {
+        api = impressApi;
+        toNumber = api.lib.util.toNumber;
+        toNumberAdvanced = api.lib.util.toNumberAdvanced;
+
         var steps = root.querySelectorAll( ".step" );
         var prev;
         startingState[ root.id ] = [];
@@ -3738,7 +4300,16 @@
                 z: el.getAttribute( "data-z" ),
                 relX: el.getAttribute( "data-rel-x" ),
                 relY: el.getAttribute( "data-rel-y" ),
-                relZ: el.getAttribute( "data-rel-z" )
+                relZ: el.getAttribute( "data-rel-z" ),
+                rotateX: el.getAttribute( "data-rotate-x" ),
+                rotateY: el.getAttribute( "data-rotate-y" ),
+                rotateZ: el.getAttribute( "data-rotate-z" ),
+                rotate: el.getAttribute( "data-rotate" ),
+                relRotateX: el.getAttribute( "data-rel-rotate-x" ),
+                relRotateY: el.getAttribute( "data-rel-rotate-y" ),
+                relRotateZ: el.getAttribute( "data-rel-rotate-z" ),
+                relPosition: el.getAttribute( "data-rel-position" ),
+                rotateOrder: el.getAttribute( "data-rotate-order" )
             } );
             var step = computeRelativePositions( el, prev );
 
@@ -3746,6 +4317,17 @@
             el.setAttribute( "data-x", step.x );
             el.setAttribute( "data-y", step.y );
             el.setAttribute( "data-z", step.z );
+            el.setAttribute( "data-rotate-x", step.rotate.x );
+            el.setAttribute( "data-rotate-y", step.rotate.y );
+            el.setAttribute( "data-rotate-z", step.rotate.z );
+            el.setAttribute( "data-rotate-order", step.rotate.order );
+            el.setAttribute( "data-rel-position", step.relative.position );
+            el.setAttribute( "data-rel-x", step.relative.x );
+            el.setAttribute( "data-rel-y", step.relative.y );
+            el.setAttribute( "data-rel-z", step.relative.z );
+            el.setAttribute( "data-rel-rotate-x", step.relative.rotate.x );
+            el.setAttribute( "data-rel-rotate-y", step.relative.rotate.y );
+            el.setAttribute( "data-rel-rotate-z", step.relative.rotate.z );
             prev = step;
         }
     };
@@ -3759,28 +4341,27 @@
         event.detail.api.lib.gc.pushCallback( function() {
             var steps = startingState[ root.id ];
             var step;
+            var attrs = [
+                [ "x", "relX" ],
+                [ "y", "relY" ],
+                [ "z", "relZ" ],
+                [ "rotate-x", "relRotateX" ],
+                [ "rotate-y", "relRotateY" ],
+                [ "rotate-z", "relRotateZ" ],
+                [ "rotate-order", "relRotateOrder" ]
+            ];
+
             while ( step = steps.pop() ) {
 
                 // Reset x/y/z in cases where this plugin has changed it.
-                if ( step.relX !== null ) {
-                    if ( step.x === null ) {
-                        step.el.removeAttribute( "data-x" );
-                    } else {
-                        step.el.setAttribute( "data-x", step.x );
-                    }
-                }
-                if ( step.relY !== null ) {
-                    if ( step.y === null ) {
-                        step.el.removeAttribute( "data-y" );
-                    } else {
-                        step.el.setAttribute( "data-y", step.y );
-                    }
-                }
-                if ( step.relZ !== null ) {
-                    if ( step.z === null ) {
-                        step.el.removeAttribute( "data-z" );
-                    } else {
-                        step.el.setAttribute( "data-z", step.z );
+                for ( var i = 0; i < attrs.length; i++ ) {
+                    if ( step[ attrs[ i ][ 1 ] ] !== null ) {
+                        if ( step[ attrs[ i ][ 0 ] ] === null ) {
+                            step.el.removeAttribute( "data-" + attrs[ i ][ 0 ] );
+                        } else {
+                            step.el.setAttribute(
+                                "data-" + attrs[ i ][ 0 ], step[ attrs[ i ][ 0 ] ] );
+                        }
                     }
                 }
             }
@@ -4009,12 +4590,28 @@
 
     var showSubstepIfAny = function( step ) {
         var substeps = step.querySelectorAll( ".substep" );
-        var visible = step.querySelectorAll( ".substep-visible" );
         if ( substeps.length > 0 ) {
-            return showSubstep( substeps, visible );
+            var sorted = sortSubsteps( substeps );
+            var visible = step.querySelectorAll( ".substep-visible" );
+            return showSubstep( sorted, visible );
         }
     };
 
+    var sortSubsteps = function( substepNodeList ) {
+        var substeps = Array.from( substepNodeList );
+        var sorted = substeps
+            .filter( el => el.dataset.substepOrder )
+            .sort( ( a, b ) => {
+                var orderA = a.dataset.substepOrder;
+                var orderB = b.dataset.substepOrder;
+                return parseInt( orderA ) - parseInt( orderB );
+            } )
+            .concat( substeps.filter( el => {
+                return el.dataset.substepOrder === undefined;
+            } ) );
+        return sorted;
+    };
+
     var showSubstep = function( substeps, visible ) {
         if ( visible.length < substeps.length ) {
             for ( var i = 0; i < substeps.length; i++ ) {
@@ -4030,8 +4627,9 @@
     var hideSubstepIfAny = function( step ) {
         var substeps = step.querySelectorAll( ".substep" );
         var visible = step.querySelectorAll( ".substep-visible" );
+        var sorted = sortSubsteps( visible );
         if ( substeps.length > 0 ) {
-            return hideSubstep( visible );
+            return hideSubstep( sorted );
         }
     };
 
diff --git a/karma.conf.js b/karma.conf.js
index 0848e3c..297892f 100644
--- a/karma.conf.js
+++ b/karma.conf.js
@@ -8,6 +8,7 @@ module.exports = function(config) {
     // base path that will be used to resolve all patterns (eg. files, exclude)
     basePath: '',
 
+    hostname: '127.0.0.1',
 
     // frameworks to use
     // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
@@ -22,11 +23,16 @@ module.exports = function(config) {
       "test/core_tests.js",
       "test/non_default.js",
       "src/plugins/navigation/navigation_tests.js",
+      "test/plugins/rel/relative_to_screen_size_tests.js",
+      "test/plugins/rel/rotation_tests.js",
+      "test/plugins/rel/padding_tests.js",
+      "test/plugins/rel/rel_to_tests.js",
       // Presentation files, for the iframe
       {pattern: "test/*.html", watched: true, served: true, included: false},
       {pattern: "test/plugins/*/*.html", watched: true, served: true, included: false},
       // JS files for iframe
       {pattern: "js/impress.js", watched: true, served: true, included: false},
+      {pattern: "node_modules/qunit-assert-close/qunit-assert-close.js", watched: false, served: true, included: true},
       {pattern: "node_modules/syn/dist/global/syn.js", watched: false, served: true, included: false}
     ],
 
diff --git a/package-lock.json b/package-lock.json
index 522c7c4..81bbf6d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,8 +1,6405 @@
 {
   "name": "impress.js",
-  "version": "1.0.0",
-  "lockfileVersion": 1,
+  "version": "1.1.0",
+  "lockfileVersion": 2,
   "requires": true,
+  "packages": {
+    "": {
+      "name": "impress.js",
+      "version": "1.1.0",
+      "license": "MIT",
+      "devDependencies": {
+        "eslint": "^6.8.0",
+        "jscs": "^3.0.7",
+        "jshint": "^2.11.0",
+        "karma": "^4.4.1",
+        "karma-chrome-launcher": "^3.1.0",
+        "karma-firefox-launcher": "^1.3.0",
+        "karma-qunit": "^4.0.0",
+        "ls": "^0.2.1",
+        "puppeteer": "^2.1.1",
+        "qunit": "^2.9.3",
+        "qunit-assert-close": "^2.1.2",
+        "syn": "^0.14.1",
+        "terser": "^4.6.7"
+      }
+    },
+    "node_modules/@babel/code-frame": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
+      "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
+      "dev": true,
+      "dependencies": {
+        "@babel/highlight": "^7.8.3"
+      }
+    },
+    "node_modules/@babel/helper-validator-identifier": {
+      "version": "7.9.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.0.tgz",
+      "integrity": "sha512-6G8bQKjOh+of4PV/ThDm/rRqlU7+IGoJuofpagU5GlEl29Vv0RGqqt86ZGRV8ZuSOY3o+8yXl5y782SMcG7SHw==",
+      "dev": true
+    },
+    "node_modules/@babel/highlight": {
+      "version": "7.9.0",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz",
+      "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-validator-identifier": "^7.9.0",
+        "chalk": "^2.0.0",
+        "js-tokens": "^4.0.0"
+      }
+    },
+    "node_modules/@types/color-name": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
+      "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
+      "dev": true
+    },
+    "node_modules/@types/mime-types": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.0.tgz",
+      "integrity": "sha1-nKUs2jY/aZxpRmwqbM2q2RPqenM=",
+      "dev": true
+    },
+    "node_modules/accepts": {
+      "version": "1.3.7",
+      "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
+      "integrity": "sha1-UxvHJlF6OytB+FACHGzBXqq1B80=",
+      "dev": true,
+      "dependencies": {
+        "mime-types": "~2.1.24",
+        "negotiator": "0.6.2"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/acorn": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz",
+      "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==",
+      "dev": true,
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/acorn-jsx": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz",
+      "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==",
+      "dev": true,
+      "peerDependencies": {
+        "acorn": "^6.0.0 || ^7.0.0"
+      }
+    },
+    "node_modules/after": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
+      "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=",
+      "dev": true
+    },
+    "node_modules/agent-base": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz",
+      "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==",
+      "dev": true,
+      "engines": {
+        "node": ">= 6.0.0"
+      }
+    },
+    "node_modules/ajv": {
+      "version": "6.12.0",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz",
+      "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==",
+      "dev": true,
+      "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"
+      }
+    },
+    "node_modules/ansi-escapes": {
+      "version": "4.3.1",
+      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz",
+      "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==",
+      "dev": true,
+      "dependencies": {
+        "type-fest": "^0.11.0"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/ansi-escapes/node_modules/type-fest": {
+      "version": "0.11.0",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz",
+      "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/ansi-regex": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+      "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^1.9.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/anymatch": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
+      "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
+      "dev": true,
+      "dependencies": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/argparse": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+      "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=",
+      "dev": true,
+      "dependencies": {
+        "sprintf-js": "~1.0.2"
+      }
+    },
+    "node_modules/arr-diff": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
+      "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "arr-flatten": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/arr-flatten": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+      "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/arr-union": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+      "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/array-unique": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
+      "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/arraybuffer.slice": {
+      "version": "0.0.7",
+      "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
+      "integrity": "sha1-O7xCdd1YTMGxCAm4nU6LY6aednU=",
+      "dev": true
+    },
+    "node_modules/assign-symbols": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+      "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/astral-regex": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
+      "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/async": {
+      "version": "2.6.3",
+      "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
+      "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
+      "dev": true,
+      "dependencies": {
+        "lodash": "^4.17.14"
+      }
+    },
+    "node_modules/async-each": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
+      "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/async-limiter": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
+      "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
+      "dev": true
+    },
+    "node_modules/async/node_modules/lodash": {
+      "version": "4.17.15",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+      "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+      "dev": true
+    },
+    "node_modules/atob": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+      "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+      "dev": true,
+      "peer": true,
+      "bin": {
+        "atob": "bin/atob.js"
+      },
+      "engines": {
+        "node": ">= 4.5.0"
+      }
+    },
+    "node_modules/babel-runtime": {
+      "version": "6.26.0",
+      "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+      "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+      "dev": true,
+      "dependencies": {
+        "core-js": "^2.4.0",
+        "regenerator-runtime": "^0.11.0"
+      }
+    },
+    "node_modules/babylon": {
+      "version": "6.18.0",
+      "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
+      "integrity": "sha1-ry87iPpvXB5MY00aD46sT1WzleM=",
+      "dev": true,
+      "bin": {
+        "babylon": "bin/babylon.js"
+      }
+    },
+    "node_modules/backo2": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
+      "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=",
+      "dev": true
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+      "dev": true
+    },
+    "node_modules/base": {
+      "version": "0.11.2",
+      "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+      "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
+      "dev": true,
+      "peer": true,
+      "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"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/base/node_modules/define-property": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+      "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-descriptor": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/base/node_modules/isobject": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+      "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/base64-arraybuffer": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
+      "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6.0"
+      }
+    },
+    "node_modules/base64id": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz",
+      "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
+    "node_modules/better-assert": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz",
+      "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=",
+      "dev": true,
+      "dependencies": {
+        "callsite": "1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/binary-extensions": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz",
+      "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/bindings": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
+      "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
+      "dev": true,
+      "optional": true,
+      "peer": true,
+      "dependencies": {
+        "file-uri-to-path": "1.0.0"
+      }
+    },
+    "node_modules/blob": {
+      "version": "0.0.5",
+      "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz",
+      "integrity": "sha1-1oDu7yX4zZGtUz9bAe7UjmTK9oM=",
+      "dev": true
+    },
+    "node_modules/bluebird": {
+      "version": "3.7.2",
+      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+      "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
+      "dev": true
+    },
+    "node_modules/body-parser": {
+      "version": "1.19.0",
+      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
+      "integrity": "sha1-lrJwnlfJxOCab9Zqj9l5hE9p8Io=",
+      "dev": true,
+      "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"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/body-parser/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/body-parser/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+      "dev": true
+    },
+    "node_modules/brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/braces": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+      "dev": true,
+      "dependencies": {
+        "fill-range": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/buffer-alloc": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
+      "integrity": "sha1-iQ3ZDZI6hz4I4Q5f1RpX5bfM4Ow=",
+      "dev": true,
+      "dependencies": {
+        "buffer-alloc-unsafe": "^1.1.0",
+        "buffer-fill": "^1.0.0"
+      }
+    },
+    "node_modules/buffer-alloc-unsafe": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz",
+      "integrity": "sha1-vX3CauKXLQ7aJTvgYdupkjScGfA=",
+      "dev": true
+    },
+    "node_modules/buffer-crc32": {
+      "version": "0.2.13",
+      "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+      "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
+      "dev": true,
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/buffer-fill": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
+      "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=",
+      "dev": true
+    },
+    "node_modules/buffer-from": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+      "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
+      "dev": true
+    },
+    "node_modules/bytes": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
+      "integrity": "sha1-9s95M6Ng4FiPqf3oVlHNx/gF0fY=",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/cache-base": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+      "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
+      "dev": true,
+      "peer": true,
+      "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"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/cache-base/node_modules/isobject": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+      "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/callsite": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
+      "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=",
+      "dev": true,
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/callsites": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/chardet": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
+      "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
+      "dev": true
+    },
+    "node_modules/chokidar": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz",
+      "integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==",
+      "dev": true,
+      "dependencies": {
+        "anymatch": "~3.1.1",
+        "braces": "~3.0.2",
+        "fsevents": "~2.1.2",
+        "glob-parent": "~5.1.0",
+        "is-binary-path": "~2.1.0",
+        "is-glob": "~4.0.1",
+        "normalize-path": "~3.0.0",
+        "readdirp": "~3.3.0"
+      },
+      "engines": {
+        "node": ">= 8.10.0"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.1.2"
+      }
+    },
+    "node_modules/class-utils": {
+      "version": "0.3.6",
+      "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+      "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "arr-union": "^3.1.0",
+        "define-property": "^0.2.5",
+        "isobject": "^3.0.0",
+        "static-extend": "^0.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/class-utils/node_modules/define-property": {
+      "version": "0.2.5",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+      "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-descriptor": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/class-utils/node_modules/is-accessor-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+      "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/class-utils/node_modules/is-data-descriptor": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+      "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/class-utils/node_modules/is-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+      "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-accessor-descriptor": "^0.1.6",
+        "is-data-descriptor": "^0.1.4",
+        "kind-of": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/class-utils/node_modules/is-descriptor/node_modules/kind-of": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+      "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/class-utils/node_modules/isobject": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+      "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/cli": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz",
+      "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=",
+      "dev": true,
+      "dependencies": {
+        "exit": "0.1.2",
+        "glob": "^7.1.1"
+      },
+      "engines": {
+        "node": ">=0.2.5"
+      }
+    },
+    "node_modules/cli-cursor": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
+      "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
+      "dev": true,
+      "dependencies": {
+        "restore-cursor": "^3.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/cli-table": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz",
+      "integrity": "sha1-9TsFJmqLGguTSz0IIebi3FkUriM=",
+      "dev": true,
+      "dependencies": {
+        "colors": "1.0.3"
+      },
+      "engines": {
+        "node": ">= 0.2.0"
+      }
+    },
+    "node_modules/cli-table/node_modules/colors": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
+      "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.1.90"
+      }
+    },
+    "node_modules/cli-width": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
+      "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
+      "dev": true
+    },
+    "node_modules/collection-visit": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+      "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "map-visit": "^1.0.0",
+        "object-visit": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "1.1.3"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+      "dev": true
+    },
+    "node_modules/colors": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
+      "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.1.90"
+      }
+    },
+    "node_modules/commander": {
+      "version": "2.12.2",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz",
+      "integrity": "sha512-BFnaq5ZOGcDN7FlrtBT4xxkgIToalIIxwjxLWVJ8bGTpe1LroqMiqQXdA7ygc7CRvaYS+9zfPGFnJqFSayx+AA==",
+      "dev": true
+    },
+    "node_modules/comment-parser": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-0.3.2.tgz",
+      "integrity": "sha1-PAPwd2uGo239mgosl8YwfzMggv4=",
+      "dev": true,
+      "dependencies": {
+        "readable-stream": "^2.0.4"
+      }
+    },
+    "node_modules/component-bind": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",
+      "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=",
+      "dev": true
+    },
+    "node_modules/component-emitter": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
+      "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
+      "dev": true
+    },
+    "node_modules/component-inherit": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",
+      "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=",
+      "dev": true
+    },
+    "node_modules/concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+      "dev": true
+    },
+    "node_modules/concat-stream": {
+      "version": "1.6.2",
+      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+      "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+      "dev": true,
+      "engines": [
+        "node >= 0.8"
+      ],
+      "dependencies": {
+        "buffer-from": "^1.0.0",
+        "inherits": "^2.0.3",
+        "readable-stream": "^2.2.2",
+        "typedarray": "^0.0.6"
+      }
+    },
+    "node_modules/connect": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz",
+      "integrity": "sha1-XUk0iRDKpeB6AYALAw0MNfIEhPg=",
+      "dev": true,
+      "dependencies": {
+        "debug": "2.6.9",
+        "finalhandler": "1.1.2",
+        "parseurl": "~1.3.3",
+        "utils-merge": "1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.10.0"
+      }
+    },
+    "node_modules/connect/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/connect/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+      "dev": true
+    },
+    "node_modules/console-browserify": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
+      "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=",
+      "dev": true,
+      "dependencies": {
+        "date-now": "^0.1.4"
+      }
+    },
+    "node_modules/content-type": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+      "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/cookie": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
+      "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/copy-descriptor": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+      "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/core-js": {
+      "version": "2.6.5",
+      "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.5.tgz",
+      "integrity": "sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A==",
+      "deprecated": "core-js@<3.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Please, upgrade your dependencies to the actual version of core-js.",
+      "dev": true
+    },
+    "node_modules/core-util-is": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+      "dev": true
+    },
+    "node_modules/cross-spawn": {
+      "version": "6.0.5",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+      "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+      "dev": true,
+      "dependencies": {
+        "nice-try": "^1.0.4",
+        "path-key": "^2.0.1",
+        "semver": "^5.5.0",
+        "shebang-command": "^1.2.0",
+        "which": "^1.2.9"
+      },
+      "engines": {
+        "node": ">=4.8"
+      }
+    },
+    "node_modules/cross-spawn/node_modules/semver": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+      "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver"
+      }
+    },
+    "node_modules/cst": {
+      "version": "0.4.10",
+      "resolved": "https://registry.npmjs.org/cst/-/cst-0.4.10.tgz",
+      "integrity": "sha1-nAXIJSkKdi8KhcCqu4wP4DWuhRY=",
+      "dev": true,
+      "dependencies": {
+        "babel-runtime": "^6.9.2",
+        "babylon": "^6.8.1",
+        "source-map-support": "^0.4.0"
+      }
+    },
+    "node_modules/cst/node_modules/source-map": {
+      "version": "0.5.7",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+      "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/cst/node_modules/source-map-support": {
+      "version": "0.4.18",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
+      "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==",
+      "dev": true,
+      "dependencies": {
+        "source-map": "^0.5.6"
+      }
+    },
+    "node_modules/custom-event": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz",
+      "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=",
+      "dev": true
+    },
+    "node_modules/cycle": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz",
+      "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/date-format": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz",
+      "integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==",
+      "dev": true,
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/date-now": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz",
+      "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=",
+      "dev": true
+    },
+    "node_modules/debug": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+      "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+      "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)",
+      "dev": true,
+      "dependencies": {
+        "ms": "^2.1.1"
+      }
+    },
+    "node_modules/decode-uri-component": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
+      "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/deep-equal": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
+      "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=",
+      "dev": true
+    },
+    "node_modules/deep-is": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+      "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
+      "dev": true
+    },
+    "node_modules/define-property": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+      "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-descriptor": "^1.0.2",
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/define-property/node_modules/isobject": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+      "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/depd": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+      "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/detect-file": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-0.1.0.tgz",
+      "integrity": "sha1-STXe39lIhkjgBrASlWbpOGcR6mM=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "fs-exists-sync": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/di": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz",
+      "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=",
+      "dev": true
+    },
+    "node_modules/doctrine": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+      "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+      "dev": true,
+      "dependencies": {
+        "esutils": "^2.0.2"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/dom-serialize": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz",
+      "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=",
+      "dev": true,
+      "dependencies": {
+        "custom-event": "~1.0.0",
+        "ent": "~2.2.0",
+        "extend": "^3.0.0",
+        "void-elements": "^2.0.0"
+      }
+    },
+    "node_modules/dom-serializer": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz",
+      "integrity": "sha1-HsQFnihLq+027sKUHUqXChic58A=",
+      "dev": true,
+      "dependencies": {
+        "domelementtype": "^1.3.0",
+        "entities": "^1.1.1"
+      }
+    },
+    "node_modules/dom-serializer/node_modules/entities": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
+      "integrity": "sha1-vfpzUplmTfr9NFKe1PhSKidf6lY=",
+      "dev": true
+    },
+    "node_modules/domelementtype": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
+      "integrity": "sha1-0EjESzew0Qp/Kj1f7j9DM9eQSB8=",
+      "dev": true
+    },
+    "node_modules/domhandler": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz",
+      "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=",
+      "dev": true,
+      "dependencies": {
+        "domelementtype": "1"
+      }
+    },
+    "node_modules/domutils": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
+      "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=",
+      "dev": true,
+      "dependencies": {
+        "dom-serializer": "0",
+        "domelementtype": "1"
+      }
+    },
+    "node_modules/ee-first": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+      "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
+      "dev": true
+    },
+    "node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true
+    },
+    "node_modules/encodeurl": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+      "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/engine.io": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.1.tgz",
+      "integrity": "sha1-tgKBw1SEpw7gNR6g6/+D7IyVIqI=",
+      "dev": true,
+      "dependencies": {
+        "accepts": "~1.3.4",
+        "base64id": "1.0.0",
+        "cookie": "0.3.1",
+        "debug": "~3.1.0",
+        "engine.io-parser": "~2.1.0",
+        "ws": "~3.3.1"
+      }
+    },
+    "node_modules/engine.io-client": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz",
+      "integrity": "sha1-b1TAR13khxWKGnx30QF4cItq3TY=",
+      "dev": true,
+      "dependencies": {
+        "component-emitter": "1.2.1",
+        "component-inherit": "0.0.3",
+        "debug": "~3.1.0",
+        "engine.io-parser": "~2.1.1",
+        "has-cors": "1.1.0",
+        "indexof": "0.0.1",
+        "parseqs": "0.0.5",
+        "parseuri": "0.0.5",
+        "ws": "~3.3.1",
+        "xmlhttprequest-ssl": "~1.5.4",
+        "yeast": "0.1.2"
+      }
+    },
+    "node_modules/engine.io-client/node_modules/debug": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+      "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/engine.io-client/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+      "dev": true
+    },
+    "node_modules/engine.io-parser": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz",
+      "integrity": "sha1-dXq5cPvy37Mse3SwMyFtVznveaY=",
+      "dev": true,
+      "dependencies": {
+        "after": "0.8.2",
+        "arraybuffer.slice": "~0.0.7",
+        "base64-arraybuffer": "0.1.5",
+        "blob": "0.0.5",
+        "has-binary2": "~1.0.2"
+      }
+    },
+    "node_modules/engine.io/node_modules/debug": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+      "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/engine.io/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+      "dev": true
+    },
+    "node_modules/ensure-posix-path": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/ensure-posix-path/-/ensure-posix-path-1.1.1.tgz",
+      "integrity": "sha512-VWU0/zXzVbeJNXvME/5EmLuEj2TauvoaTz6aFYK1Z92JCBlDlZ3Gu0tuGR42kpW1754ywTs+QB0g5TP0oj9Zaw==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/ent": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz",
+      "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=",
+      "dev": true
+    },
+    "node_modules/entities": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz",
+      "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=",
+      "dev": true
+    },
+    "node_modules/escape-html": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+      "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
+      "dev": true
+    },
+    "node_modules/escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/eslint": {
+      "version": "6.8.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz",
+      "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==",
+      "dev": true,
+      "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"
+      },
+      "bin": {
+        "eslint": "bin/eslint.js"
+      },
+      "engines": {
+        "node": "^8.10.0 || ^10.13.0 || >=11.10.1"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/eslint-scope": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz",
+      "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==",
+      "dev": true,
+      "dependencies": {
+        "esrecurse": "^4.1.0",
+        "estraverse": "^4.1.1"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/eslint-utils": {
+      "version": "1.4.3",
+      "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz",
+      "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==",
+      "dev": true,
+      "dependencies": {
+        "eslint-visitor-keys": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/eslint-visitor-keys": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz",
+      "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/eslint/node_modules/lodash": {
+      "version": "4.17.15",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+      "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+      "dev": true
+    },
+    "node_modules/espree": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz",
+      "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==",
+      "dev": true,
+      "dependencies": {
+        "acorn": "^7.1.1",
+        "acorn-jsx": "^5.2.0",
+        "eslint-visitor-keys": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/esprima": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+      "dev": true,
+      "bin": {
+        "esparse": "bin/esparse.js",
+        "esvalidate": "bin/esvalidate.js"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/esquery": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.2.0.tgz",
+      "integrity": "sha512-weltsSqdeWIX9G2qQZz7KlTRJdkkOCTPgLYJUz1Hacf48R4YOwGPHO3+ORfWedqJKbq5WQmsgK90n+pFLIKt/Q==",
+      "dev": true,
+      "dependencies": {
+        "estraverse": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/esquery/node_modules/estraverse": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.0.0.tgz",
+      "integrity": "sha512-j3acdrMzqrxmJTNj5dbr1YbjacrYgAxVMeF0gK16E3j494mOe7xygM/ZLIguEQ0ETwAg2hlJCtHRGav+y0Ny5A==",
+      "dev": true,
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/esrecurse": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
+      "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
+      "dev": true,
+      "dependencies": {
+        "estraverse": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/estraverse": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
+      "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/esutils": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/eventemitter3": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz",
+      "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==",
+      "dev": true
+    },
+    "node_modules/exists-stat": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/exists-stat/-/exists-stat-1.0.0.tgz",
+      "integrity": "sha1-BmDjUlouidnkRhKUQMJy7foktSk=",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/exit": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
+      "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/expand-brackets": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
+      "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-posix-bracket": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/expand-range": {
+      "version": "1.8.2",
+      "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
+      "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "fill-range": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/expand-range/node_modules/fill-range": {
+      "version": "2.2.4",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz",
+      "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-number": "^2.1.0",
+        "isobject": "^2.0.0",
+        "randomatic": "^3.0.0",
+        "repeat-element": "^1.1.2",
+        "repeat-string": "^1.5.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/expand-range/node_modules/is-number": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
+      "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/expand-tilde": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz",
+      "integrity": "sha1-C4HrqJflo9MdHD0QL48BRB5VlEk=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "os-homedir": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/extend": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+      "dev": true
+    },
+    "node_modules/extend-shallow": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+      "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "assign-symbols": "^1.0.0",
+        "is-extendable": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/extend-shallow/node_modules/is-extendable": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+      "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-plain-object": "^2.0.4"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/external-editor": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
+      "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
+      "dev": true,
+      "dependencies": {
+        "chardet": "^0.7.0",
+        "iconv-lite": "^0.4.24",
+        "tmp": "^0.0.33"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/extglob": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
+      "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-extglob": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/extglob/node_modules/is-extglob": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+      "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/extract-zip": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz",
+      "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==",
+      "dev": true,
+      "dependencies": {
+        "concat-stream": "^1.6.2",
+        "debug": "^2.6.9",
+        "mkdirp": "^0.5.4",
+        "yauzl": "^2.10.0"
+      },
+      "bin": {
+        "extract-zip": "cli.js"
+      }
+    },
+    "node_modules/extract-zip/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/extract-zip/node_modules/minimist": {
+      "version": "1.2.5",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+      "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
+      "dev": true
+    },
+    "node_modules/extract-zip/node_modules/mkdirp": {
+      "version": "0.5.4",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz",
+      "integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==",
+      "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)",
+      "dev": true,
+      "dependencies": {
+        "minimist": "^1.2.5"
+      },
+      "bin": {
+        "mkdirp": "bin/cmd.js"
+      }
+    },
+    "node_modules/extract-zip/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+      "dev": true
+    },
+    "node_modules/eyes": {
+      "version": "0.1.8",
+      "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz",
+      "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=",
+      "dev": true,
+      "engines": {
+        "node": "> 0.1.90"
+      }
+    },
+    "node_modules/fast-deep-equal": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
+      "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==",
+      "dev": true
+    },
+    "node_modules/fast-json-stable-stringify": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+      "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+      "dev": true
+    },
+    "node_modules/fast-levenshtein": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+      "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
+      "dev": true
+    },
+    "node_modules/fd-slicer": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+      "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
+      "dev": true,
+      "dependencies": {
+        "pend": "~1.2.0"
+      }
+    },
+    "node_modules/figures": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
+      "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
+      "dev": true,
+      "dependencies": {
+        "escape-string-regexp": "^1.0.5"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/file-entry-cache": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz",
+      "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==",
+      "dev": true,
+      "dependencies": {
+        "flat-cache": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/file-uri-to-path": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
+      "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
+      "dev": true,
+      "optional": true,
+      "peer": true
+    },
+    "node_modules/filename-regex": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
+      "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/fill-range": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+      "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+      "dev": true,
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/finalhandler": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+      "integrity": "sha1-t+fQAP/RGTjQ/bBTUG9uur6fWH0=",
+      "dev": true,
+      "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"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/finalhandler/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/finalhandler/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+      "dev": true
+    },
+    "node_modules/findup-sync": {
+      "version": "0.4.3",
+      "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.4.3.tgz",
+      "integrity": "sha1-QAQ5Kee8YK3wt/SCfExudaDeyhI=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "detect-file": "^0.1.0",
+        "is-glob": "^2.0.1",
+        "micromatch": "^2.3.7",
+        "resolve-dir": "^0.1.0"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/findup-sync/node_modules/is-extglob": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+      "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/findup-sync/node_modules/is-glob": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+      "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-extglob": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/flat-cache": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz",
+      "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==",
+      "dev": true,
+      "dependencies": {
+        "flatted": "^2.0.0",
+        "rimraf": "2.6.3",
+        "write": "1.0.3"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/flatted": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz",
+      "integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==",
+      "dev": true
+    },
+    "node_modules/follow-redirects": {
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.10.0.tgz",
+      "integrity": "sha512-4eyLK6s6lH32nOvLLwlIOnr9zrL8Sm+OvW4pVTJNoXeGzYIkHVf+pADQi+OJ0E67hiuSLezPVPyBcIZO50TmmQ==",
+      "dev": true,
+      "dependencies": {
+        "debug": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/follow-redirects/node_modules/debug": {
+      "version": "3.2.6",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+      "integrity": "sha1-6D0X3hbYp++3cX7b5fsQE17uYps=",
+      "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)",
+      "dev": true,
+      "dependencies": {
+        "ms": "^2.1.1"
+      }
+    },
+    "node_modules/for-in": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+      "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/for-own": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
+      "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "for-in": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/fragment-cache": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+      "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "map-cache": "^0.2.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/fs-exists-sync": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz",
+      "integrity": "sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/fs-extra": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
+      "integrity": "sha1-TxicRKoSO4lfcigE9V6iPq3DSOk=",
+      "dev": true,
+      "dependencies": {
+        "graceful-fs": "^4.1.2",
+        "jsonfile": "^4.0.0",
+        "universalify": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=6 <7 || >=8"
+      }
+    },
+    "node_modules/fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+      "dev": true
+    },
+    "node_modules/fsevents": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz",
+      "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==",
+      "deprecated": "\"Please update to latest v2.3 or v2.2\"",
+      "dev": true,
+      "hasInstallScript": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/functional-red-black-tree": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+      "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
+      "dev": true
+    },
+    "node_modules/get-value": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+      "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/glob": {
+      "version": "7.1.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
+      "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
+      "dev": true,
+      "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"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/glob-base": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
+      "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "glob-parent": "^2.0.0",
+        "is-glob": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/glob-base/node_modules/glob-parent": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
+      "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-glob": "^2.0.0"
+      }
+    },
+    "node_modules/glob-base/node_modules/is-extglob": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+      "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/glob-base/node_modules/is-glob": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+      "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-extglob": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/glob-parent": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
+      "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
+      "dev": true,
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/global-modules": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz",
+      "integrity": "sha1-6lo77ULG1s6ZWk+KEmm12uIjgo0=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "global-prefix": "^0.1.4",
+        "is-windows": "^0.2.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/global-prefix": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.5.tgz",
+      "integrity": "sha1-jTvGuNo8qBEqFg2NSW/wRiv+948=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "homedir-polyfill": "^1.0.0",
+        "ini": "^1.3.4",
+        "is-windows": "^0.2.0",
+        "which": "^1.2.12"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/globals": {
+      "version": "12.4.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
+      "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==",
+      "dev": true,
+      "dependencies": {
+        "type-fest": "^0.8.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/graceful-fs": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
+      "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
+      "dev": true
+    },
+    "node_modules/graceful-readlink": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
+      "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=",
+      "dev": true
+    },
+    "node_modules/has-ansi": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+      "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/has-ansi/node_modules/ansi-regex": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+      "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/has-binary2": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz",
+      "integrity": "sha1-d3asYn8+p3JQz8My2rfd9eT10R0=",
+      "dev": true,
+      "dependencies": {
+        "isarray": "2.0.1"
+      }
+    },
+    "node_modules/has-binary2/node_modules/isarray": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
+      "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=",
+      "dev": true
+    },
+    "node_modules/has-color": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz",
+      "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/has-cors": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz",
+      "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=",
+      "dev": true
+    },
+    "node_modules/has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/has-value": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+      "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "get-value": "^2.0.6",
+        "has-values": "^1.0.0",
+        "isobject": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/has-value/node_modules/isobject": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+      "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/has-values": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+      "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-number": "^3.0.0",
+        "kind-of": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/has-values/node_modules/is-number": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+      "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/has-values/node_modules/is-number/node_modules/kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/has-values/node_modules/kind-of": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+      "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/homedir-polyfill": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
+      "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "parse-passwd": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/htmlparser2": {
+      "version": "3.8.3",
+      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz",
+      "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=",
+      "dev": true,
+      "dependencies": {
+        "domelementtype": "1",
+        "domhandler": "2.3",
+        "domutils": "1.5",
+        "entities": "1.0",
+        "readable-stream": "1.1"
+      }
+    },
+    "node_modules/htmlparser2/node_modules/isarray": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+      "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
+      "dev": true
+    },
+    "node_modules/htmlparser2/node_modules/readable-stream": {
+      "version": "1.1.14",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
+      "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
+      "dev": true,
+      "dependencies": {
+        "core-util-is": "~1.0.0",
+        "inherits": "~2.0.1",
+        "isarray": "0.0.1",
+        "string_decoder": "~0.10.x"
+      }
+    },
+    "node_modules/htmlparser2/node_modules/string_decoder": {
+      "version": "0.10.31",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+      "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
+      "dev": true
+    },
+    "node_modules/http-errors": {
+      "version": "1.7.2",
+      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
+      "integrity": "sha1-T1ApzxMjnzEDblsuVSkrz7zIXI8=",
+      "dev": true,
+      "dependencies": {
+        "depd": "~1.1.2",
+        "inherits": "2.0.3",
+        "setprototypeof": "1.1.1",
+        "statuses": ">= 1.5.0 < 2",
+        "toidentifier": "1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/http-proxy": {
+      "version": "1.18.0",
+      "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz",
+      "integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==",
+      "dev": true,
+      "dependencies": {
+        "eventemitter3": "^4.0.0",
+        "follow-redirects": "^1.0.0",
+        "requires-port": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/https-proxy-agent": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz",
+      "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==",
+      "dev": true,
+      "dependencies": {
+        "agent-base": "5",
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 6.0.0"
+      }
+    },
+    "node_modules/i": {
+      "version": "0.3.6",
+      "resolved": "https://registry.npmjs.org/i/-/i-0.3.6.tgz",
+      "integrity": "sha1-2WyScyB28HJxG2sQ/X1PZa2O4j0=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.4"
+      }
+    },
+    "node_modules/iconv-lite": {
+      "version": "0.4.24",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+      "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=",
+      "dev": true,
+      "dependencies": {
+        "safer-buffer": ">= 2.1.2 < 3"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/ignore": {
+      "version": "4.0.6",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+      "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/import-fresh": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz",
+      "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==",
+      "dev": true,
+      "dependencies": {
+        "parent-module": "^1.0.0",
+        "resolve-from": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/imurmurhash": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+      "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8.19"
+      }
+    },
+    "node_modules/indexof": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
+      "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=",
+      "dev": true
+    },
+    "node_modules/inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+      "dev": true,
+      "dependencies": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "node_modules/inherit": {
+      "version": "2.2.7",
+      "resolved": "https://registry.npmjs.org/inherit/-/inherit-2.2.7.tgz",
+      "integrity": "sha1-TiOOKJvHrd34/1BT0PJqL82pS58=",
+      "dev": true
+    },
+    "node_modules/inherits": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+      "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+      "dev": true
+    },
+    "node_modules/ini": {
+      "version": "1.3.8",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+      "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/inquirer": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.1.0.tgz",
+      "integrity": "sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg==",
+      "dev": true,
+      "dependencies": {
+        "ansi-escapes": "^4.2.1",
+        "chalk": "^3.0.0",
+        "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.4.0",
+        "rxjs": "^6.5.3",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0",
+        "through": "^2.3.6"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/inquirer/node_modules/ansi-styles": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
+      "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+      "dev": true,
+      "dependencies": {
+        "@types/color-name": "^1.1.1",
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/inquirer/node_modules/chalk": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
+      "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/inquirer/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/inquirer/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/inquirer/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/inquirer/node_modules/lodash": {
+      "version": "4.17.15",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+      "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+      "dev": true
+    },
+    "node_modules/inquirer/node_modules/mute-stream": {
+      "version": "0.0.8",
+      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
+      "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
+      "dev": true
+    },
+    "node_modules/inquirer/node_modules/strip-ansi": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+      "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/inquirer/node_modules/supports-color": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
+      "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-accessor-descriptor": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+      "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-accessor-descriptor/node_modules/kind-of": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-binary-path": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+      "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+      "dev": true,
+      "dependencies": {
+        "binary-extensions": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-buffer": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/is-data-descriptor": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+      "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-data-descriptor/node_modules/kind-of": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-descriptor": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+      "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-accessor-descriptor": "^1.0.0",
+        "is-data-descriptor": "^1.0.0",
+        "kind-of": "^6.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-descriptor/node_modules/kind-of": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-dotfile": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
+      "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-equal-shallow": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
+      "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-primitive": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-extendable": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+      "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-glob": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
+      "integrity": "sha1-dWfb6fL14kZ7x3q4PEopSCQHpdw=",
+      "dev": true,
+      "dependencies": {
+        "is-extglob": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/is-plain-object": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-plain-object/node_modules/isobject": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+      "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-posix-bracket": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz",
+      "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-primitive": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
+      "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-promise": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
+      "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=",
+      "dev": true
+    },
+    "node_modules/is-utf8": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+      "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
+      "dev": true
+    },
+    "node_modules/is-windows": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz",
+      "integrity": "sha1-3hqm1j6indJIc3tp8f+LgALSEIw=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-wsl": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.1.1.tgz",
+      "integrity": "sha512-umZHcSrwlDHo2TGMXv0DZ8dIUGunZ2Iv68YZnrmCiBPkZ4aaOhtv7pXJKeki9k3qJ3RJr0cDyitcl5wEH3AYog==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+      "dev": true
+    },
+    "node_modules/isbinaryfile": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz",
+      "integrity": "sha1-XW3vPt6/boyoyunDAYOoBLX4voA=",
+      "dev": true,
+      "dependencies": {
+        "buffer-alloc": "^1.2.0"
+      },
+      "engines": {
+        "node": ">=0.6.0"
+      }
+    },
+    "node_modules/isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+      "dev": true
+    },
+    "node_modules/isobject": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+      "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "isarray": "1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/isstream": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+      "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
+      "dev": true
+    },
+    "node_modules/js-reporters": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/js-reporters/-/js-reporters-1.2.1.tgz",
+      "integrity": "sha1-+IxgjjJKM3OpW8xFrTBeXJecRZs=",
+      "dev": true
+    },
+    "node_modules/js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+      "dev": true
+    },
+    "node_modules/js-yaml": {
+      "version": "3.13.1",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
+      "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
+      "dev": true,
+      "dependencies": {
+        "argparse": "^1.0.7",
+        "esprima": "^4.0.0"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/jscs": {
+      "version": "3.0.7",
+      "resolved": "https://registry.npmjs.org/jscs/-/jscs-3.0.7.tgz",
+      "integrity": "sha1-cUG03/W4bjLQ6Z12S4NnZ8MNIBo=",
+      "deprecated": "JSCS has merged with ESLint! See - https://medium.com/@markelog/jscs-end-of-the-line-bc9bf0b3fdb2",
+      "dev": true,
+      "dependencies": {
+        "chalk": "~1.1.0",
+        "cli-table": "~0.3.1",
+        "commander": "~2.9.0",
+        "cst": "^0.4.3",
+        "estraverse": "^4.1.0",
+        "exit": "~0.1.2",
+        "glob": "^5.0.1",
+        "htmlparser2": "3.8.3",
+        "js-yaml": "~3.4.0",
+        "jscs-jsdoc": "^2.0.0",
+        "jscs-preset-wikimedia": "~1.0.0",
+        "jsonlint": "~1.6.2",
+        "lodash": "~3.10.0",
+        "minimatch": "~3.0.0",
+        "natural-compare": "~1.2.2",
+        "pathval": "~0.1.1",
+        "prompt": "~0.2.14",
+        "reserved-words": "^0.1.1",
+        "resolve": "^1.1.6",
+        "strip-bom": "^2.0.0",
+        "strip-json-comments": "~1.0.2",
+        "to-double-quotes": "^2.0.0",
+        "to-single-quotes": "^2.0.0",
+        "vow": "~0.4.8",
+        "vow-fs": "~0.3.4",
+        "xmlbuilder": "^3.1.0"
+      },
+      "bin": {
+        "jscs": "bin/jscs"
+      },
+      "engines": {
+        "node": ">= 0.10.0"
+      }
+    },
+    "node_modules/jscs-jsdoc": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/jscs-jsdoc/-/jscs-jsdoc-2.0.0.tgz",
+      "integrity": "sha1-9T684CmqMSW9iCkLpQ1k1FEKSHE=",
+      "dev": true,
+      "dependencies": {
+        "comment-parser": "^0.3.1",
+        "jsdoctypeparser": "~1.2.0"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/jscs-preset-wikimedia": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/jscs-preset-wikimedia/-/jscs-preset-wikimedia-1.0.1.tgz",
+      "integrity": "sha1-pqX6WWf9Z6XWCQOOHHlOr0HUIz0=",
+      "deprecated": "No longer maintained. We recomment migrating to ESLint with eslint-config-wikimedia.",
+      "dev": true
+    },
+    "node_modules/jscs/node_modules/ansi-regex": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+      "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/jscs/node_modules/ansi-styles": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+      "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/jscs/node_modules/chalk": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+      "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+      "dev": true,
+      "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"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/jscs/node_modules/commander": {
+      "version": "2.9.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
+      "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=",
+      "dev": true,
+      "dependencies": {
+        "graceful-readlink": ">= 1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.6.x"
+      }
+    },
+    "node_modules/jscs/node_modules/esprima": {
+      "version": "2.7.3",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz",
+      "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=",
+      "dev": true,
+      "bin": {
+        "esparse": "bin/esparse.js",
+        "esvalidate": "bin/esvalidate.js"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/jscs/node_modules/glob": {
+      "version": "5.0.15",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
+      "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
+      "dev": true,
+      "dependencies": {
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "2 || 3",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/jscs/node_modules/js-yaml": {
+      "version": "3.4.6",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.4.6.tgz",
+      "integrity": "sha1-a+GyP2JJ9T0pM3D9TRqqY84bTrA=",
+      "dev": true,
+      "dependencies": {
+        "argparse": "^1.0.2",
+        "esprima": "^2.6.0",
+        "inherit": "^2.2.2"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/jscs/node_modules/lodash": {
+      "version": "3.10.1",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
+      "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=",
+      "dev": true
+    },
+    "node_modules/jscs/node_modules/natural-compare": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.2.2.tgz",
+      "integrity": "sha1-H5bWDjFBysG20FZTzg2urHY69qo=",
+      "dev": true
+    },
+    "node_modules/jscs/node_modules/strip-ansi": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+      "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/jscs/node_modules/strip-json-comments": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz",
+      "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=",
+      "dev": true,
+      "bin": {
+        "strip-json-comments": "cli.js"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/jscs/node_modules/supports-color": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+      "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/jsdoctypeparser": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/jsdoctypeparser/-/jsdoctypeparser-1.2.0.tgz",
+      "integrity": "sha1-597cFToRhJ/8UUEUSuhqfvDCU5I=",
+      "dev": true,
+      "dependencies": {
+        "lodash": "^3.7.0"
+      }
+    },
+    "node_modules/jsdoctypeparser/node_modules/lodash": {
+      "version": "3.10.1",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
+      "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=",
+      "dev": true
+    },
+    "node_modules/jshint": {
+      "version": "2.11.0",
+      "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.11.0.tgz",
+      "integrity": "sha512-ooaD/hrBPhu35xXW4gn+o3SOuzht73gdBuffgJzrZBJZPGgGiiTvJEgTyxFvBO2nz0+X1G6etF8SzUODTlLY6Q==",
+      "dev": true,
+      "dependencies": {
+        "cli": "~1.0.0",
+        "console-browserify": "1.1.x",
+        "exit": "0.1.x",
+        "htmlparser2": "3.8.x",
+        "lodash": "~4.17.11",
+        "minimatch": "~3.0.2",
+        "shelljs": "0.3.x",
+        "strip-json-comments": "1.0.x"
+      },
+      "bin": {
+        "jshint": "bin/jshint"
+      }
+    },
+    "node_modules/jshint/node_modules/strip-json-comments": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz",
+      "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=",
+      "dev": true,
+      "bin": {
+        "strip-json-comments": "cli.js"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/json-schema-traverse": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+      "dev": true
+    },
+    "node_modules/json-stable-stringify-without-jsonify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+      "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
+      "dev": true
+    },
+    "node_modules/jsonfile": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+      "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
+      "dev": true,
+      "dependencies": {
+        "graceful-fs": "^4.1.6"
+      },
+      "optionalDependencies": {
+        "graceful-fs": "^4.1.6"
+      }
+    },
+    "node_modules/jsonlint": {
+      "version": "1.6.3",
+      "resolved": "https://registry.npmjs.org/jsonlint/-/jsonlint-1.6.3.tgz",
+      "integrity": "sha1-y14x78C3gpHQ2GL77wWQCt8hKYg=",
+      "dev": true,
+      "dependencies": {
+        "JSV": "^4.0.x",
+        "nomnom": "^1.5.x"
+      },
+      "bin": {
+        "jsonlint": "lib/cli.js"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/JSV": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/JSV/-/JSV-4.0.2.tgz",
+      "integrity": "sha1-0Hf2glVx+CEy+d/67Vh7QCn+/1c=",
+      "dev": true,
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/karma": {
+      "version": "4.4.1",
+      "resolved": "https://registry.npmjs.org/karma/-/karma-4.4.1.tgz",
+      "integrity": "sha512-L5SIaXEYqzrh6b1wqYC42tNsFMx2PWuxky84pK9coK09MvmL7mxii3G3bZBh/0rvD27lqDd0le9jyhzvwif73A==",
+      "dev": true,
+      "dependencies": {
+        "bluebird": "^3.3.0",
+        "body-parser": "^1.16.1",
+        "braces": "^3.0.2",
+        "chokidar": "^3.0.0",
+        "colors": "^1.1.0",
+        "connect": "^3.6.0",
+        "di": "^0.0.1",
+        "dom-serialize": "^2.2.0",
+        "flatted": "^2.0.0",
+        "glob": "^7.1.1",
+        "graceful-fs": "^4.1.2",
+        "http-proxy": "^1.13.0",
+        "isbinaryfile": "^3.0.0",
+        "lodash": "^4.17.14",
+        "log4js": "^4.0.0",
+        "mime": "^2.3.1",
+        "minimatch": "^3.0.2",
+        "optimist": "^0.6.1",
+        "qjobs": "^1.1.4",
+        "range-parser": "^1.2.0",
+        "rimraf": "^2.6.0",
+        "safe-buffer": "^5.0.1",
+        "socket.io": "2.1.1",
+        "source-map": "^0.6.1",
+        "tmp": "0.0.33",
+        "useragent": "2.3.0"
+      },
+      "bin": {
+        "karma": "bin/karma"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/karma-chrome-launcher": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.0.tgz",
+      "integrity": "sha512-3dPs/n7vgz1rxxtynpzZTvb9y/GIaW8xjAwcIGttLbycqoFtI7yo1NGnQi6oFTherRE+GIhCAHZC4vEqWGhNvg==",
+      "dev": true,
+      "dependencies": {
+        "which": "^1.2.1"
+      }
+    },
+    "node_modules/karma-firefox-launcher": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/karma-firefox-launcher/-/karma-firefox-launcher-1.3.0.tgz",
+      "integrity": "sha512-Fi7xPhwrRgr+94BnHX0F5dCl1miIW4RHnzjIGxF8GaIEp7rNqX7LSi7ok63VXs3PS/5MQaQMhGxw+bvD+pibBQ==",
+      "dev": true,
+      "dependencies": {
+        "is-wsl": "^2.1.0"
+      }
+    },
+    "node_modules/karma-qunit": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/karma-qunit/-/karma-qunit-4.0.0.tgz",
+      "integrity": "sha512-sGuMyTMbiA2zq/aV43uduwf58mMiMDiG6YH3dvaarQnwFLmyRD1i8356TndX8lFeVSOtykowtBtpcdGxyuezTA==",
+      "dev": true,
+      "peerDependencies": {
+        "karma": "^4.0.0",
+        "qunit": "^2.0.0"
+      }
+    },
+    "node_modules/karma/node_modules/lodash": {
+      "version": "4.17.15",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+      "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+      "dev": true
+    },
+    "node_modules/kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/levn": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+      "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+      "dev": true,
+      "dependencies": {
+        "prelude-ls": "~1.1.2",
+        "type-check": "~0.3.2"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/lodash": {
+      "version": "4.17.11",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
+      "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
+      "dev": true
+    },
+    "node_modules/log4js": {
+      "version": "4.5.1",
+      "resolved": "https://registry.npmjs.org/log4js/-/log4js-4.5.1.tgz",
+      "integrity": "sha512-EEEgFcE9bLgaYUKuozyFfytQM2wDHtXn4tAN41pkaxpNjAykv11GVdeI4tHtmPWW4Xrgh9R/2d7XYghDVjbKKw==",
+      "dev": true,
+      "dependencies": {
+        "date-format": "^2.0.0",
+        "debug": "^4.1.1",
+        "flatted": "^2.0.0",
+        "rfdc": "^1.1.4",
+        "streamroller": "^1.0.6"
+      },
+      "engines": {
+        "node": ">=6.0"
+      }
+    },
+    "node_modules/lru-cache": {
+      "version": "4.1.5",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
+      "integrity": "sha1-i75Q6oW+1ZvJ4z3KuCNe6bz0Q80=",
+      "dev": true,
+      "dependencies": {
+        "pseudomap": "^1.0.2",
+        "yallist": "^2.1.2"
+      }
+    },
+    "node_modules/ls": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/ls/-/ls-0.2.1.tgz",
+      "integrity": "sha1-DZbMhwYAgG+ua9iSl9xcZkVMv3E=",
+      "dev": true,
+      "dependencies": {
+        "glob": "7.0.5"
+      }
+    },
+    "node_modules/ls/node_modules/glob": {
+      "version": "7.0.5",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.5.tgz",
+      "integrity": "sha1-tCAqaQmbu00pKnwblbZoK2fr3JU=",
+      "dev": true,
+      "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"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/map-cache": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+      "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/map-visit": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+      "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "object-visit": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/matcher-collection": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/matcher-collection/-/matcher-collection-1.1.2.tgz",
+      "integrity": "sha512-YQ/teqaOIIfUHedRam08PB3NK7Mjct6BvzRnJmpGDm8uFXpNr1sbY4yuflI5JcEs6COpYA0FpRQhSDBf1tT95g==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "minimatch": "^3.0.2"
+      }
+    },
+    "node_modules/math-random": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz",
+      "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/media-typer": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+      "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/micromatch": {
+      "version": "2.3.11",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
+      "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
+      "dev": true,
+      "peer": true,
+      "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"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/micromatch/node_modules/braces": {
+      "version": "1.8.5",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
+      "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "expand-range": "^1.8.1",
+        "preserve": "^0.2.0",
+        "repeat-element": "^1.1.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/micromatch/node_modules/is-extglob": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+      "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/micromatch/node_modules/is-glob": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+      "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-extglob": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/micromatch/node_modules/normalize-path": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+      "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "remove-trailing-separator": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/mime": {
+      "version": "2.4.4",
+      "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz",
+      "integrity": "sha1-vXuRE1/GsBzePpuuM9ZZtj2IV+U=",
+      "dev": true,
+      "bin": {
+        "mime": "cli.js"
+      },
+      "engines": {
+        "node": ">=4.0.0"
+      }
+    },
+    "node_modules/mime-db": {
+      "version": "1.43.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz",
+      "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mime-types": {
+      "version": "2.1.26",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz",
+      "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==",
+      "dev": true,
+      "dependencies": {
+        "mime-db": "1.43.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mimic-fn": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+      "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/minimatch": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+      "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=",
+      "dev": true,
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/minimist": {
+      "version": "0.0.8",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+      "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
+      "dev": true
+    },
+    "node_modules/mixin-deep": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
+      "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "for-in": "^1.0.2",
+        "is-extendable": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/mixin-deep/node_modules/is-extendable": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+      "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-plain-object": "^2.0.4"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/mkdirp": {
+      "version": "0.5.1",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+      "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+      "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)",
+      "dev": true,
+      "dependencies": {
+        "minimist": "0.0.8"
+      },
+      "bin": {
+        "mkdirp": "bin/cmd.js"
+      }
+    },
+    "node_modules/ms": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+      "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
+      "dev": true
+    },
+    "node_modules/mute-stream": {
+      "version": "0.0.7",
+      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
+      "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
+      "dev": true
+    },
+    "node_modules/nan": {
+      "version": "2.15.0",
+      "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz",
+      "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==",
+      "dev": true,
+      "optional": true,
+      "peer": true
+    },
+    "node_modules/nanomatch": {
+      "version": "1.2.13",
+      "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+      "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+      "dev": true,
+      "peer": true,
+      "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"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/nanomatch/node_modules/arr-diff": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+      "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/nanomatch/node_modules/array-unique": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+      "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/nanomatch/node_modules/is-windows": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+      "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/nanomatch/node_modules/kind-of": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/natural-compare": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+      "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
+      "dev": true
+    },
+    "node_modules/ncp": {
+      "version": "0.4.2",
+      "resolved": "https://registry.npmjs.org/ncp/-/ncp-0.4.2.tgz",
+      "integrity": "sha1-q8xsvT7C7Spyn/bnwfqPAXhKhXQ=",
+      "dev": true,
+      "bin": {
+        "ncp": "bin/ncp"
+      }
+    },
+    "node_modules/negotiator": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
+      "integrity": "sha1-/qz3zPUlp3rpY0Q2pkiD/+yjRvs=",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/nice-try": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
+      "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
+      "dev": true
+    },
+    "node_modules/node-watch": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/node-watch/-/node-watch-0.6.1.tgz",
+      "integrity": "sha512-gwQiR7weFRV8mAtT0x0kXkZ18dfRLB45xH7q0hCOVQMLfLb2f1ZaSvR57q4/b/Vj6B0RwMNJYbvb69e1yM7qEA==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/nomnom": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz",
+      "integrity": "sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=",
+      "deprecated": "Package no longer supported. Contact support@npmjs.com for more info.",
+      "dev": true,
+      "dependencies": {
+        "chalk": "~0.4.0",
+        "underscore": "~1.6.0"
+      }
+    },
+    "node_modules/nomnom/node_modules/ansi-styles": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz",
+      "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/nomnom/node_modules/chalk": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz",
+      "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "~1.0.0",
+        "has-color": "~0.1.0",
+        "strip-ansi": "~0.1.0"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/nomnom/node_modules/strip-ansi": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz",
+      "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=",
+      "dev": true,
+      "bin": {
+        "strip-ansi": "cli.js"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/normalize-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-component": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz",
+      "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=",
+      "dev": true
+    },
+    "node_modules/object-copy": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+      "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "copy-descriptor": "^0.1.0",
+        "define-property": "^0.2.5",
+        "kind-of": "^3.0.3"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-copy/node_modules/define-property": {
+      "version": "0.2.5",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+      "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-descriptor": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-copy/node_modules/is-accessor-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+      "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-copy/node_modules/is-data-descriptor": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+      "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-copy/node_modules/is-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+      "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-accessor-descriptor": "^0.1.6",
+        "is-data-descriptor": "^0.1.4",
+        "kind-of": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-copy/node_modules/is-descriptor/node_modules/kind-of": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+      "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-visit": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+      "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "isobject": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-visit/node_modules/isobject": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+      "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object.omit": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
+      "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "for-own": "^0.1.4",
+        "is-extendable": "^0.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object.pick": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+      "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object.pick/node_modules/isobject": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+      "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/on-finished": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+      "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+      "dev": true,
+      "dependencies": {
+        "ee-first": "1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+      "dev": true,
+      "dependencies": {
+        "wrappy": "1"
+      }
+    },
+    "node_modules/onetime": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz",
+      "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==",
+      "dev": true,
+      "dependencies": {
+        "mimic-fn": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/optimist": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
+      "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
+      "dev": true,
+      "dependencies": {
+        "minimist": "~0.0.1",
+        "wordwrap": "~0.0.2"
+      }
+    },
+    "node_modules/optimist/node_modules/wordwrap": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
+      "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/optionator": {
+      "version": "0.8.3",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
+      "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
+      "dev": true,
+      "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"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/os-homedir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+      "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/os-tmpdir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+      "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/parent-module": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+      "dev": true,
+      "dependencies": {
+        "callsites": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/parse-glob": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
+      "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "glob-base": "^0.3.0",
+        "is-dotfile": "^1.0.0",
+        "is-extglob": "^1.0.0",
+        "is-glob": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/parse-glob/node_modules/is-extglob": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+      "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/parse-glob/node_modules/is-glob": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+      "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-extglob": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/parse-passwd": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
+      "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/parseqs": {
+      "version": "0.0.5",
+      "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz",
+      "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=",
+      "dev": true,
+      "dependencies": {
+        "better-assert": "~1.0.0"
+      }
+    },
+    "node_modules/parseuri": {
+      "version": "0.0.5",
+      "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz",
+      "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=",
+      "dev": true,
+      "dependencies": {
+        "better-assert": "~1.0.0"
+      }
+    },
+    "node_modules/parseurl": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+      "integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ=",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/pascalcase": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+      "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/path-key": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+      "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/path-parse": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+      "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
+      "dev": true
+    },
+    "node_modules/pathval": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/pathval/-/pathval-0.1.1.tgz",
+      "integrity": "sha1-CPkRzcqczllCiA2ngXvAtyO2bYI=",
+      "dev": true
+    },
+    "node_modules/pend": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+      "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
+      "dev": true
+    },
+    "node_modules/picomatch": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
+      "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
+      "dev": true,
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/pkginfo": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.4.1.tgz",
+      "integrity": "sha1-tUGO8EOd5UJfxJlQQtztFPsqhP8=",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
+    "node_modules/posix-character-classes": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+      "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/prelude-ls": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+      "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/preserve": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
+      "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/process-nextick-args": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+      "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
+      "dev": true
+    },
+    "node_modules/progress": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+      "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/prompt": {
+      "version": "0.2.14",
+      "resolved": "https://registry.npmjs.org/prompt/-/prompt-0.2.14.tgz",
+      "integrity": "sha1-V3VPZPVD/XsIRXB8gY7OYY8F/9w=",
+      "dev": true,
+      "dependencies": {
+        "pkginfo": "0.x.x",
+        "read": "1.0.x",
+        "revalidator": "0.1.x",
+        "utile": "0.2.x",
+        "winston": "0.8.x"
+      },
+      "engines": {
+        "node": ">= 0.6.6"
+      }
+    },
+    "node_modules/proxy-from-env": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+      "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
+      "dev": true
+    },
+    "node_modules/pseudomap": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+      "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
+      "dev": true
+    },
+    "node_modules/punycode": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+      "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/puppeteer": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-2.1.1.tgz",
+      "integrity": "sha512-LWzaDVQkk1EPiuYeTOj+CZRIjda4k2s5w4MK4xoH2+kgWV/SDlkYHmxatDdtYrciHUKSXTsGgPgPP8ILVdBsxg==",
+      "dev": true,
+      "hasInstallScript": true,
+      "dependencies": {
+        "@types/mime-types": "^2.1.0",
+        "debug": "^4.1.0",
+        "extract-zip": "^1.6.6",
+        "https-proxy-agent": "^4.0.0",
+        "mime": "^2.0.3",
+        "mime-types": "^2.1.25",
+        "progress": "^2.0.1",
+        "proxy-from-env": "^1.0.0",
+        "rimraf": "^2.6.1",
+        "ws": "^6.1.0"
+      },
+      "engines": {
+        "node": ">=8.16.0"
+      }
+    },
+    "node_modules/puppeteer/node_modules/ws": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
+      "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
+      "dev": true,
+      "dependencies": {
+        "async-limiter": "~1.0.0"
+      }
+    },
+    "node_modules/qjobs": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz",
+      "integrity": "sha1-xF6cYYAL0IfviNfiVkI73Unl0HE=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.9"
+      }
+    },
+    "node_modules/qs": {
+      "version": "6.7.0",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
+      "integrity": "sha1-QdwaAV49WB8WIXdr4xr7KHapsbw=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.6"
+      }
+    },
+    "node_modules/qunit": {
+      "version": "2.9.3",
+      "resolved": "https://registry.npmjs.org/qunit/-/qunit-2.9.3.tgz",
+      "integrity": "sha512-RH4VYSaVsNRDthMFFboTJAJ8q4kJM5LvOqWponKUYPEAeOcmc/YFV1QsZ7ikknA3TjqliWFJYEV63vvVXaALmQ==",
+      "dev": true,
+      "dependencies": {
+        "commander": "2.12.2",
+        "js-reporters": "1.2.1",
+        "minimatch": "3.0.4",
+        "node-watch": "0.6.1",
+        "resolve": "1.9.0"
+      },
+      "bin": {
+        "qunit": "bin/qunit.js"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/qunit-assert-close": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/qunit-assert-close/-/qunit-assert-close-2.1.2.tgz",
+      "integrity": "sha1-cC1pSSr1kBCi5AQN1k/gzS4EPuE=",
+      "dev": true,
+      "peerDependencies": {
+        "qunitjs": "*"
+      }
+    },
+    "node_modules/qunitjs": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/qunitjs/-/qunitjs-2.4.1.tgz",
+      "integrity": "sha512-by/2zYvsNdS6Q6Ev6UJ3qJK+OYVlTzWlQ4afaeYMhVh1dd2K3N1ZZKCrCm3WSWPnz5ELMT8WyJRcVy5PXT2y+Q==",
+      "deprecated": "2.4.1 is the last version where QUnit will be published as 'qunitjs'. To receive future updates, you will need to change the package name to 'qunit'.",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "chokidar": "1.6.1",
+        "commander": "2.9.0",
+        "exists-stat": "1.0.0",
+        "findup-sync": "0.4.3",
+        "js-reporters": "1.2.0",
+        "resolve": "1.3.2",
+        "walk-sync": "0.3.1"
+      },
+      "bin": {
+        "qunit": "bin/qunit"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/qunitjs/node_modules/anymatch": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz",
+      "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "micromatch": "^2.1.5",
+        "normalize-path": "^2.0.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/arr-diff": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+      "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/array-unique": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+      "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/binary-extensions": {
+      "version": "1.13.1",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
+      "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/braces": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+      "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+      "dev": true,
+      "peer": true,
+      "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"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/braces/node_modules/extend-shallow": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+      "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-extendable": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/chokidar": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.6.1.tgz",
+      "integrity": "sha1-L0RHq16W5Q+z14n9kNTHLg5McMI=",
+      "deprecated": "Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "anymatch": "^1.3.0",
+        "async-each": "^1.0.0",
+        "fsevents": "^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"
+      }
+    },
+    "node_modules/qunitjs/node_modules/commander": {
+      "version": "2.9.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
+      "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "graceful-readlink": ">= 1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.6.x"
+      }
+    },
+    "node_modules/qunitjs/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/expand-brackets": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+      "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+      "dev": true,
+      "peer": true,
+      "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"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/expand-brackets/node_modules/define-property": {
+      "version": "0.2.5",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+      "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-descriptor": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/expand-brackets/node_modules/extend-shallow": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+      "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-extendable": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/expand-brackets/node_modules/is-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+      "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-accessor-descriptor": "^0.1.6",
+        "is-data-descriptor": "^0.1.4",
+        "kind-of": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/expand-brackets/node_modules/kind-of": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+      "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/extglob": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+      "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+      "dev": true,
+      "peer": true,
+      "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"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/extglob/node_modules/define-property": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+      "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-descriptor": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/extglob/node_modules/extend-shallow": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+      "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-extendable": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/fill-range": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+      "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "extend-shallow": "^2.0.1",
+        "is-number": "^3.0.0",
+        "repeat-string": "^1.6.1",
+        "to-regex-range": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/fill-range/node_modules/extend-shallow": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+      "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-extendable": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/fsevents": {
+      "version": "1.2.13",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
+      "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
+      "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.",
+      "dev": true,
+      "hasInstallScript": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "peer": true,
+      "dependencies": {
+        "bindings": "^1.5.0",
+        "nan": "^2.12.1"
+      },
+      "engines": {
+        "node": ">= 4.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/glob-parent": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
+      "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-glob": "^2.0.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/is-accessor-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+      "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/is-accessor-descriptor/node_modules/kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/is-binary-path": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
+      "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "binary-extensions": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/is-data-descriptor": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+      "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/is-data-descriptor/node_modules/kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/is-extglob": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+      "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/is-glob": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+      "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-extglob": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/is-number": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+      "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/is-number/node_modules/kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-buffer": "^1.1.5"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/isobject": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+      "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/js-reporters": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/js-reporters/-/js-reporters-1.2.0.tgz",
+      "integrity": "sha1-fPLLaYGWaEeQNQ0MTKB/Su2ewX4=",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/qunitjs/node_modules/kind-of": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/qunitjs/node_modules/normalize-path": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+      "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "remove-trailing-separator": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/readdirp": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
+      "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "graceful-fs": "^4.1.11",
+        "micromatch": "^3.1.10",
+        "readable-stream": "^2.0.2"
+      },
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/qunitjs/node_modules/readdirp/node_modules/micromatch": {
+      "version": "3.1.10",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+      "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+      "dev": true,
+      "peer": true,
+      "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"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/qunitjs/node_modules/resolve": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.3.2.tgz",
+      "integrity": "sha1-HwRCyeDLuBNuh7kwX5MvRsfygjU=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "path-parse": "^1.0.5"
+      }
+    },
+    "node_modules/qunitjs/node_modules/to-regex-range": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+      "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-number": "^3.0.0",
+        "repeat-string": "^1.6.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/randomatic": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz",
+      "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-number": "^4.0.0",
+        "kind-of": "^6.0.0",
+        "math-random": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.10.0"
+      }
+    },
+    "node_modules/randomatic/node_modules/is-number": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
+      "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/randomatic/node_modules/kind-of": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/range-parser": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+      "integrity": "sha1-PPNwI9GZ4cJNGlW4SADC8+ZGgDE=",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/raw-body": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
+      "integrity": "sha1-oc5vucm8NWylLoklarWQWeE9AzI=",
+      "dev": true,
+      "dependencies": {
+        "bytes": "3.1.0",
+        "http-errors": "1.7.2",
+        "iconv-lite": "0.4.24",
+        "unpipe": "1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/read": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
+      "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=",
+      "dev": true,
+      "dependencies": {
+        "mute-stream": "~0.0.4"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "node_modules/readable-stream": {
+      "version": "2.3.6",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+      "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+      "dev": true,
+      "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"
+      }
+    },
+    "node_modules/readdirp": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz",
+      "integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==",
+      "dev": true,
+      "dependencies": {
+        "picomatch": "^2.0.7"
+      },
+      "engines": {
+        "node": ">=8.10.0"
+      }
+    },
+    "node_modules/regenerator-runtime": {
+      "version": "0.11.1",
+      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
+      "integrity": "sha1-vgWtf5v30i4Fb5cmzuUBf78Z4uk=",
+      "dev": true
+    },
+    "node_modules/regex-cache": {
+      "version": "0.4.4",
+      "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
+      "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-equal-shallow": "^0.1.3"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/regex-not": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+      "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "extend-shallow": "^3.0.2",
+        "safe-regex": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/regexpp": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz",
+      "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.5.0"
+      }
+    },
+    "node_modules/remove-trailing-separator": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+      "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/repeat-element": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz",
+      "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/repeat-string": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+      "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/requires-port": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+      "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
+      "dev": true
+    },
+    "node_modules/reserved-words": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/reserved-words/-/reserved-words-0.1.2.tgz",
+      "integrity": "sha1-AKCUD5jNUBrqqsMWQR2a3FKzGrE=",
+      "dev": true
+    },
+    "node_modules/resolve": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.9.0.tgz",
+      "integrity": "sha512-TZNye00tI67lwYvzxCxHGjwTNlUV70io54/Ed4j6PscB8xVfuBJpRenI/o6dVk0cY0PYTY27AgCoGGxRnYuItQ==",
+      "dev": true,
+      "dependencies": {
+        "path-parse": "^1.0.6"
+      }
+    },
+    "node_modules/resolve-dir": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz",
+      "integrity": "sha1-shklmlYC+sXFxJatiUpujMQwJh4=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "expand-tilde": "^1.2.2",
+        "global-modules": "^0.2.3"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/resolve-from": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/resolve-url": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+      "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
+      "deprecated": "https://github.com/lydell/resolve-url#deprecated",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/restore-cursor": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
+      "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
+      "dev": true,
+      "dependencies": {
+        "onetime": "^5.1.0",
+        "signal-exit": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ret": {
+      "version": "0.1.15",
+      "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+      "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.12"
+      }
+    },
+    "node_modules/revalidator": {
+      "version": "0.1.8",
+      "resolved": "https://registry.npmjs.org/revalidator/-/revalidator-0.1.8.tgz",
+      "integrity": "sha1-/s5hv6DBtSoga9axgZgYS91SOjs=",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
+    "node_modules/rfdc": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.4.tgz",
+      "integrity": "sha1-unLME2egzNnPgahws7WL060H+MI=",
+      "dev": true
+    },
+    "node_modules/rimraf": {
+      "version": "2.6.3",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+      "integrity": "sha1-stEE/g2Psnz54KHNqCYt04M8bKs=",
+      "dev": true,
+      "dependencies": {
+        "glob": "^7.1.3"
+      },
+      "bin": {
+        "rimraf": "bin.js"
+      }
+    },
+    "node_modules/run-async": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.0.tgz",
+      "integrity": "sha512-xJTbh/d7Lm7SBhc1tNvTpeCHaEzoyxPrqNlvSdMfBTYwaY++UJFyXUOxAtsRUXjlqOfj8luNaR9vjCh4KeV+pg==",
+      "dev": true,
+      "dependencies": {
+        "is-promise": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/rxjs": {
+      "version": "6.5.4",
+      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz",
+      "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==",
+      "dev": true,
+      "dependencies": {
+        "tslib": "^1.9.0"
+      },
+      "engines": {
+        "npm": ">=2.0.0"
+      }
+    },
+    "node_modules/safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=",
+      "dev": true
+    },
+    "node_modules/safe-regex": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+      "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ret": "~0.1.10"
+      }
+    },
+    "node_modules/safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=",
+      "dev": true
+    },
+    "node_modules/semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/set-value": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
+      "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "extend-shallow": "^2.0.1",
+        "is-extendable": "^0.1.1",
+        "is-plain-object": "^2.0.3",
+        "split-string": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/set-value/node_modules/extend-shallow": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+      "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-extendable": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/setprototypeof": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
+      "integrity": "sha1-fpWsskqpL1iF4KvvW6ExMw1K5oM=",
+      "dev": true
+    },
+    "node_modules/shebang-command": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+      "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+      "dev": true,
+      "dependencies": {
+        "shebang-regex": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/shebang-regex": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+      "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/shelljs": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz",
+      "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=",
+      "dev": true,
+      "bin": {
+        "shjs": "bin/shjs"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/signal-exit": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
+      "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
+      "dev": true
+    },
+    "node_modules/slice-ansi": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
+      "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^3.2.0",
+        "astral-regex": "^1.0.0",
+        "is-fullwidth-code-point": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+      "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/snapdragon": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+      "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+      "dev": true,
+      "peer": true,
+      "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"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon-node": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+      "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "define-property": "^1.0.0",
+        "isobject": "^3.0.0",
+        "snapdragon-util": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon-node/node_modules/define-property": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+      "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-descriptor": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon-node/node_modules/isobject": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+      "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon-util": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+      "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.2.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/snapdragon/node_modules/define-property": {
+      "version": "0.2.5",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+      "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-descriptor": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon/node_modules/extend-shallow": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+      "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-extendable": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon/node_modules/is-accessor-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+      "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon/node_modules/is-data-descriptor": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+      "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon/node_modules/is-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+      "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-accessor-descriptor": "^0.1.6",
+        "is-data-descriptor": "^0.1.4",
+        "kind-of": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon/node_modules/is-descriptor/node_modules/kind-of": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+      "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/snapdragon/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/snapdragon/node_modules/source-map": {
+      "version": "0.5.7",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+      "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/socket.io": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz",
+      "integrity": "sha1-oGnF/qvuPmshSnW0DOBlLhz7mYA=",
+      "dev": true,
+      "dependencies": {
+        "debug": "~3.1.0",
+        "engine.io": "~3.2.0",
+        "has-binary2": "~1.0.2",
+        "socket.io-adapter": "~1.1.0",
+        "socket.io-client": "2.1.1",
+        "socket.io-parser": "~3.2.0"
+      }
+    },
+    "node_modules/socket.io-adapter": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz",
+      "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==",
+      "dev": true
+    },
+    "node_modules/socket.io-client": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz",
+      "integrity": "sha1-3LOBA0NqtFeN2wJmOK4vIbYjZx8=",
+      "dev": true,
+      "dependencies": {
+        "backo2": "1.0.2",
+        "base64-arraybuffer": "0.1.5",
+        "component-bind": "1.0.0",
+        "component-emitter": "1.2.1",
+        "debug": "~3.1.0",
+        "engine.io-client": "~3.2.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.2.0",
+        "to-array": "0.1.4"
+      }
+    },
+    "node_modules/socket.io-client/node_modules/debug": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+      "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/socket.io-client/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+      "dev": true
+    },
+    "node_modules/socket.io-parser": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz",
+      "integrity": "sha1-58Yii2qh+BTmFIrqMltRqpSZ4Hc=",
+      "dev": true,
+      "dependencies": {
+        "component-emitter": "1.2.1",
+        "debug": "~3.1.0",
+        "isarray": "2.0.1"
+      }
+    },
+    "node_modules/socket.io-parser/node_modules/debug": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+      "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/socket.io-parser/node_modules/isarray": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
+      "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=",
+      "dev": true
+    },
+    "node_modules/socket.io-parser/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+      "dev": true
+    },
+    "node_modules/socket.io/node_modules/debug": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+      "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/socket.io/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+      "dev": true
+    },
+    "node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/source-map-resolve": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
+      "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
+      "dev": true,
+      "peer": true,
+      "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"
+      }
+    },
+    "node_modules/source-map-support": {
+      "version": "0.5.16",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz",
+      "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==",
+      "dev": true,
+      "dependencies": {
+        "buffer-from": "^1.0.0",
+        "source-map": "^0.6.0"
+      }
+    },
+    "node_modules/source-map-url": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz",
+      "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/split-string": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+      "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "extend-shallow": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/sprintf-js": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+      "dev": true
+    },
+    "node_modules/stack-trace": {
+      "version": "0.0.10",
+      "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
+      "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=",
+      "dev": true,
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/static-extend": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+      "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "define-property": "^0.2.5",
+        "object-copy": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/static-extend/node_modules/define-property": {
+      "version": "0.2.5",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+      "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-descriptor": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/static-extend/node_modules/is-accessor-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+      "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/static-extend/node_modules/is-data-descriptor": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+      "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/static-extend/node_modules/is-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+      "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "is-accessor-descriptor": "^0.1.6",
+        "is-data-descriptor": "^0.1.4",
+        "kind-of": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/static-extend/node_modules/is-descriptor/node_modules/kind-of": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+      "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/statuses": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+      "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/streamroller": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-1.0.6.tgz",
+      "integrity": "sha512-3QC47Mhv3/aZNFpDDVO44qQb9gwB9QggMEE0sQmkTAwBVYdBRWISdsywlkfm5II1Q5y/pmrHflti/IgmIzdDBg==",
+      "dev": true,
+      "dependencies": {
+        "async": "^2.6.2",
+        "date-format": "^2.0.0",
+        "debug": "^3.2.6",
+        "fs-extra": "^7.0.1",
+        "lodash": "^4.17.14"
+      },
+      "engines": {
+        "node": ">=6.0"
+      }
+    },
+    "node_modules/streamroller/node_modules/debug": {
+      "version": "3.2.6",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+      "integrity": "sha1-6D0X3hbYp++3cX7b5fsQE17uYps=",
+      "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)",
+      "dev": true,
+      "dependencies": {
+        "ms": "^2.1.1"
+      }
+    },
+    "node_modules/streamroller/node_modules/lodash": {
+      "version": "4.17.15",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+      "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+      "dev": true
+    },
+    "node_modules/string_decoder": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+      "dev": true,
+      "dependencies": {
+        "safe-buffer": "~5.1.0"
+      }
+    },
+    "node_modules/string-width": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+      "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+      "dev": true,
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/string-width/node_modules/strip-ansi": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+      "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-ansi": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+      "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/strip-ansi/node_modules/ansi-regex": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+      "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/strip-bom": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
+      "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
+      "dev": true,
+      "dependencies": {
+        "is-utf8": "^0.2.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/strip-json-comments": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz",
+      "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/syn": {
+      "version": "0.14.1",
+      "resolved": "https://registry.npmjs.org/syn/-/syn-0.14.1.tgz",
+      "integrity": "sha512-0b+KMtbT52PMX3F7nUDr/HINxTilZt8fDOZmKOadDWU1ymSJQ6CWJgUS9Mggq5VpbpDjPLJ3TC1lSYWlrskU6g==",
+      "dev": true
+    },
+    "node_modules/table": {
+      "version": "5.4.6",
+      "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz",
+      "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==",
+      "dev": true,
+      "dependencies": {
+        "ajv": "^6.10.2",
+        "lodash": "^4.17.14",
+        "slice-ansi": "^2.1.0",
+        "string-width": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/table/node_modules/emoji-regex": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+      "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
+      "dev": true
+    },
+    "node_modules/table/node_modules/is-fullwidth-code-point": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+      "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/table/node_modules/lodash": {
+      "version": "4.17.15",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+      "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+      "dev": true
+    },
+    "node_modules/table/node_modules/string-width": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+      "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+      "dev": true,
+      "dependencies": {
+        "emoji-regex": "^7.0.1",
+        "is-fullwidth-code-point": "^2.0.0",
+        "strip-ansi": "^5.1.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/terser": {
+      "version": "4.6.7",
+      "resolved": "https://registry.npmjs.org/terser/-/terser-4.6.7.tgz",
+      "integrity": "sha512-fmr7M1f7DBly5cX2+rFDvmGBAaaZyPrHYK4mMdHEDAdNTqXSZgSOfqsfGq2HqPGT/1V0foZZuCZFx8CHKgAk3g==",
+      "dev": true,
+      "dependencies": {
+        "commander": "^2.20.0",
+        "source-map": "~0.6.1",
+        "source-map-support": "~0.5.12"
+      },
+      "bin": {
+        "terser": "bin/terser"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/terser/node_modules/commander": {
+      "version": "2.20.3",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+      "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+      "dev": true
+    },
+    "node_modules/text-table": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+      "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+      "dev": true
+    },
+    "node_modules/through": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+      "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
+      "dev": true
+    },
+    "node_modules/tmp": {
+      "version": "0.0.33",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+      "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=",
+      "dev": true,
+      "dependencies": {
+        "os-tmpdir": "~1.0.2"
+      },
+      "engines": {
+        "node": ">=0.6.0"
+      }
+    },
+    "node_modules/to-array": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
+      "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=",
+      "dev": true
+    },
+    "node_modules/to-double-quotes": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/to-double-quotes/-/to-double-quotes-2.0.0.tgz",
+      "integrity": "sha1-qvIx1vqUiUn4GTAburRITYWI5Kc=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/to-object-path": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+      "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "kind-of": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/to-regex": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+      "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "regex-not": "^1.0.2",
+        "safe-regex": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "dev": true,
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/to-single-quotes": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/to-single-quotes/-/to-single-quotes-2.0.1.tgz",
+      "integrity": "sha1-fMKRUfD18sQZRvEZ9ZMv5VQXASU=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/toidentifier": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
+      "integrity": "sha1-fhvjRw8ed5SLxD2Uo8j013UrpVM=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.6"
+      }
+    },
+    "node_modules/tslib": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz",
+      "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==",
+      "dev": true
+    },
+    "node_modules/type-check": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+      "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+      "dev": true,
+      "dependencies": {
+        "prelude-ls": "~1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/type-fest": {
+      "version": "0.8.1",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+      "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/type-is": {
+      "version": "1.6.18",
+      "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+      "integrity": "sha1-TlUs0F3wlGfcvE73Od6J8s83wTE=",
+      "dev": true,
+      "dependencies": {
+        "media-typer": "0.3.0",
+        "mime-types": "~2.1.24"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/typedarray": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+      "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
+      "dev": true
+    },
+    "node_modules/ultron": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz",
+      "integrity": "sha1-n+FTahCmZKZSZqHjzPhf02MCvJw=",
+      "dev": true
+    },
+    "node_modules/underscore": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz",
+      "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=",
+      "dev": true
+    },
+    "node_modules/union-value": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+      "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "arr-union": "^3.1.0",
+        "get-value": "^2.0.6",
+        "is-extendable": "^0.1.1",
+        "set-value": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/universalify": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+      "integrity": "sha1-tkb2m+OULavOzJ1mOcgNwQXvqmY=",
+      "dev": true,
+      "engines": {
+        "node": ">= 4.0.0"
+      }
+    },
+    "node_modules/unpipe": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+      "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/unset-value": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+      "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "has-value": "^0.3.1",
+        "isobject": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/unset-value/node_modules/has-value": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+      "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "get-value": "^2.0.3",
+        "has-values": "^0.1.4",
+        "isobject": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/unset-value/node_modules/has-value/node_modules/isobject": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+      "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "isarray": "1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/unset-value/node_modules/has-values": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+      "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/unset-value/node_modules/isobject": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+      "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/uri-js": {
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
+      "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
+      "dev": true,
+      "dependencies": {
+        "punycode": "^2.1.0"
+      }
+    },
+    "node_modules/urix": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+      "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
+      "deprecated": "Please see https://github.com/lydell/urix#deprecated",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/use": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+      "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/useragent": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz",
+      "integrity": "sha1-IX+UOtVAyyEoZYqyP8lg9qiMmXI=",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "4.1.x",
+        "tmp": "0.0.x"
+      }
+    },
+    "node_modules/util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+      "dev": true
+    },
+    "node_modules/utile": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/utile/-/utile-0.2.1.tgz",
+      "integrity": "sha1-kwyI6ZCY1iIINMNWy9mncFItkNc=",
+      "dev": true,
+      "dependencies": {
+        "async": "~0.2.9",
+        "deep-equal": "*",
+        "i": "0.3.x",
+        "mkdirp": "0.x.x",
+        "ncp": "0.4.x",
+        "rimraf": "2.x.x"
+      },
+      "engines": {
+        "node": ">= 0.6.4"
+      }
+    },
+    "node_modules/utile/node_modules/async": {
+      "version": "0.2.10",
+      "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz",
+      "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=",
+      "dev": true
+    },
+    "node_modules/utils-merge": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+      "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
+    "node_modules/uuid": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz",
+      "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=",
+      "deprecated": "Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.",
+      "dev": true
+    },
+    "node_modules/v8-compile-cache": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz",
+      "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==",
+      "dev": true
+    },
+    "node_modules/void-elements": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz",
+      "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/vow": {
+      "version": "0.4.19",
+      "resolved": "https://registry.npmjs.org/vow/-/vow-0.4.19.tgz",
+      "integrity": "sha1-zF701rtpctgwgwp8ns+K2DSnxSU=",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
+    "node_modules/vow-fs": {
+      "version": "0.3.6",
+      "resolved": "https://registry.npmjs.org/vow-fs/-/vow-fs-0.3.6.tgz",
+      "integrity": "sha1-LUxZviLivyYY3fWXq0uqkjvnIA0=",
+      "dev": true,
+      "dependencies": {
+        "glob": "^7.0.5",
+        "uuid": "^2.0.2",
+        "vow": "^0.4.7",
+        "vow-queue": "^0.4.1"
+      },
+      "engines": {
+        "node": ">= 0.6.0"
+      }
+    },
+    "node_modules/vow-queue": {
+      "version": "0.4.3",
+      "resolved": "https://registry.npmjs.org/vow-queue/-/vow-queue-0.4.3.tgz",
+      "integrity": "sha1-S6j2S1bpISwNvlfxQFruvVTM540=",
+      "dev": true,
+      "dependencies": {
+        "vow": "^0.4.17"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/walk-sync": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/walk-sync/-/walk-sync-0.3.1.tgz",
+      "integrity": "sha1-VYoWrqyMDbWcAotzxm85doTs5GU=",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ensure-posix-path": "^1.0.0",
+        "matcher-collection": "^1.0.0"
+      }
+    },
+    "node_modules/which": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+      "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+      "dev": true,
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "which": "bin/which"
+      }
+    },
+    "node_modules/winston": {
+      "version": "0.8.3",
+      "resolved": "https://registry.npmjs.org/winston/-/winston-0.8.3.tgz",
+      "integrity": "sha1-ZLar9M0Brcrv1QCTk7HY6L7BnbA=",
+      "dev": true,
+      "dependencies": {
+        "async": "0.2.x",
+        "colors": "0.6.x",
+        "cycle": "1.0.x",
+        "eyes": "0.1.x",
+        "isstream": "0.1.x",
+        "pkginfo": "0.3.x",
+        "stack-trace": "0.0.x"
+      },
+      "engines": {
+        "node": ">= 0.6.0"
+      }
+    },
+    "node_modules/winston/node_modules/async": {
+      "version": "0.2.10",
+      "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz",
+      "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=",
+      "dev": true
+    },
+    "node_modules/winston/node_modules/colors": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz",
+      "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.1.90"
+      }
+    },
+    "node_modules/winston/node_modules/pkginfo": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.3.1.tgz",
+      "integrity": "sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE=",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
+    "node_modules/word-wrap": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+      "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+      "dev": true
+    },
+    "node_modules/write": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz",
+      "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==",
+      "dev": true,
+      "dependencies": {
+        "mkdirp": "^0.5.1"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/ws": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz",
+      "integrity": "sha1-8c+E/i1ekB686U767OeF8YeiKPI=",
+      "dev": true,
+      "dependencies": {
+        "async-limiter": "~1.0.0",
+        "safe-buffer": "~5.1.0",
+        "ultron": "~1.1.0"
+      }
+    },
+    "node_modules/xmlbuilder": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-3.1.0.tgz",
+      "integrity": "sha1-LIaIjy1OrehQ+jjKf3Ij9yCVFuE=",
+      "dev": true,
+      "dependencies": {
+        "lodash": "^3.5.0"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/xmlbuilder/node_modules/lodash": {
+      "version": "3.10.1",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
+      "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=",
+      "dev": true
+    },
+    "node_modules/xmlhttprequest-ssl": {
+      "version": "1.5.5",
+      "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz",
+      "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/yallist": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+      "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
+      "dev": true
+    },
+    "node_modules/yauzl": {
+      "version": "2.10.0",
+      "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+      "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
+      "dev": true,
+      "dependencies": {
+        "buffer-crc32": "~0.2.3",
+        "fd-slicer": "~1.1.0"
+      }
+    },
+    "node_modules/yeast": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
+      "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=",
+      "dev": true
+    }
+  },
   "dependencies": {
     "@babel/code-frame": {
       "version": "7.8.3",
@@ -42,12 +6439,6 @@
       "integrity": "sha1-nKUs2jY/aZxpRmwqbM2q2RPqenM=",
       "dev": true
     },
-    "JSV": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/JSV/-/JSV-4.0.2.tgz",
-      "integrity": "sha1-0Hf2glVx+CEy+d/67Vh7QCn+/1c=",
-      "dev": true
-    },
     "accepts": {
       "version": "1.3.7",
       "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
@@ -68,7 +6459,8 @@
       "version": "5.2.0",
       "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz",
       "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==",
-      "dev": true
+      "dev": true,
+      "requires": {}
     },
     "after": {
       "version": "0.8.2",
@@ -145,12 +6537,50 @@
         "sprintf-js": "~1.0.2"
       }
     },
+    "arr-diff": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
+      "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "arr-flatten": "^1.0.1"
+      }
+    },
+    "arr-flatten": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+      "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+      "dev": true,
+      "peer": true
+    },
+    "arr-union": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+      "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
+      "dev": true,
+      "peer": true
+    },
+    "array-unique": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
+      "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
+      "dev": true,
+      "peer": true
+    },
     "arraybuffer.slice": {
       "version": "0.0.7",
       "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
       "integrity": "sha1-O7xCdd1YTMGxCAm4nU6LY6aednU=",
       "dev": true
     },
+    "assign-symbols": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+      "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
+      "dev": true,
+      "peer": true
+    },
     "astral-regex": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
@@ -174,12 +6604,26 @@
         }
       }
     },
+    "async-each": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
+      "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==",
+      "dev": true,
+      "peer": true
+    },
     "async-limiter": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
       "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
       "dev": true
     },
+    "atob": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+      "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+      "dev": true,
+      "peer": true
+    },
     "babel-runtime": {
       "version": "6.26.0",
       "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
@@ -208,6 +6652,41 @@
       "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
       "dev": true
     },
+    "base": {
+      "version": "0.11.2",
+      "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+      "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "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"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-descriptor": "^1.0.0"
+          }
+        },
+        "isobject": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
     "base64-arraybuffer": {
       "version": "0.1.5",
       "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
@@ -235,6 +6714,17 @@
       "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==",
       "dev": true
     },
+    "bindings": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
+      "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
+      "dev": true,
+      "optional": true,
+      "peer": true,
+      "requires": {
+        "file-uri-to-path": "1.0.0"
+      }
+    },
     "blob": {
       "version": "0.0.5",
       "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz",
@@ -341,6 +6831,33 @@
       "integrity": "sha1-9s95M6Ng4FiPqf3oVlHNx/gF0fY=",
       "dev": true
     },
+    "cache-base": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+      "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "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"
+      },
+      "dependencies": {
+        "isobject": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
     "callsite": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
@@ -386,6 +6903,79 @@
         "readdirp": "~3.3.0"
       }
     },
+    "class-utils": {
+      "version": "0.3.6",
+      "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+      "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "arr-union": "^3.1.0",
+        "define-property": "^0.2.5",
+        "isobject": "^3.0.0",
+        "static-extend": "^0.1.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "0.1.6",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+          "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "0.1.4",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+          "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          }
+        },
+        "is-descriptor": {
+          "version": "0.1.6",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+          "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-accessor-descriptor": "^0.1.6",
+            "is-data-descriptor": "^0.1.4",
+            "kind-of": "^5.0.0"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "5.1.0",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+              "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+              "dev": true,
+              "peer": true
+            }
+          }
+        },
+        "isobject": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
     "cli": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz",
@@ -428,6 +7018,17 @@
       "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
       "dev": true
     },
+    "collection-visit": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+      "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "map-visit": "^1.0.0",
+        "object-visit": "^1.0.0"
+      }
+    },
     "color-convert": {
       "version": "1.9.3",
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -550,6 +7151,13 @@
       "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=",
       "dev": true
     },
+    "copy-descriptor": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+      "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
+      "dev": true,
+      "peer": true
+    },
     "core-js": {
       "version": "2.6.5",
       "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.5.tgz",
@@ -644,6 +7252,13 @@
         "ms": "^2.1.1"
       }
     },
+    "decode-uri-component": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
+      "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
+      "dev": true,
+      "peer": true
+    },
     "deep-equal": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
@@ -656,12 +7271,42 @@
       "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
       "dev": true
     },
+    "define-property": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+      "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "is-descriptor": "^1.0.2",
+        "isobject": "^3.0.1"
+      },
+      "dependencies": {
+        "isobject": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
     "depd": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
       "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
       "dev": true
     },
+    "detect-file": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-0.1.0.tgz",
+      "integrity": "sha1-STXe39lIhkjgBrASlWbpOGcR6mM=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "fs-exists-sync": "^0.1.0"
+      }
+    },
     "di": {
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz",
@@ -830,6 +7475,13 @@
         "has-binary2": "~1.0.2"
       }
     },
+    "ensure-posix-path": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/ensure-posix-path/-/ensure-posix-path-1.1.1.tgz",
+      "integrity": "sha512-VWU0/zXzVbeJNXvME/5EmLuEj2TauvoaTz6aFYK1Z92JCBlDlZ3Gu0tuGR42kpW1754ywTs+QB0g5TP0oj9Zaw==",
+      "dev": true,
+      "peer": true
+    },
     "ent": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz",
@@ -993,18 +7645,104 @@
       "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==",
       "dev": true
     },
+    "exists-stat": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/exists-stat/-/exists-stat-1.0.0.tgz",
+      "integrity": "sha1-BmDjUlouidnkRhKUQMJy7foktSk=",
+      "dev": true,
+      "peer": true
+    },
     "exit": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
       "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=",
       "dev": true
     },
+    "expand-brackets": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
+      "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "is-posix-bracket": "^0.1.0"
+      }
+    },
+    "expand-range": {
+      "version": "1.8.2",
+      "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
+      "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "fill-range": "^2.1.0"
+      },
+      "dependencies": {
+        "fill-range": {
+          "version": "2.2.4",
+          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz",
+          "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-number": "^2.1.0",
+            "isobject": "^2.0.0",
+            "randomatic": "^3.0.0",
+            "repeat-element": "^1.1.2",
+            "repeat-string": "^1.5.2"
+          }
+        },
+        "is-number": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
+          "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          }
+        }
+      }
+    },
+    "expand-tilde": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz",
+      "integrity": "sha1-C4HrqJflo9MdHD0QL48BRB5VlEk=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "os-homedir": "^1.0.1"
+      }
+    },
     "extend": {
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
       "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
       "dev": true
     },
+    "extend-shallow": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+      "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "assign-symbols": "^1.0.0",
+        "is-extendable": "^1.0.1"
+      },
+      "dependencies": {
+        "is-extendable": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-plain-object": "^2.0.4"
+          }
+        }
+      }
+    },
     "external-editor": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
@@ -1016,6 +7754,25 @@
         "tmp": "^0.0.33"
       }
     },
+    "extglob": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
+      "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "is-extglob": "^1.0.0"
+      },
+      "dependencies": {
+        "is-extglob": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+          "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
     "extract-zip": {
       "version": "1.7.0",
       "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz",
@@ -1111,6 +7868,21 @@
         "flat-cache": "^2.0.1"
       }
     },
+    "file-uri-to-path": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
+      "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
+      "dev": true,
+      "optional": true,
+      "peer": true
+    },
+    "filename-regex": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
+      "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=",
+      "dev": true,
+      "peer": true
+    },
     "fill-range": {
       "version": "7.0.1",
       "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@@ -1152,6 +7924,38 @@
         }
       }
     },
+    "findup-sync": {
+      "version": "0.4.3",
+      "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.4.3.tgz",
+      "integrity": "sha1-QAQ5Kee8YK3wt/SCfExudaDeyhI=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "detect-file": "^0.1.0",
+        "is-glob": "^2.0.1",
+        "micromatch": "^2.3.7",
+        "resolve-dir": "^0.1.0"
+      },
+      "dependencies": {
+        "is-extglob": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+          "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+          "dev": true,
+          "peer": true
+        },
+        "is-glob": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+          "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-extglob": "^1.0.0"
+          }
+        }
+      }
+    },
     "flat-cache": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz",
@@ -1189,6 +7993,40 @@
         }
       }
     },
+    "for-in": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+      "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+      "dev": true,
+      "peer": true
+    },
+    "for-own": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
+      "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "for-in": "^1.0.1"
+      }
+    },
+    "fragment-cache": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+      "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "map-cache": "^0.2.2"
+      }
+    },
+    "fs-exists-sync": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz",
+      "integrity": "sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=",
+      "dev": true,
+      "peer": true
+    },
     "fs-extra": {
       "version": "7.0.1",
       "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
@@ -1219,6 +8057,13 @@
       "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
       "dev": true
     },
+    "get-value": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+      "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
+      "dev": true,
+      "peer": true
+    },
     "glob": {
       "version": "7.1.3",
       "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
@@ -1233,6 +8078,46 @@
         "path-is-absolute": "^1.0.0"
       }
     },
+    "glob-base": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
+      "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "glob-parent": "^2.0.0",
+        "is-glob": "^2.0.0"
+      },
+      "dependencies": {
+        "glob-parent": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
+          "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-glob": "^2.0.0"
+          }
+        },
+        "is-extglob": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+          "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+          "dev": true,
+          "peer": true
+        },
+        "is-glob": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+          "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-extglob": "^1.0.0"
+          }
+        }
+      }
+    },
     "glob-parent": {
       "version": "5.1.1",
       "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
@@ -1242,6 +8127,30 @@
         "is-glob": "^4.0.1"
       }
     },
+    "global-modules": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz",
+      "integrity": "sha1-6lo77ULG1s6ZWk+KEmm12uIjgo0=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "global-prefix": "^0.1.4",
+        "is-windows": "^0.2.0"
+      }
+    },
+    "global-prefix": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.5.tgz",
+      "integrity": "sha1-jTvGuNo8qBEqFg2NSW/wRiv+948=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "homedir-polyfill": "^1.0.0",
+        "ini": "^1.3.4",
+        "is-windows": "^0.2.0",
+        "which": "^1.2.12"
+      }
+    },
     "globals": {
       "version": "12.4.0",
       "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
@@ -1315,6 +8224,82 @@
       "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
       "dev": true
     },
+    "has-value": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+      "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "get-value": "^2.0.6",
+        "has-values": "^1.0.0",
+        "isobject": "^3.0.0"
+      },
+      "dependencies": {
+        "isobject": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "has-values": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+      "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "is-number": "^3.0.0",
+        "kind-of": "^4.0.0"
+      },
+      "dependencies": {
+        "is-number": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+          "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "3.2.2",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+              "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+              "dev": true,
+              "peer": true,
+              "requires": {
+                "is-buffer": "^1.1.5"
+              }
+            }
+          }
+        },
+        "kind-of": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+          "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "homedir-polyfill": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
+      "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "parse-passwd": "^1.0.0"
+      }
+    },
     "htmlparser2": {
       "version": "3.8.3",
       "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz",
@@ -1453,6 +8438,13 @@
       "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
       "dev": true
     },
+    "ini": {
+      "version": "1.3.8",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+      "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+      "dev": true,
+      "peer": true
+    },
     "inquirer": {
       "version": "7.1.0",
       "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.1.0.tgz",
@@ -1547,6 +8539,25 @@
         }
       }
     },
+    "is-accessor-descriptor": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+      "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "kind-of": "^6.0.0"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "6.0.3",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+          "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
     "is-binary-path": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
@@ -1556,6 +8567,77 @@
         "binary-extensions": "^2.0.0"
       }
     },
+    "is-buffer": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+      "dev": true,
+      "peer": true
+    },
+    "is-data-descriptor": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+      "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "kind-of": "^6.0.0"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "6.0.3",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+          "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "is-descriptor": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+      "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "is-accessor-descriptor": "^1.0.0",
+        "is-data-descriptor": "^1.0.0",
+        "kind-of": "^6.0.2"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "6.0.3",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+          "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "is-dotfile": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
+      "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=",
+      "dev": true,
+      "peer": true
+    },
+    "is-equal-shallow": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
+      "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "is-primitive": "^2.0.0"
+      }
+    },
+    "is-extendable": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+      "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
+      "dev": true,
+      "peer": true
+    },
     "is-extglob": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -1583,6 +8665,39 @@
       "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
       "dev": true
     },
+    "is-plain-object": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "isobject": "^3.0.1"
+      },
+      "dependencies": {
+        "isobject": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "is-posix-bracket": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz",
+      "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=",
+      "dev": true,
+      "peer": true
+    },
+    "is-primitive": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
+      "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=",
+      "dev": true,
+      "peer": true
+    },
     "is-promise": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
@@ -1595,6 +8710,13 @@
       "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
       "dev": true
     },
+    "is-windows": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz",
+      "integrity": "sha1-3hqm1j6indJIc3tp8f+LgALSEIw=",
+      "dev": true,
+      "peer": true
+    },
     "is-wsl": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.1.1.tgz",
@@ -1622,6 +8744,16 @@
       "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
       "dev": true
     },
+    "isobject": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+      "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "isarray": "1.0.0"
+      }
+    },
     "isstream": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
@@ -1871,6 +9003,12 @@
         "nomnom": "^1.5.x"
       }
     },
+    "JSV": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/JSV/-/JSV-4.0.2.tgz",
+      "integrity": "sha1-0Hf2glVx+CEy+d/67Vh7QCn+/1c=",
+      "dev": true
+    },
     "karma": {
       "version": "4.4.1",
       "resolved": "https://registry.npmjs.org/karma/-/karma-4.4.1.tgz",
@@ -1935,7 +9073,18 @@
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/karma-qunit/-/karma-qunit-4.0.0.tgz",
       "integrity": "sha512-sGuMyTMbiA2zq/aV43uduwf58mMiMDiG6YH3dvaarQnwFLmyRD1i8356TndX8lFeVSOtykowtBtpcdGxyuezTA==",
-      "dev": true
+      "dev": true,
+      "requires": {}
+    },
+    "kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "is-buffer": "^1.1.5"
+      }
     },
     "levn": {
       "version": "0.3.0",
@@ -2001,12 +9150,109 @@
         }
       }
     },
+    "map-cache": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+      "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
+      "dev": true,
+      "peer": true
+    },
+    "map-visit": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+      "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "object-visit": "^1.0.0"
+      }
+    },
+    "matcher-collection": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/matcher-collection/-/matcher-collection-1.1.2.tgz",
+      "integrity": "sha512-YQ/teqaOIIfUHedRam08PB3NK7Mjct6BvzRnJmpGDm8uFXpNr1sbY4yuflI5JcEs6COpYA0FpRQhSDBf1tT95g==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "minimatch": "^3.0.2"
+      }
+    },
+    "math-random": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz",
+      "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==",
+      "dev": true,
+      "peer": true
+    },
     "media-typer": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
       "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
       "dev": true
     },
+    "micromatch": {
+      "version": "2.3.11",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
+      "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "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"
+      },
+      "dependencies": {
+        "braces": {
+          "version": "1.8.5",
+          "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
+          "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "expand-range": "^1.8.1",
+            "preserve": "^0.2.0",
+            "repeat-element": "^1.1.2"
+          }
+        },
+        "is-extglob": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+          "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+          "dev": true,
+          "peer": true
+        },
+        "is-glob": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+          "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-extglob": "^1.0.0"
+          }
+        },
+        "normalize-path": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+          "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "remove-trailing-separator": "^1.0.1"
+          }
+        }
+      }
+    },
     "mime": {
       "version": "2.4.4",
       "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz",
@@ -2049,6 +9295,29 @@
       "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
       "dev": true
     },
+    "mixin-deep": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
+      "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "for-in": "^1.0.2",
+        "is-extendable": "^1.0.1"
+      },
+      "dependencies": {
+        "is-extendable": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-plain-object": "^2.0.4"
+          }
+        }
+      }
+    },
     "mkdirp": {
       "version": "0.5.1",
       "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
@@ -2070,6 +9339,64 @@
       "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
       "dev": true
     },
+    "nan": {
+      "version": "2.15.0",
+      "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz",
+      "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==",
+      "dev": true,
+      "optional": true,
+      "peer": true
+    },
+    "nanomatch": {
+      "version": "1.2.13",
+      "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+      "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "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"
+      },
+      "dependencies": {
+        "arr-diff": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+          "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
+          "dev": true,
+          "peer": true
+        },
+        "array-unique": {
+          "version": "0.3.2",
+          "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+          "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
+          "dev": true,
+          "peer": true
+        },
+        "is-windows": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+          "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+          "dev": true,
+          "peer": true
+        },
+        "kind-of": {
+          "version": "6.0.3",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+          "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
     "natural-compare": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
@@ -2147,6 +9474,120 @@
       "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=",
       "dev": true
     },
+    "object-copy": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+      "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "copy-descriptor": "^0.1.0",
+        "define-property": "^0.2.5",
+        "kind-of": "^3.0.3"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "0.1.6",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+          "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "0.1.4",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+          "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          }
+        },
+        "is-descriptor": {
+          "version": "0.1.6",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+          "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-accessor-descriptor": "^0.1.6",
+            "is-data-descriptor": "^0.1.4",
+            "kind-of": "^5.0.0"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "5.1.0",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+              "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+              "dev": true,
+              "peer": true
+            }
+          }
+        }
+      }
+    },
+    "object-visit": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+      "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "isobject": "^3.0.0"
+      },
+      "dependencies": {
+        "isobject": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "object.omit": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
+      "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "for-own": "^0.1.4",
+        "is-extendable": "^0.1.1"
+      }
+    },
+    "object.pick": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+      "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "isobject": "^3.0.1"
+      },
+      "dependencies": {
+        "isobject": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
     "on-finished": {
       "version": "2.3.0",
       "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
@@ -2206,6 +9647,13 @@
         "word-wrap": "~1.2.3"
       }
     },
+    "os-homedir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+      "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
+      "dev": true,
+      "peer": true
+    },
     "os-tmpdir": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
@@ -2221,6 +9669,45 @@
         "callsites": "^3.0.0"
       }
     },
+    "parse-glob": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
+      "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "glob-base": "^0.3.0",
+        "is-dotfile": "^1.0.0",
+        "is-extglob": "^1.0.0",
+        "is-glob": "^2.0.0"
+      },
+      "dependencies": {
+        "is-extglob": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+          "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+          "dev": true,
+          "peer": true
+        },
+        "is-glob": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+          "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-extglob": "^1.0.0"
+          }
+        }
+      }
+    },
+    "parse-passwd": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
+      "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
+      "dev": true,
+      "peer": true
+    },
     "parseqs": {
       "version": "0.0.5",
       "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz",
@@ -2245,6 +9732,13 @@
       "integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ=",
       "dev": true
     },
+    "pascalcase": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+      "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
+      "dev": true,
+      "peer": true
+    },
     "path-is-absolute": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
@@ -2287,12 +9781,26 @@
       "integrity": "sha1-tUGO8EOd5UJfxJlQQtztFPsqhP8=",
       "dev": true
     },
+    "posix-character-classes": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+      "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
+      "dev": true,
+      "peer": true
+    },
     "prelude-ls": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
       "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
       "dev": true
     },
+    "preserve": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
+      "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=",
+      "dev": true,
+      "peer": true
+    },
     "process-nextick-args": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
@@ -2360,34 +9868,519 @@
           "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
           "dev": true,
           "requires": {
-            "async-limiter": "~1.0.0"
+            "async-limiter": "~1.0.0"
+          }
+        }
+      }
+    },
+    "qjobs": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz",
+      "integrity": "sha1-xF6cYYAL0IfviNfiVkI73Unl0HE=",
+      "dev": true
+    },
+    "qs": {
+      "version": "6.7.0",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
+      "integrity": "sha1-QdwaAV49WB8WIXdr4xr7KHapsbw=",
+      "dev": true
+    },
+    "qunit": {
+      "version": "2.9.3",
+      "resolved": "https://registry.npmjs.org/qunit/-/qunit-2.9.3.tgz",
+      "integrity": "sha512-RH4VYSaVsNRDthMFFboTJAJ8q4kJM5LvOqWponKUYPEAeOcmc/YFV1QsZ7ikknA3TjqliWFJYEV63vvVXaALmQ==",
+      "dev": true,
+      "requires": {
+        "commander": "2.12.2",
+        "js-reporters": "1.2.1",
+        "minimatch": "3.0.4",
+        "node-watch": "0.6.1",
+        "resolve": "1.9.0"
+      }
+    },
+    "qunit-assert-close": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/qunit-assert-close/-/qunit-assert-close-2.1.2.tgz",
+      "integrity": "sha1-cC1pSSr1kBCi5AQN1k/gzS4EPuE=",
+      "dev": true,
+      "requires": {}
+    },
+    "qunitjs": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/qunitjs/-/qunitjs-2.4.1.tgz",
+      "integrity": "sha512-by/2zYvsNdS6Q6Ev6UJ3qJK+OYVlTzWlQ4afaeYMhVh1dd2K3N1ZZKCrCm3WSWPnz5ELMT8WyJRcVy5PXT2y+Q==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "chokidar": "1.6.1",
+        "commander": "2.9.0",
+        "exists-stat": "1.0.0",
+        "findup-sync": "0.4.3",
+        "js-reporters": "1.2.0",
+        "resolve": "1.3.2",
+        "walk-sync": "0.3.1"
+      },
+      "dependencies": {
+        "anymatch": {
+          "version": "1.3.2",
+          "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz",
+          "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "micromatch": "^2.1.5",
+            "normalize-path": "^2.0.0"
+          }
+        },
+        "arr-diff": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+          "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
+          "dev": true,
+          "peer": true
+        },
+        "array-unique": {
+          "version": "0.3.2",
+          "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+          "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
+          "dev": true,
+          "peer": true
+        },
+        "binary-extensions": {
+          "version": "1.13.1",
+          "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
+          "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
+          "dev": true,
+          "peer": true
+        },
+        "braces": {
+          "version": "2.3.2",
+          "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+          "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "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"
+          },
+          "dependencies": {
+            "extend-shallow": {
+              "version": "2.0.1",
+              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+              "dev": true,
+              "peer": true,
+              "requires": {
+                "is-extendable": "^0.1.0"
+              }
+            }
+          }
+        },
+        "chokidar": {
+          "version": "1.6.1",
+          "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.6.1.tgz",
+          "integrity": "sha1-L0RHq16W5Q+z14n9kNTHLg5McMI=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "anymatch": "^1.3.0",
+            "async-each": "^1.0.0",
+            "fsevents": "^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"
+          }
+        },
+        "commander": {
+          "version": "2.9.0",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
+          "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "graceful-readlink": ">= 1.0.0"
+          }
+        },
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "expand-brackets": {
+          "version": "2.1.4",
+          "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+          "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "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"
+          },
+          "dependencies": {
+            "define-property": {
+              "version": "0.2.5",
+              "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+              "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+              "dev": true,
+              "peer": true,
+              "requires": {
+                "is-descriptor": "^0.1.0"
+              }
+            },
+            "extend-shallow": {
+              "version": "2.0.1",
+              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+              "dev": true,
+              "peer": true,
+              "requires": {
+                "is-extendable": "^0.1.0"
+              }
+            },
+            "is-descriptor": {
+              "version": "0.1.6",
+              "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+              "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+              "dev": true,
+              "peer": true,
+              "requires": {
+                "is-accessor-descriptor": "^0.1.6",
+                "is-data-descriptor": "^0.1.4",
+                "kind-of": "^5.0.0"
+              }
+            },
+            "kind-of": {
+              "version": "5.1.0",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+              "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+              "dev": true,
+              "peer": true
+            }
+          }
+        },
+        "extglob": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+          "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "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"
+          },
+          "dependencies": {
+            "define-property": {
+              "version": "1.0.0",
+              "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+              "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+              "dev": true,
+              "peer": true,
+              "requires": {
+                "is-descriptor": "^1.0.0"
+              }
+            },
+            "extend-shallow": {
+              "version": "2.0.1",
+              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+              "dev": true,
+              "peer": true,
+              "requires": {
+                "is-extendable": "^0.1.0"
+              }
+            }
+          }
+        },
+        "fill-range": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+          "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "extend-shallow": "^2.0.1",
+            "is-number": "^3.0.0",
+            "repeat-string": "^1.6.1",
+            "to-regex-range": "^2.1.0"
+          },
+          "dependencies": {
+            "extend-shallow": {
+              "version": "2.0.1",
+              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+              "dev": true,
+              "peer": true,
+              "requires": {
+                "is-extendable": "^0.1.0"
+              }
+            }
+          }
+        },
+        "fsevents": {
+          "version": "1.2.13",
+          "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
+          "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
+          "dev": true,
+          "optional": true,
+          "peer": true,
+          "requires": {
+            "bindings": "^1.5.0",
+            "nan": "^2.12.1"
+          }
+        },
+        "glob-parent": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
+          "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-glob": "^2.0.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "0.1.6",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+          "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "3.2.2",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+              "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+              "dev": true,
+              "peer": true,
+              "requires": {
+                "is-buffer": "^1.1.5"
+              }
+            }
+          }
+        },
+        "is-binary-path": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
+          "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "binary-extensions": "^1.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "0.1.4",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+          "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "3.2.2",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+              "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+              "dev": true,
+              "peer": true,
+              "requires": {
+                "is-buffer": "^1.1.5"
+              }
+            }
+          }
+        },
+        "is-extglob": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+          "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+          "dev": true,
+          "peer": true
+        },
+        "is-glob": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+          "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-extglob": "^1.0.0"
+          }
+        },
+        "is-number": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+          "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "3.2.2",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+              "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+              "dev": true,
+              "peer": true,
+              "requires": {
+                "is-buffer": "^1.1.5"
+              }
+            }
+          }
+        },
+        "isobject": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+          "dev": true,
+          "peer": true
+        },
+        "js-reporters": {
+          "version": "1.2.0",
+          "resolved": "https://registry.npmjs.org/js-reporters/-/js-reporters-1.2.0.tgz",
+          "integrity": "sha1-fPLLaYGWaEeQNQ0MTKB/Su2ewX4=",
+          "dev": true,
+          "peer": true
+        },
+        "kind-of": {
+          "version": "6.0.3",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+          "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+          "dev": true,
+          "peer": true
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true,
+          "peer": true
+        },
+        "normalize-path": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+          "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "remove-trailing-separator": "^1.0.1"
+          }
+        },
+        "readdirp": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
+          "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "graceful-fs": "^4.1.11",
+            "micromatch": "^3.1.10",
+            "readable-stream": "^2.0.2"
+          },
+          "dependencies": {
+            "micromatch": {
+              "version": "3.1.10",
+              "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+              "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+              "dev": true,
+              "peer": true,
+              "requires": {
+                "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"
+              }
+            }
+          }
+        },
+        "resolve": {
+          "version": "1.3.2",
+          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.3.2.tgz",
+          "integrity": "sha1-HwRCyeDLuBNuh7kwX5MvRsfygjU=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "path-parse": "^1.0.5"
+          }
+        },
+        "to-regex-range": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+          "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-number": "^3.0.0",
+            "repeat-string": "^1.6.1"
           }
         }
       }
     },
-    "qjobs": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz",
-      "integrity": "sha1-xF6cYYAL0IfviNfiVkI73Unl0HE=",
-      "dev": true
-    },
-    "qs": {
-      "version": "6.7.0",
-      "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
-      "integrity": "sha1-QdwaAV49WB8WIXdr4xr7KHapsbw=",
-      "dev": true
-    },
-    "qunit": {
-      "version": "2.9.3",
-      "resolved": "https://registry.npmjs.org/qunit/-/qunit-2.9.3.tgz",
-      "integrity": "sha512-RH4VYSaVsNRDthMFFboTJAJ8q4kJM5LvOqWponKUYPEAeOcmc/YFV1QsZ7ikknA3TjqliWFJYEV63vvVXaALmQ==",
+    "randomatic": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz",
+      "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==",
       "dev": true,
+      "peer": true,
       "requires": {
-        "commander": "2.12.2",
-        "js-reporters": "1.2.1",
-        "minimatch": "3.0.4",
-        "node-watch": "0.6.1",
-        "resolve": "1.9.0"
+        "is-number": "^4.0.0",
+        "kind-of": "^6.0.0",
+        "math-random": "^1.0.1"
+      },
+      "dependencies": {
+        "is-number": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
+          "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
+          "dev": true,
+          "peer": true
+        },
+        "kind-of": {
+          "version": "6.0.3",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+          "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+          "dev": true,
+          "peer": true
+        }
       }
     },
     "range-parser": {
@@ -2447,12 +10440,54 @@
       "integrity": "sha1-vgWtf5v30i4Fb5cmzuUBf78Z4uk=",
       "dev": true
     },
+    "regex-cache": {
+      "version": "0.4.4",
+      "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
+      "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "is-equal-shallow": "^0.1.3"
+      }
+    },
+    "regex-not": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+      "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "extend-shallow": "^3.0.2",
+        "safe-regex": "^1.1.0"
+      }
+    },
     "regexpp": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz",
       "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==",
       "dev": true
     },
+    "remove-trailing-separator": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+      "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
+      "dev": true,
+      "peer": true
+    },
+    "repeat-element": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz",
+      "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==",
+      "dev": true,
+      "peer": true
+    },
+    "repeat-string": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+      "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
+      "dev": true,
+      "peer": true
+    },
     "requires-port": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
@@ -2474,12 +10509,30 @@
         "path-parse": "^1.0.6"
       }
     },
+    "resolve-dir": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz",
+      "integrity": "sha1-shklmlYC+sXFxJatiUpujMQwJh4=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "expand-tilde": "^1.2.2",
+        "global-modules": "^0.2.3"
+      }
+    },
     "resolve-from": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
       "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
       "dev": true
     },
+    "resolve-url": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+      "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
+      "dev": true,
+      "peer": true
+    },
     "restore-cursor": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
@@ -2490,6 +10543,13 @@
         "signal-exit": "^3.0.2"
       }
     },
+    "ret": {
+      "version": "0.1.15",
+      "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+      "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
+      "dev": true,
+      "peer": true
+    },
     "revalidator": {
       "version": "0.1.8",
       "resolved": "https://registry.npmjs.org/revalidator/-/revalidator-0.1.8.tgz",
@@ -2535,6 +10595,16 @@
       "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=",
       "dev": true
     },
+    "safe-regex": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+      "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "ret": "~0.1.10"
+      }
+    },
     "safer-buffer": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
@@ -2547,6 +10617,31 @@
       "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
       "dev": true
     },
+    "set-value": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
+      "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "extend-shallow": "^2.0.1",
+        "is-extendable": "^0.1.1",
+        "is-plain-object": "^2.0.3",
+        "split-string": "^3.0.1"
+      },
+      "dependencies": {
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        }
+      }
+    },
     "setprototypeof": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
@@ -2599,6 +10694,151 @@
         }
       }
     },
+    "snapdragon": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+      "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "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"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        },
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "0.1.6",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+          "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "0.1.4",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+          "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          }
+        },
+        "is-descriptor": {
+          "version": "0.1.6",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+          "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-accessor-descriptor": "^0.1.6",
+            "is-data-descriptor": "^0.1.4",
+            "kind-of": "^5.0.0"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "5.1.0",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+              "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+              "dev": true,
+              "peer": true
+            }
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true,
+          "peer": true
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "snapdragon-node": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+      "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "define-property": "^1.0.0",
+        "isobject": "^3.0.0",
+        "snapdragon-util": "^3.0.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-descriptor": "^1.0.0"
+          }
+        },
+        "isobject": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
+    "snapdragon-util": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+      "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "kind-of": "^3.2.0"
+      }
+    },
     "socket.io": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz",
@@ -2715,6 +10955,20 @@
       "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
       "dev": true
     },
+    "source-map-resolve": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
+      "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "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": {
       "version": "0.5.16",
       "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz",
@@ -2725,6 +10979,23 @@
         "source-map": "^0.6.0"
       }
     },
+    "source-map-url": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz",
+      "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==",
+      "dev": true,
+      "peer": true
+    },
+    "split-string": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+      "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "extend-shallow": "^3.0.0"
+      }
+    },
     "sprintf-js": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
@@ -2737,6 +11008,70 @@
       "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=",
       "dev": true
     },
+    "static-extend": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+      "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "define-property": "^0.2.5",
+        "object-copy": "^0.1.0"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "0.1.6",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+          "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "0.1.4",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+          "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          }
+        },
+        "is-descriptor": {
+          "version": "0.1.6",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+          "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "is-accessor-descriptor": "^0.1.6",
+            "is-data-descriptor": "^0.1.4",
+            "kind-of": "^5.0.0"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "5.1.0",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+              "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+              "dev": true,
+              "peer": true
+            }
+          }
+        }
+      }
+    },
     "statuses": {
       "version": "1.5.0",
       "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
@@ -2773,6 +11108,15 @@
         }
       }
     },
+    "string_decoder": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "~5.1.0"
+      }
+    },
     "string-width": {
       "version": "4.2.0",
       "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
@@ -2795,15 +11139,6 @@
         }
       }
     },
-    "string_decoder": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
-      "dev": true,
-      "requires": {
-        "safe-buffer": "~5.1.0"
-      }
-    },
     "strip-ansi": {
       "version": "5.2.0",
       "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
@@ -2946,6 +11281,29 @@
       "integrity": "sha1-qvIx1vqUiUn4GTAburRITYWI5Kc=",
       "dev": true
     },
+    "to-object-path": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+      "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "kind-of": "^3.0.2"
+      }
+    },
+    "to-regex": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+      "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "regex-not": "^1.0.2",
+        "safe-regex": "^1.1.0"
+      }
+    },
     "to-regex-range": {
       "version": "5.0.1",
       "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -3016,6 +11374,19 @@
       "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=",
       "dev": true
     },
+    "union-value": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+      "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "arr-union": "^3.1.0",
+        "get-value": "^2.0.6",
+        "is-extendable": "^0.1.1",
+        "set-value": "^2.0.1"
+      }
+    },
     "universalify": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
@@ -3028,6 +11399,57 @@
       "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
       "dev": true
     },
+    "unset-value": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+      "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "has-value": "^0.3.1",
+        "isobject": "^3.0.0"
+      },
+      "dependencies": {
+        "has-value": {
+          "version": "0.3.1",
+          "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+          "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "get-value": "^2.0.3",
+            "has-values": "^0.1.4",
+            "isobject": "^2.0.0"
+          },
+          "dependencies": {
+            "isobject": {
+              "version": "2.1.0",
+              "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+              "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+              "dev": true,
+              "peer": true,
+              "requires": {
+                "isarray": "1.0.0"
+              }
+            }
+          }
+        },
+        "has-values": {
+          "version": "0.1.4",
+          "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+          "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=",
+          "dev": true,
+          "peer": true
+        },
+        "isobject": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+          "dev": true,
+          "peer": true
+        }
+      }
+    },
     "uri-js": {
       "version": "4.2.2",
       "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
@@ -3037,6 +11459,20 @@
         "punycode": "^2.1.0"
       }
     },
+    "urix": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+      "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
+      "dev": true,
+      "peer": true
+    },
+    "use": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+      "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
+      "dev": true,
+      "peer": true
+    },
     "useragent": {
       "version": "2.3.0",
       "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz",
@@ -3126,6 +11562,17 @@
         "vow": "^0.4.17"
       }
     },
+    "walk-sync": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/walk-sync/-/walk-sync-0.3.1.tgz",
+      "integrity": "sha1-VYoWrqyMDbWcAotzxm85doTs5GU=",
+      "dev": true,
+      "peer": true,
+      "requires": {
+        "ensure-posix-path": "^1.0.0",
+        "matcher-collection": "^1.0.0"
+      }
+    },
     "which": {
       "version": "1.3.1",
       "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
diff --git a/package.json b/package.json
index 72953ea..2643ee2 100644
--- a/package.json
+++ b/package.json
@@ -24,9 +24,9 @@
   "scripts": {
     "all": "npm run build && npm run test && npm run lint",
     "build": "node build.js",
-    "lint": "jshint src test/*.js && jscs src test/*.js",
-    "new-lint": "eslint src test",
-    "test": "karma start --log-level debug --single-run=true"
+    "lint": "npm exec -- jshint src test/*.js && npm exec -- jscs src test/*.js",
+    "new-lint": "npm exec -- eslint src test",
+    "test": "npm exec -- karma start --log-level debug --single-run=true"
   },
   "devDependencies": {
     "eslint": "^6.8.0",
@@ -39,8 +39,8 @@
     "ls": "^0.2.1",
     "puppeteer": "^2.1.1",
     "qunit": "^2.9.3",
+    "qunit-assert-close": "^2.1.2",
     "syn": "^0.14.1",
     "terser": "^4.6.7"
-  },
-  "dependencies": {}
+  }
 }
diff --git a/qunit_test_runner.html b/qunit_test_runner.html
index 749f7ef..251874d 100644
--- a/qunit_test_runner.html
+++ b/qunit_test_runner.html
@@ -13,6 +13,7 @@
   <div id="qunit"></div>
   <div id="qunit-fixture"></div>
   <script src="node_modules/qunit/qunit/qunit.js"></script>
+  <script src="node_modules/qunit-assert-close/qunit-assert-close.js"></script>
   <!-- The QUnit tests. -->
   <script src="test/helpers.js"></script>
   <!-- Core tests -->
@@ -20,5 +21,9 @@
   <script src="test/non_default.js"></script>
   <!-- Plugins -->
   <script src="src/plugins/navigation/navigation_tests.js"></script>
+  <script src="test/plugins/rel/relative_to_screen_size_tests.js"></script>
+  <script src="test/plugins/rel/rotation_tests.js"></script>
+  <script src="test/plugins/rel/padding_tests.js"></script>
+  <script src="test/plugins/rel/rel_to_tests.js"></script>
 </body>
 </html>
diff --git a/src/impress.js b/src/impress.js
index bee8570..00779ab 100644
--- a/src/impress.js
+++ b/src/impress.js
@@ -167,9 +167,9 @@
 
     // Some default config values.
     var defaults = {
-        width: 1024,
-        height: 768,
-        maxScale: 1,
+        width: 1920,
+        height: 1080,
+        maxScale: 3,
         minScale: 0,
 
         perspective: 1000,
@@ -177,6 +177,9 @@
         transitionDuration: 1000
     };
 
+    // Configuration options
+    var config = null;
+
     // It's just an empty function ... and a useless comment.
     var empty = function() { return false; };
 
@@ -228,9 +231,6 @@
         // Array of step elements
         var steps = null;
 
-        // Configuration options
-        var config = null;
-
         // Scale factor of the browser window
         var windowScale = null;
 
@@ -281,9 +281,9 @@
             var data = el.dataset,
                 step = {
                     translate: {
-                        x: lib.util.toNumber( data.x ),
-                        y: lib.util.toNumber( data.y ),
-                        z: lib.util.toNumber( data.z )
+                        x: lib.util.toNumberAdvanced( data.x ),
+                        y: lib.util.toNumberAdvanced( data.y ),
+                        z: lib.util.toNumberAdvanced( data.z )
                     },
                     rotate: {
                         x: lib.util.toNumber( data.rotateX ),
@@ -321,9 +321,27 @@
             steps.forEach( initStep );
         };
 
+        // Build configuration from root and defaults
+        var buildConfig = function() {
+            var rootData = root.dataset;
+            return {
+                width: lib.util.toNumber( rootData.width, defaults.width ),
+                height: lib.util.toNumber( rootData.height, defaults.height ),
+                maxScale: lib.util.toNumber( rootData.maxScale, defaults.maxScale ),
+                minScale: lib.util.toNumber( rootData.minScale, defaults.minScale ),
+                perspective: lib.util.toNumber( rootData.perspective, defaults.perspective ),
+                transitionDuration: lib.util.toNumber(
+                    rootData.transitionDuration, defaults.transitionDuration
+                )
+            };
+        };
+
         // `init` API function that initializes (and runs) the presentation.
         var init = function() {
             if ( initialized ) { return; }
+
+            // Initialize the configuration object, so it can be used by pre-init plugins.
+            config = buildConfig();
             execPreInitPlugins( root );
 
             // First we set up the viewport for mobile devices.
@@ -335,19 +353,6 @@
                 document.head.appendChild( meta );
             }
 
-            // Initialize configuration object
-            var rootData = root.dataset;
-            config = {
-                width: lib.util.toNumber( rootData.width, defaults.width ),
-                height: lib.util.toNumber( rootData.height, defaults.height ),
-                maxScale: lib.util.toNumber( rootData.maxScale, defaults.maxScale ),
-                minScale: lib.util.toNumber( rootData.minScale, defaults.minScale ),
-                perspective: lib.util.toNumber( rootData.perspective, defaults.perspective ),
-                transitionDuration: lib.util.toNumber(
-                    rootData.transitionDuration, defaults.transitionDuration
-                )
-            };
-
             windowScale = computeWindowScale( config );
 
             // Wrap steps with "canvas" element
@@ -776,7 +781,7 @@
             // scrolling to element in hash.
             //
             // And it has to be set after animation finishes, because in Chrome it
-            // makes transtion laggy.
+            // makes transition laggy.
             // BUG: http://code.google.com/p/chromium/issues/detail?id=62820
             lib.gc.addEventListener( root, "impress:stepenter", function( event ) {
                 window.location.hash = lastHash = "#/" + event.target.id;
@@ -868,7 +873,7 @@
             var thisLevel = preInitPlugins[ i ];
             if ( thisLevel !== undefined ) {
                 for ( var j = 0; j < thisLevel.length; j++ ) {
-                    thisLevel[ j ]( root );
+                    thisLevel[ j ]( root, roots[ "impress-root-" + root.id ] );
                 }
             }
         }
@@ -888,6 +893,10 @@
         preStepLeavePlugins[ weight ].push( plugin );
     };
 
+    impress.getConfig = function() {
+        return config;
+    };
+
     // Called at beginning of goto(), to execute all preStepLeave plugins.
     var execPreStepLeavePlugins = function( event ) { //jshint ignore:line
         for ( var i = 0; i < preStepLeavePlugins.length; i++ ) {
diff --git a/src/lib/rotation.js b/src/lib/rotation.js
new file mode 100644
index 0000000..59e8405
--- /dev/null
+++ b/src/lib/rotation.js
@@ -0,0 +1,429 @@
+/**
+ * Helper functions for rotation.
+ *
+ * Tommy Tam (c) 2021
+ * MIT License
+ */
+( function( document, window ) {
+    "use strict";
+
+    // Singleton library variables
+    var roots = [];
+
+    var libraryFactory = function( rootId ) {
+        if ( roots[ "impress-root-" + rootId ] ) {
+            return roots[ "impress-root-" + rootId ];
+        }
+
+        /**
+         * Round the number to 2 decimals, it's enough for use
+         */
+        var roundNumber = function( num ) {
+            return Math.round( ( num + Number.EPSILON ) * 100 ) / 100;
+        };
+
+        /**
+         * Get the length/norm of a vector.
+         *
+         * https://en.wikipedia.org/wiki/Norm_(mathematics)
+         */
+        var vectorLength = function( vec ) {
+            return Math.sqrt( vec.x * vec.x + vec.y * vec.y + vec.z * vec.z );
+        };
+
+        /**
+         * Dot product of two vectors.
+         *
+         * https://en.wikipedia.org/wiki/Dot_product
+         */
+        var vectorDotProd = function( vec1, vec2 ) {
+            return vec1.x * vec2.x + vec1.y * vec2.y + vec1.z * vec2.z;
+        };
+
+        /**
+         * Cross product of two vectors.
+         *
+         * https://en.wikipedia.org/wiki/Cross_product
+         */
+        var vectorCrossProd = function( vec1, vec2 ) {
+            return {
+                x: vec1.y * vec2.z - vec1.z * vec2.y,
+                y: vec1.z * vec2.x - vec1.x * vec2.z,
+                z: vec1.x * vec2.y - vec1.y * vec2.x
+            };
+        };
+
+        /**
+         * Determine wheter a vector is a zero vector
+         */
+        var isZeroVector = function( vec ) {
+            return !roundNumber( vec.x ) && !roundNumber( vec.y ) && !roundNumber( vec.z );
+        };
+
+        /**
+         * Scalar triple product of three vectors.
+         *
+         * It can be used to determine the handness of vectors.
+         *
+         * https://en.wikipedia.org/wiki/Triple_product#Scalar_triple_product
+         */
+        var tripleProduct = function( vec1, vec2, vec3 ) {
+            return vectorDotProd( vectorCrossProd( vec1, vec2 ), vec3 );
+        };
+
+        /**
+         * The world/absolute unit coordinates.
+         *
+         * This coordinate is used by browser to position objects.
+         * It will not be affected by object rotations.
+         * All relative positions will finally be converted to this
+         * coordinate to be used.
+         */
+        var worldUnitCoordinate = {
+            x: { x:1, y:0, z:0 },
+            y: { x:0, y:1, z:0 },
+            z: { x:0, y:0, z:1 }
+        };
+
+        /**
+         * Make quaternion from rotation axis and angle.
+         *
+         * q = [ cos(½θ), sin(½θ) axis ]
+         *
+         * If the angle is zero, returns the corresponded quaternion
+         * of axis.
+         *
+         * If the angle is not zero, returns the rotating quaternion
+         * which corresponds to rotation about the axis, by the angle θ.
+         *
+         * https://en.wikipedia.org/wiki/Quaternion
+         * https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation
+         */
+        var makeQuaternion = function( axis, theta = 0 ) {
+            var r = 0;
+            var t = 1;
+
+            if ( theta ) {
+                var radians = theta * Math.PI / 180;
+                r = Math.cos( radians / 2 );
+                t = Math.sin( radians / 2 ) / vectorLength( axis );
+            }
+
+            var q = [ r, axis.x * t, axis.y * t, axis.z * t ];
+
+            return q;
+        };
+
+        /**
+         * Extract vector from quaternion
+         */
+        var quaternionToVector = function( quaternion ) {
+            return {
+                x: roundNumber( quaternion[ 1 ] ),
+                y: roundNumber( quaternion[ 2 ] ),
+                z: roundNumber( quaternion[ 3 ] )
+            };
+        };
+
+        /**
+         * Returns the conjugate quaternion of a quaternion
+         *
+         * https://en.wikipedia.org/wiki/Quaternion#Conjugation,_the_norm,_and_reciprocal
+         */
+        var conjugateQuaternion = function( quaternion ) {
+            return [ quaternion[ 0 ], -quaternion[ 1 ], -quaternion[ 2 ], -quaternion[ 3 ] ];
+        };
+
+        /**
+         * Left multiple two quaternion.
+         *
+         * Is's used to combine two rotating quaternion into one.
+         */
+        var leftMulQuaternion = function( q1, q2 ) {
+            return [
+                ( q1[ 0 ] * q2[ 0 ] - q1[ 1 ] * q2[ 1 ] - q1[ 2 ] * q2[ 2 ] - q1[ 3 ] * q2[ 3 ] ),
+                ( q1[ 1 ] * q2[ 0 ] + q1[ 0 ] * q2[ 1 ] - q1[ 3 ] * q2[ 2 ] + q1[ 2 ] * q2[ 3 ] ),
+                ( q1[ 2 ] * q2[ 0 ] + q1[ 3 ] * q2[ 1 ] + q1[ 0 ] * q2[ 2 ] - q1[ 1 ] * q2[ 3 ] ),
+                ( q1[ 3 ] * q2[ 0 ] - q1[ 2 ] * q2[ 1 ] + q1[ 1 ] * q2[ 2 ] + q1[ 0 ] * q2[ 3 ] )
+            ];
+        };
+
+        /**
+         * Convert a rotation into a quaternion
+         */
+        var rotationToQuaternion = function( baseCoordinate, rotation ) {
+            var order = rotation.order ? rotation.order : "xyz";
+            var axes = order.split( "" );
+            var result = [ 1, 0, 0, 0 ];
+
+            for ( var i = 0; i < axes.length; i++ ) {
+                var deg = rotation[ axes[ i ] ];
+                if ( !deg || ( Math.abs( deg ) < 0.0001 ) ) {
+                    continue;
+                }
+
+                // All CSS rotation is based on the rotated coordinate
+                // So we need to calculate the rotated coordinate first
+                var coordinate = baseCoordinate;
+                if ( i > 0 ) {
+                    coordinate = {
+                        x: rotateByQuaternion( baseCoordinate.x, result ),
+                        y: rotateByQuaternion( baseCoordinate.y, result ),
+                        z: rotateByQuaternion( baseCoordinate.z, result )
+                    };
+                }
+
+                result = leftMulQuaternion(
+                    makeQuaternion( coordinate[ axes[ i ] ], deg ),
+                    result );
+
+            }
+
+            return result;
+        };
+
+        /**
+         * Rotate a vector by a quaternion.
+         */
+        var rotateByQuaternion = function( vec, quaternion ) {
+            var q = makeQuaternion( vec );
+
+            q = leftMulQuaternion(
+                leftMulQuaternion( quaternion, q ),
+                conjugateQuaternion( quaternion ) );
+
+            return quaternionToVector( q );
+        };
+
+        /**
+         * Rotate a vector by rotaion sequence.
+         */
+        var rotateVector = function( baseCoordinate, vec, rotation ) {
+            var quaternion = rotationToQuaternion( baseCoordinate, rotation );
+
+            return rotateByQuaternion( vec, quaternion );
+        };
+
+        /**
+         * Given a rotation, return the rotationed coordinate
+         */
+        var rotateCoordinate = function( coordinate, rotation ) {
+            var quaternion = rotationToQuaternion( coordinate, rotation );
+
+            return {
+                x: rotateByQuaternion( coordinate.x, quaternion ),
+                y: rotateByQuaternion( coordinate.y, quaternion ),
+                z: rotateByQuaternion( coordinate.z, quaternion )
+            };
+        };
+
+        /**
+         * Return the angle between two vector.
+         *
+         * The axis is used to determine the rotation direction.
+         */
+        var angleBetweenTwoVector = function( axis, vec1, vec2 ) {
+            var vecLen1 = vectorLength( vec1 );
+            var vecLen2 = vectorLength( vec2 );
+
+            if ( !vecLen1 || !vecLen2 ) {
+                return 0;
+            }
+
+            var cos = vectorDotProd( vec1, vec2 ) / vecLen1 / vecLen2 ;
+            var angle = Math.acos( cos ) * 180 / Math.PI;
+
+            if ( tripleProduct( vec1, vec2, axis ) > 0 ) {
+                return angle;
+            } else {
+                return -angle;
+            }
+        };
+
+        /**
+         * Return the angle between a vector and a plane.
+         *
+         * The plane is determined by an axis and a vector on the plane.
+         */
+        var angleBetweenPlaneAndVector = function( axis, planeVec, rotatedVec ) {
+            var norm = vectorCrossProd( axis, planeVec );
+
+            if ( isZeroVector( norm ) ) {
+                return 0;
+            }
+
+            return 90 - angleBetweenTwoVector( axis, rotatedVec, norm );
+        };
+
+        /**
+         * Calculated a order specified rotation sequence to
+         * transform from the world coordinate to required coordinate.
+         */
+        var coordinateToOrderedRotation = function( coordinate, order ) {
+            var axis0 = order[ 0 ];
+            var axis1 = order[ 1 ];
+            var axis2 = order[ 2 ];
+            var reversedOrder = order.split( "" ).reverse().join( "" );
+
+            var rotate2 = angleBetweenPlaneAndVector(
+                coordinate[ axis2 ],
+                worldUnitCoordinate[ axis0 ],
+                coordinate[ axis0 ] );
+
+            // The r2 is the reverse of rotate for axis2
+            // The coordinate1 is the coordinate before rotate of axis2
+            var r2 = { order: reversedOrder };
+            r2[ axis2 ] = -rotate2;
+
+            var coordinate1 = rotateCoordinate( coordinate, r2 );
+
+            // Calculate the rotation for axis1
+            var rotate1 = angleBetweenTwoVector(
+                coordinate1[ axis1 ],
+                worldUnitCoordinate[ axis0 ],
+                coordinate1[ axis0 ] );
+
+            // Calculate the rotation for axis0
+            var rotate0 = angleBetweenTwoVector(
+                worldUnitCoordinate[ axis0 ],
+                worldUnitCoordinate[ axis1 ],
+                coordinate1[ axis1 ] );
+
+            var rotation = { };
+            rotation.order = order;
+            rotation[ axis0 ] = roundNumber( rotate0 );
+            rotation[ axis1 ] = roundNumber( rotate1 );
+            rotation[ axis2 ] = roundNumber( rotate2 );
+
+            return rotation;
+        };
+
+        /**
+         * Returns the possible rotations from unit coordinate
+         * to specified coordinate.
+         */
+        var possibleRotations = function( coordinate ) {
+            var orders = [ "xyz", "xzy", "yxz", "yzx", "zxy", "zyx" ];
+            var rotations = [ ];
+
+            for ( var i = 0; i < orders.length; ++i ) {
+                rotations.push(
+                    coordinateToOrderedRotation( coordinate, orders[ i ] )
+                );
+            }
+
+            return rotations;
+        };
+
+        /**
+         * Calculate a degree which in range (-180, 180] of baseDeg
+         */
+        var nearestAngle = function( baseDeg, deg ) {
+            while ( deg > baseDeg + 180 ) {
+                deg -= 360;
+            }
+
+            while ( deg < baseDeg - 180 ) {
+                deg += 360;
+            }
+
+            return deg;
+        };
+
+        /**
+         * Given a base rotation and multiple rotations, return the best one.
+         *
+         * The best one is the one has least rotate from base.
+         */
+        var bestRotation = function( baseRotate, rotations ) {
+            var bestScore;
+            var bestRotation;
+
+            for ( var i = 0; i < rotations.length; ++i ) {
+                var rotation = {
+                    order: rotations[ i ].order,
+                    x: nearestAngle( baseRotate.x, rotations[ i ].x ),
+                    y: nearestAngle( baseRotate.y, rotations[ i ].y ),
+                    z: nearestAngle( baseRotate.z, rotations[ i ].z )
+                };
+
+                var score = Math.abs( rotation.x - baseRotate.x ) +
+                    Math.abs( rotation.y - baseRotate.y ) +
+                    Math.abs( rotation.z - baseRotate.z );
+
+                if ( !i || ( score < bestScore ) ) {
+                    bestScore = score;
+                    bestRotation = rotation;
+                }
+            }
+
+            return bestRotation;
+        };
+
+        /**
+         * Given a coordinate, return the best rotation to achieve it.
+         *
+         * The baseRotate is used to select the near rotation from it.
+         */
+        var coordinateToRotation = function( baseRotate, coordinate ) {
+            var rotations = possibleRotations( coordinate );
+
+            return bestRotation( baseRotate, rotations );
+        };
+
+        /**
+         * Apply a relative rotation to the base rotation.
+         *
+         * Calculate the coordinate after the rotation on each axis,
+         * and finally find out a one step rotation has the effect
+         * of two rotation.
+         *
+         * If there're multiple way to accomplish, select the one
+         * that is nearest to the base.
+         *
+         * Return one rotation has the same effect.
+         */
+        var combineRotations = function( rotations ) {
+
+            // No rotation
+            if ( rotations.length <= 0 ) {
+                return { x:0, y:0, z:0, order:"xyz" };
+            }
+
+            // Find out the base coordinate
+            var coordinate = worldUnitCoordinate;
+
+            // One by one apply rotations in order
+            for ( var i = 0; i < rotations.length; i++ ) {
+                coordinate = rotateCoordinate( coordinate, rotations[ i ] );
+            }
+
+            // Calculate one rotation from unit coordinate to rotated
+            // coordinate.  Because there're multiple possibles,
+            // select the one nearest to the base
+            var rotate = coordinateToRotation( rotations[ 0 ], coordinate );
+
+            return rotate;
+        };
+
+        var translateRelative = function( relative, prevRotation ) {
+            var result = rotateVector(
+                worldUnitCoordinate, relative, prevRotation );
+            result.rotate = combineRotations(
+                [ prevRotation, relative.rotate ] );
+
+            return result;
+        };
+
+        var lib = {
+            translateRelative: translateRelative
+        };
+
+        roots[ "impress-root-" + rootId ] = lib;
+        return lib;
+    };
+
+    // Let impress core know about the existence of this library
+    window.impress.addLibraryFactory( { rotation: libraryFactory } );
+
+} )( document, window );
diff --git a/src/lib/util.js b/src/lib/util.js
index b0d3a93..680fd74 100644
--- a/src/lib/util.js
+++ b/src/lib/util.js
@@ -46,7 +46,8 @@
 
             // Get id from url # by removing `#` or `#/` from the beginning,
             // so both "fallback" `#slide-id` and "enhanced" `#/slide-id` will work
-            return byId( window.location.hash.replace( /^#\/?/, "" ) );
+            var encoded = window.location.hash.replace( /^#\/?/, "" );
+            return byId( decodeURIComponent( encoded ) );
         };
 
         // `getUrlParamValue` return a given URL parameter value if it exists
@@ -80,6 +81,26 @@
             return isNaN( numeric ) ? ( fallback || 0 ) : Number( numeric );
         };
 
+        /**
+         * Extends toNumber() to correctly compute also relative-to-screen-size values 5w and 5h.
+         *
+         * Returns the computed value in pixels with w/h postfix removed.
+         */
+        var toNumberAdvanced = function( numeric, fallback ) {
+            if ( typeof numeric !== "string" ) {
+                return toNumber( numeric, fallback );
+            }
+            var ratio = numeric.match( /^([+-]*[\d\.]+)([wh])$/ );
+            if ( ratio == null ) {
+                return toNumber( numeric, fallback );
+            } else {
+                var value = parseFloat( ratio[ 1 ] );
+                var config = window.impress.getConfig();
+                var multiplier = ratio[ 2 ] === "w" ? config.width : config.height;
+                return value * multiplier;
+            }
+        };
+
         // `triggerEvent` builds a custom DOM event with given `eventName` and `detail` data
         // and triggers it on element given as `el`.
         var triggerEvent = function( el, eventName, detail ) {
@@ -96,6 +117,7 @@
             getElementFromHash: getElementFromHash,
             throttle: throttle,
             toNumber: toNumber,
+            toNumberAdvanced: toNumberAdvanced,
             triggerEvent: triggerEvent,
             getUrlParamValue: getUrlParamValue
         };
diff --git a/src/plugins/blackout/blackout.js b/src/plugins/blackout/blackout.js
index caa44c6..439e868 100644
--- a/src/plugins/blackout/blackout.js
+++ b/src/plugins/blackout/blackout.js
@@ -88,7 +88,6 @@
         root = event.target;
         canvas = root.firstElementChild;
         var gc = api.lib.gc;
-        var util = api.lib.util;
 
         gc.addEventListener( document, "keydown", function( event ) {
 
diff --git a/src/plugins/extras/extras.js b/src/plugins/extras/extras.js
index 1321dfa..7c953ca 100644
--- a/src/plugins/extras/extras.js
+++ b/src/plugins/extras/extras.js
@@ -41,7 +41,7 @@
               i--;
               while ( i >= 0 ) {
                 var newElement = element.cloneNode( false );
-                newElement.innerHTML = markdown.toHTML( slides[ i ] );
+                newElement.innerHTML = markdown.toHTML( slides[ i ], dialect );
                 element.parentNode.insertBefore( newElement, element );
                 element = newElement;
                 i--;
diff --git a/src/plugins/impressConsole/impressConsole.js b/src/plugins/impressConsole/impressConsole.js
index bfabea5..c00ee67 100644
--- a/src/plugins/impressConsole/impressConsole.js
+++ b/src/plugins/impressConsole/impressConsole.js
@@ -39,6 +39,20 @@
             'useAMPM': false
         };
         break;
+    case 'zh-CN':
+    case 'zh-cn':
+        lang = {
+            'noNotes': '<div class="noNotes">当前帧没有备注</div>',
+            'restart': '重新开始',
+            'clickToOpen': '点击以打开演讲者控制界面',
+            'prev': '上一帧',
+            'next': '下一帧',
+            'loading': '加载中',
+            'ready': '就绪',
+            'moving': '移动中',
+            'useAMPM': false
+        };
+        break;
     case 'en': // jshint ignore:line
     default : // jshint ignore:line
         lang = {
@@ -169,7 +183,7 @@
                 var preSrc = baseURL + '#' + nextStep().id;
                 var slideView = consoleWindow.document.getElementById( 'slideView' );
 
-                // Setting them when they are already set causes glithes in Firefox, so check first:
+                // Setting when already set causes glitches in Firefox, so check first:
                 if ( slideView.src !== slideSrc ) {
                     slideView.src = slideSrc;
                 }
@@ -206,7 +220,7 @@
                 var preSrc = baseURL + '#' + nextStep().id;
                 var slideView = consoleWindow.document.getElementById( 'slideView' );
 
-                // Setting them when they are already set causes glithes in Firefox, so check first:
+                // Setting when already set causes glitches in Firefox, so check first:
                 if ( slideView.src !== slideSrc ) {
                     slideView.src = slideSrc;
                 }
diff --git a/src/plugins/navigation-ui/README.md b/src/plugins/navigation-ui/README.md
index 0b30202..cf05bf4 100644
--- a/src/plugins/navigation-ui/README.md
+++ b/src/plugins/navigation-ui/README.md
@@ -4,6 +4,8 @@ Navigation UI plugin
 This plugin provides UI elements "back", "forward" and a list to select
 a specific slide number.
 
+Element attribut title is used for select option content if available, it uses element id if no title is provided.
+
 The navigation controls are visible if the toolbar plugin is enabled. To add the toolbar to your
 presentations, [see toolbar plugin README](../toolbar/README.md).
 
diff --git a/src/plugins/navigation-ui/navigation-ui.js b/src/plugins/navigation-ui/navigation-ui.js
index 507e945..8a89960 100644
--- a/src/plugins/navigation-ui/navigation-ui.js
+++ b/src/plugins/navigation-ui/navigation-ui.js
@@ -45,7 +45,9 @@
             // Omit steps that are listed as hidden from select widget
             if ( hideSteps.indexOf( steps[ i ] ) < 0 ) {
                 options = options + '<option value="' + steps[ i ].id + '">' + // jshint ignore:line
-                                    steps[ i ].id + '</option>' + '\n'; // jshint ignore:line
+							(
+								steps[ i ].title ? steps[ i ].title : steps[ i ].id
+							) + '</option>' + '\n';
             }
         }
         return options;
diff --git a/src/plugins/rel/README.md b/src/plugins/rel/README.md
index 800fda7..8b93606 100644
--- a/src/plugins/rel/README.md
+++ b/src/plugins/rel/README.md
@@ -22,6 +22,13 @@ Following html attributes are supported for step elements:
     data-rel-z
     data-rel-to
 
+    data-rel-rotate-x
+    data-rel-rotate-y
+    data-rel-rotate-z
+
+    data-rel-position
+    data-rel-reset
+
 Non-zero values are also inherited from the previous step. This makes it easy to 
 create a boring presentation where each slide shifts for example 1000px down 
 from the previous.
@@ -47,6 +54,31 @@ If you need a reference to a step that is shown later make use of the goto plugi
     <div id="shown-earlier" class="step" data-rel-to="shown-later" data-rel-x="1000" data-rel-y="500" data-goto-prev="shown-first" data-goto-next="shown-later">
     <div id="shown-last" class="step" data-goto-prev="shown-later">
 
+Relative positioning
+--------------------
+
+All `data-rel-x`/`y`/`z` is used world coordinate by default. So the value should be alternated according to the rotation state of previous slides.
+
+To easy relative positioning, the `data-rel-position` attribute is introduced.
+
+`data-rel-position` has a default value of "absolute", which works like this attribute is not introduced.
+
+When `data-rel-position="relative"`, everything changed. The rotation of previous is no need to be considered, you can set all the `data-rel-` attributes as if the previous has no rotation. This plugin will calculate the acual position according to the position and rotation of the previous slide and the relative settings. This make it possible to split a presentation into parts, construct each parts standalone without consider the final position, and then assemble them together.
+
+For example, if you want the slide slided in from the right hand side, all you need is `data-rel-x="1000"`, no matter the rotation of the previous slide. If the previous slide has `data-rotate-z="90"`, the actual attribute of this slide will work like `data-rel-y="1000"`.
+
+Not only relative positions, the relative rotations can be used while `data-rel-position="relative"`.
+
+For example, `data-rel-rotate-y="45"` will make the slide has an angle of 45 degree to the previous slide. It make it easy to build a circle and do other complicated positioning.
+
+If not set, the `data-rel-position` attribute will be inherited from previous slide. So we only need to set it at the first slide, then all done.
+
+To avoid the boring need to set most `data-rel-*` to zero, but set only one or two ones, `data-rel-reset` attribute can be used: 
+
+- `data-rel-reset` equals to: `data-rel-x="0" data-rel-y="0" data-rel-z="0" data-rel-rotate-x="0" data-rel-rotate-y="0" data-rel-rotate-z="0"`
+- `data-rel-reset="all"` works like `data-rel-reset`, in additions `data-rotate-x="0" data-rotate-y="0" data-rotate-z="0"`
+
+When `data-rel-position="relative"` and `data-rel-to` is specified, `data-rotate-*` and `data-rel-*` will be inherited from specified slide too.
 
 IMPORTANT: Incompatible change
 ------------------------------
diff --git a/src/plugins/rel/rel.js b/src/plugins/rel/rel.js
index ef54650..65aef19 100644
--- a/src/plugins/rel/rel.js
+++ b/src/plugins/rel/rel.js
@@ -48,34 +48,11 @@
 ( function( document, window ) {
     "use strict";
 
+    var api;
     var startingState = {};
 
-    /**
-     * Copied from core impress.js. We currently lack a library mechanism to
-     * to share utility functions like this.
-     */
-    var toNumber = function( numeric, fallback ) {
-        return isNaN( numeric ) ? ( fallback || 0 ) : Number( numeric );
-    };
-
-    /**
-     * Extends toNumber() to correctly compute also relative-to-screen-size values 5w and 5h.
-     *
-     * Returns the computed value in pixels with w/h postfix removed.
-     */
-    var toNumberAdvanced = function( numeric, fallback ) {
-        if ( typeof numeric !== "string" ) {
-            return toNumber( numeric, fallback );
-        }
-        var ratio = numeric.match( /^([+-]*[\d\.]+)([wh])$/ );
-        if ( ratio == null ) {
-            return toNumber( numeric, fallback );
-        } else {
-            var value = parseFloat( ratio[ 1 ] );
-            var multiplier = ratio[ 2 ] === "w" ? window.innerWidth : window.innerHeight;
-            return value * multiplier;
-        }
-    };
+    var toNumber;
+    var toNumberAdvanced;
 
     var computeRelativePositions = function( el, prev ) {
         var data = el.dataset;
@@ -83,20 +60,64 @@
         if ( !prev ) {
 
             // For the first step, inherit these defaults
-            prev = { x:0, y:0, z:0, relative: { x:0, y:0, z:0 } };
+            prev = {
+                x:0, y:0, z:0,
+                rotate: { x:0, y:0, z:0, order:"xyz" },
+                relative: {
+                    position: "absolute",
+                    x:0, y:0, z:0,
+                    rotate: { x:0, y:0, z:0, order:"xyz" }
+                }
+            };
         }
 
+        var ref = prev;
         if ( data.relTo ) {
 
-            var ref = document.getElementById( data.relTo );
+            ref = document.getElementById( data.relTo );
             if ( ref ) {
 
                 // Test, if it is a previous step that already has some assigned position data
                 if ( el.compareDocumentPosition( ref ) & Node.DOCUMENT_POSITION_PRECEDING ) {
-                    prev.x = toNumber( ref.getAttribute( "data-x" ) );
-                    prev.y = toNumber( ref.getAttribute( "data-y" ) );
-                    prev.z = toNumber( ref.getAttribute( "data-z" ) );
-                    prev.relative = {};
+                    prev.x = toNumberAdvanced( ref.getAttribute( "data-x" ) );
+                    prev.y = toNumberAdvanced( ref.getAttribute( "data-y" ) );
+                    prev.z = toNumberAdvanced( ref.getAttribute( "data-z" ) );
+
+                    var prevPosition = ref.getAttribute( "data-rel-position" ) || "absolute";
+
+                    if ( prevPosition !== "relative" ) {
+
+                        // For compatibility with the old behavior, doesn't inherit otherthings,
+                        // just like a reset.
+                        prev.rotate = { x:0, y:0, z:0, order: "xyz" };
+                        prev.relative = {
+                            position: "absolute",
+                            x:0, y:0, z:0,
+                            rotate: { x:0, y:0, z:0, order:"xyz" }
+                        };
+                    } else {
+
+                        // For data-rel-position="relative", inherit all
+                        prev.rotate.y = toNumber( ref.getAttribute( "data-rotate-y" ) );
+                        prev.rotate.x = toNumber( ref.getAttribute( "data-rotate-x" ) );
+                        prev.rotate.z = toNumber(
+                            ref.getAttribute( "data-rotate-z" ) ||
+                            ref.getAttribute( "data-rotate" ) );
+
+                        // We also inherit relatives from relTo slide
+                        prev.relative = {
+                            position: prevPosition,
+                            x: toNumberAdvanced( ref.getAttribute( "data-rel-x" ), 0 ),
+                            y: toNumberAdvanced( ref.getAttribute( "data-rel-y" ), 0 ),
+                            z: toNumberAdvanced( ref.getAttribute( "data-rel-z" ), 0 ),
+                            rotate: {
+                                x: toNumberAdvanced( ref.getAttribute( "data-rel-rotate-x" ), 0 ),
+                                y: toNumberAdvanced( ref.getAttribute( "data-rel-rotate-y" ), 0 ),
+                                z: toNumberAdvanced( ref.getAttribute( "data-rel-rotate-z" ), 0 ),
+                                order: ( ref.getAttribute( "data-rel-rotate-order" ) ||  "xyz" )
+                            }
+                        };
+                    }
                 } else {
                     window.console.error(
                         "impress.js rel plugin: Step \"" + data.relTo + "\" is not defined " +
@@ -117,39 +138,104 @@
             }
         }
 
+        // While ``data-rel-reset="relative"`` or just ``data-rel-reset``,
+        // ``data-rel-x/y/z`` and ``data-rel-rotate-x/y/z`` will have default value of 0,
+        // instead of inherit from previous slide.
+        //
+        // If ``data-rel-reset="all"``, ``data-rotate-*`` are not inherited from previous slide too.
+        // So ``data-rel-reset="all" data-rotate-x="90"`` means
+        // ``data-rotate-x="90" data-rotate-y="0" data-rotate-z="0"``, we doesn't need to
+        // bother clearing all unneeded attributes.
+
+        var inheritRotation = true;
+        if ( el.hasAttribute( "data-rel-reset" ) ) {
+
+            // Don't inherit from prev, just use the relative setting for current element
+            prev.relative = {
+                position: prev.relative.position,
+                x:0, y:0, z:0,
+                rotate: { x:0, y:0, z:0, order: "xyz" } };
+
+            if ( data.relReset === "all" ) {
+                inheritRotation = false;
+            }
+        }
+
         var step = {
-                x: toNumber( data.x, prev.x ),
-                y: toNumber( data.y, prev.y ),
-                z: toNumber( data.z, prev.z ),
+                x: toNumberAdvanced( data.x, prev.x ),
+                y: toNumberAdvanced( data.y, prev.y ),
+                z: toNumberAdvanced( data.z, prev.z ),
+                rotate: {
+                    x: toNumber( data.rotateX, 0 ),
+                    y: toNumber( data.rotateY, 0 ),
+                    z: toNumber( data.rotateZ || data.rotate, 0 ),
+                    order: data.rotateOrder || "xyz"
+                },
                 relative: {
+                    position: data.relPosition || prev.relative.position,
                     x: toNumberAdvanced( data.relX, prev.relative.x ),
                     y: toNumberAdvanced( data.relY, prev.relative.y ),
-                    z: toNumberAdvanced( data.relZ, prev.relative.z )
+                    z: toNumberAdvanced( data.relZ, prev.relative.z ),
+                    rotate: {
+                        x: toNumber( data.relRotateX, prev.relative.rotate.x ),
+                        y: toNumber( data.relRotateY, prev.relative.rotate.y ),
+                        z: toNumber( data.relRotateZ, prev.relative.rotate.z ),
+                        order: data.rotateOrder || "xyz"
+                    }
                 }
             };
 
+        // The final relatives maybe or maybe not the same with orignal data-rel-*
+        var relative = step.relative;
+
+        if ( step.relative.position === "relative" && inheritRotation ) {
+
+            // Calculate relatives based on previous slide
+            relative = api.lib.rotation.translateRelative(
+                step.relative, prev.rotate );
+
+            // Convert rotations to values that works with step.rotate
+            relative.rotate.x -= step.rotate.x;
+            relative.rotate.y -= step.rotate.y;
+            relative.rotate.z -= step.rotate.z;
+        }
+
         // Relative position is ignored/zero if absolute is given.
         // Note that this also has the effect of resetting any inherited relative values.
         if ( data.x !== undefined ) {
-            step.relative.x = 0;
+            relative.x = step.relative.x = 0;
         }
         if ( data.y !== undefined ) {
-            step.relative.y = 0;
+            relative.y = step.relative.y = 0;
         }
         if ( data.z !== undefined ) {
-            step.relative.z = 0;
+            relative.z = step.relative.z = 0;
+        }
+        if ( data.rotateX !== undefined || !inheritRotation ) {
+            relative.rotate.x = step.relative.rotate.x = 0;
+        }
+        if ( data.rotateY !== undefined || !inheritRotation ) {
+            relative.rotate.y = step.relative.rotate.y = 0;
+        }
+        if ( data.rotateZ !== undefined || data.rotate !== undefined || !inheritRotation ) {
+            relative.rotate.z = step.relative.rotate.z = 0;
         }
 
-        // Apply relative position to absolute position, if non-zero
-        // Note that at this point, the relative values contain a number value of pixels.
-        step.x = step.x + step.relative.x;
-        step.y = step.y + step.relative.y;
-        step.z = step.z + step.relative.z;
+        step.x = step.x + relative.x;
+        step.y = step.y + relative.y;
+        step.z = step.z + relative.z;
+        step.rotate.x = step.rotate.x + relative.rotate.x;
+        step.rotate.y = step.rotate.y + relative.rotate.y;
+        step.rotate.z = step.rotate.z + relative.rotate.z;
 
         return step;
     };
 
-    var rel = function( root ) {
+    var rel = function( root, impressApi ) {
+        api = impressApi;
+        toNumber = api.lib.util.toNumber;
+        toNumberAdvanced = api.lib.util.toNumberAdvanced;
+
         var steps = root.querySelectorAll( ".step" );
         var prev;
         startingState[ root.id ] = [];
@@ -162,7 +248,16 @@
                 z: el.getAttribute( "data-z" ),
                 relX: el.getAttribute( "data-rel-x" ),
                 relY: el.getAttribute( "data-rel-y" ),
-                relZ: el.getAttribute( "data-rel-z" )
+                relZ: el.getAttribute( "data-rel-z" ),
+                rotateX: el.getAttribute( "data-rotate-x" ),
+                rotateY: el.getAttribute( "data-rotate-y" ),
+                rotateZ: el.getAttribute( "data-rotate-z" ),
+                rotate: el.getAttribute( "data-rotate" ),
+                relRotateX: el.getAttribute( "data-rel-rotate-x" ),
+                relRotateY: el.getAttribute( "data-rel-rotate-y" ),
+                relRotateZ: el.getAttribute( "data-rel-rotate-z" ),
+                relPosition: el.getAttribute( "data-rel-position" ),
+                rotateOrder: el.getAttribute( "data-rotate-order" )
             } );
             var step = computeRelativePositions( el, prev );
 
@@ -170,6 +265,17 @@
             el.setAttribute( "data-x", step.x );
             el.setAttribute( "data-y", step.y );
             el.setAttribute( "data-z", step.z );
+            el.setAttribute( "data-rotate-x", step.rotate.x );
+            el.setAttribute( "data-rotate-y", step.rotate.y );
+            el.setAttribute( "data-rotate-z", step.rotate.z );
+            el.setAttribute( "data-rotate-order", step.rotate.order );
+            el.setAttribute( "data-rel-position", step.relative.position );
+            el.setAttribute( "data-rel-x", step.relative.x );
+            el.setAttribute( "data-rel-y", step.relative.y );
+            el.setAttribute( "data-rel-z", step.relative.z );
+            el.setAttribute( "data-rel-rotate-x", step.relative.rotate.x );
+            el.setAttribute( "data-rel-rotate-y", step.relative.rotate.y );
+            el.setAttribute( "data-rel-rotate-z", step.relative.rotate.z );
             prev = step;
         }
     };
@@ -183,28 +289,27 @@
         event.detail.api.lib.gc.pushCallback( function() {
             var steps = startingState[ root.id ];
             var step;
+            var attrs = [
+                [ "x", "relX" ],
+                [ "y", "relY" ],
+                [ "z", "relZ" ],
+                [ "rotate-x", "relRotateX" ],
+                [ "rotate-y", "relRotateY" ],
+                [ "rotate-z", "relRotateZ" ],
+                [ "rotate-order", "relRotateOrder" ]
+            ];
+
             while ( step = steps.pop() ) {
 
                 // Reset x/y/z in cases where this plugin has changed it.
-                if ( step.relX !== null ) {
-                    if ( step.x === null ) {
-                        step.el.removeAttribute( "data-x" );
-                    } else {
-                        step.el.setAttribute( "data-x", step.x );
-                    }
-                }
-                if ( step.relY !== null ) {
-                    if ( step.y === null ) {
-                        step.el.removeAttribute( "data-y" );
-                    } else {
-                        step.el.setAttribute( "data-y", step.y );
-                    }
-                }
-                if ( step.relZ !== null ) {
-                    if ( step.z === null ) {
-                        step.el.removeAttribute( "data-z" );
-                    } else {
-                        step.el.setAttribute( "data-z", step.z );
+                for ( var i = 0; i < attrs.length; i++ ) {
+                    if ( step[ attrs[ i ][ 1 ] ] !== null ) {
+                        if ( step[ attrs[ i ][ 0 ] ] === null ) {
+                            step.el.removeAttribute( "data-" + attrs[ i ][ 0 ] );
+                        } else {
+                            step.el.setAttribute(
+                                "data-" + attrs[ i ][ 0 ], step[ attrs[ i ][ 0 ] ] );
+                        }
                     }
                 }
             }
diff --git a/src/plugins/substep/README.md b/src/plugins/substep/README.md
index d15326b..0dec55c 100644
--- a/src/plugins/substep/README.md
+++ b/src/plugins/substep/README.md
@@ -9,6 +9,12 @@ alternatively hide one (for `prev()`). Only once all substeps are shown, will a
 actually move to the next step, and only when all are hidden will a call to `prev()` move to the
 previous one.
 
+By default, this plugin reveals substeps in the order in which they appear in the HTML.  If you
+would like to reveal them in a different order, you can supply an integer to `data-substep-order`.
+If you do so, this plugin will reveal the substeps in ascending order; any substeps without a
+specified `data-substep-order` will be revealed after all substeps with a specified order have
+been revealed.
+
 Calls to `goto()` will be ignored by this plugin, i.e. `goto()` will transition to whichever step is
 the target.
 
diff --git a/src/plugins/substep/substep.js b/src/plugins/substep/substep.js
index 01d5fd5..2f08250 100644
--- a/src/plugins/substep/substep.js
+++ b/src/plugins/substep/substep.js
@@ -61,12 +61,28 @@
 
     var showSubstepIfAny = function( step ) {
         var substeps = step.querySelectorAll( ".substep" );
-        var visible = step.querySelectorAll( ".substep-visible" );
         if ( substeps.length > 0 ) {
-            return showSubstep( substeps, visible );
+            var sorted = sortSubsteps( substeps );
+            var visible = step.querySelectorAll( ".substep-visible" );
+            return showSubstep( sorted, visible );
         }
     };
 
+    var sortSubsteps = function( substepNodeList ) {
+        var substeps = Array.from( substepNodeList );
+        var sorted = substeps
+            .filter( el => el.dataset.substepOrder )
+            .sort( ( a, b ) => {
+                var orderA = a.dataset.substepOrder;
+                var orderB = b.dataset.substepOrder;
+                return parseInt( orderA ) - parseInt( orderB );
+            } )
+            .concat( substeps.filter( el => {
+                return el.dataset.substepOrder === undefined;
+            } ) );
+        return sorted;
+    };
+
     var showSubstep = function( substeps, visible ) {
         if ( visible.length < substeps.length ) {
             for ( var i = 0; i < substeps.length; i++ ) {
@@ -82,8 +98,9 @@
     var hideSubstepIfAny = function( step ) {
         var substeps = step.querySelectorAll( ".substep" );
         var visible = step.querySelectorAll( ".substep-visible" );
+        var sorted = sortSubsteps( visible );
         if ( substeps.length > 0 ) {
-            return hideSubstep( visible );
+            return hideSubstep( sorted );
         }
     };
 
diff --git a/test/plugins/rel/padding_tests.js b/test/plugins/rel/padding_tests.js
new file mode 100644
index 0000000..c02eb5f
--- /dev/null
+++ b/test/plugins/rel/padding_tests.js
@@ -0,0 +1,160 @@
+QUnit.module( "rel plugin padding tests" );
+
+QUnit.test( "padding_relative", function( assert ) {
+  window.console.log( "Begin padding_relative" );
+  var done = assert.async();
+
+  loadIframe( "test/plugins/rel/padding_tests_presentation.html", assert, function() {
+    initPresentation( assert, function() {
+      var iframe = document.getElementById( "presentation-iframe" );
+      var iframeDoc = iframe.contentDocument;
+
+      var root  = iframeDoc.querySelector( "div#impress" );
+
+      var origin = iframeDoc.querySelector( "div#origin" );
+      var origin_x = iframeDoc.querySelector( "div#origin_x" );
+      var origin_y = iframeDoc.querySelector( "div#origin_y" );
+      var origin_z = iframeDoc.querySelector( "div#origin_z" );
+
+      var x = iframeDoc.querySelector( "div#x" );
+      var x_x = iframeDoc.querySelector( "div#x_x" );
+      var x_y = iframeDoc.querySelector( "div#x_y" );
+      var x_z = iframeDoc.querySelector( "div#x_z" );
+
+      var y = iframeDoc.querySelector( "div#y" );
+      var y_x = iframeDoc.querySelector( "div#y_x" );
+      var y_y = iframeDoc.querySelector( "div#y_y" );
+      var y_z = iframeDoc.querySelector( "div#y_z" );
+
+      var z = iframeDoc.querySelector( "div#z" );
+      var z_x = iframeDoc.querySelector( "div#z_x" );
+      var z_y = iframeDoc.querySelector( "div#z_y" );
+      var z_z = iframeDoc.querySelector( "div#z_z" );
+
+      var reset = iframeDoc.querySelector( "div#reset" );
+
+      assert.close( origin.dataset.x, 0, 1, "origin data-x attribute" );
+      assert.close( origin.dataset.y, 0, 1, "origin data-y attribute" );
+      assert.close( origin.dataset.z, 0, 1, "origin data-z attribute" );
+      assert.close( origin.dataset.rotateX, 0, 1, "origin data-rotate-x" );
+      assert.close( origin.dataset.rotateY, 0, 1, "origin data-rotate-y" );
+      assert.close( origin.dataset.rotateZ, 0, 1, "origin data-rotate-z" );
+
+      assert.close( origin_x.dataset.x, 500, 1, "origin_x data-x attribute" );
+      assert.close( origin_x.dataset.y, 0, 1, "origin_x data-y attribute" );
+      assert.close( origin_x.dataset.z, 0, 1, "origin_x data-z attribute" );
+      assert.close( origin_x.dataset.rotateX, 0, 1, "origin_x data-rotate-x" );
+      assert.close( origin_x.dataset.rotateY, 0, 1, "origin_x data-rotate-y" );
+      assert.close( origin_x.dataset.rotateZ, 0, 1, "origin_x data-rotate-z" );
+
+      assert.close( origin_y.dataset.x, 0, 1, "origin_y data-x attribute" );
+      assert.close( origin_y.dataset.y, 500, 1, "origin_y data-y attribute" );
+      assert.close( origin_y.dataset.z, 0, 1, "origin_y data-z attribute" );
+      assert.close( origin_y.dataset.rotateX, 0, 1, "origin_y data-rotate-x" );
+      assert.close( origin_y.dataset.rotateY, 0, 1, "origin_y data-rotate-y" );
+      assert.close( origin_y.dataset.rotateZ, 0, 1, "origin_y data-rotate-z" );
+
+      assert.close( origin_z.dataset.x, 0, 1, "origin_z data-x attribute" );
+      assert.close( origin_z.dataset.y, 0, 1, "origin_z data-y attribute" );
+      assert.close( origin_z.dataset.z, 500, 1, "origin_z data-z attribute" );
+      assert.close( origin_z.dataset.rotateX, 0, 1, "origin_z data-rotate-x" );
+      assert.close( origin_z.dataset.rotateY, 0, 1, "origin_z data-rotate-y" );
+      assert.close( origin_z.dataset.rotateZ, 0, 1, "origin_z data-rotate-z" );
+
+      assert.close( x.dataset.x, 0, 1, "x data-x attribute" );
+      assert.close( x.dataset.y, 0, 1, "x data-y attribute" );
+      assert.close( x.dataset.z, 0, 1, "x data-z attribute" );
+      assert.close( x.dataset.rotateX, 90, 1, "x data-rotate-x" );
+      assert.close( x.dataset.rotateY, 0, 1, "x data-rotate-y" );
+      assert.close( x.dataset.rotateZ, 0, 1, "x data-rotate-z" );
+
+      assert.close( x_x.dataset.x, 500, 1, "x_x data-x attribute" );
+      assert.close( x_x.dataset.y, 0, 1, "x_x data-y attribute" );
+      assert.close( x_x.dataset.z, 0, 1, "x_x data-z attribute" );
+      assert.close( x_x.dataset.rotateX, 90, 1, "x_x data-rotate-x" );
+      assert.close( x_x.dataset.rotateY, 0, 1, "x_x data-rotate-y" );
+      assert.close( x_x.dataset.rotateZ, 0, 1, "x_x data-rotate-z" );
+
+      assert.close( x_y.dataset.x, 0, 1, "x_y data-x attribute" );
+      assert.close( x_y.dataset.y, 0, 1, "x_y data-y attribute" );
+      assert.close( x_y.dataset.z, 500, 1, "x_y data-z attribute" );
+      assert.close( x_y.dataset.rotateX, 90, 1, "x_y data-rotate-x" );
+      assert.close( x_y.dataset.rotateY, 0, 1, "x_y data-rotate-y" );
+      assert.close( x_y.dataset.rotateZ, 0, 1, "x_y data-rotate-z" );
+
+      assert.close( x_z.dataset.x, 0, 1, "x_z data-x attribute" );
+      assert.close( x_z.dataset.y, -500, 1, "x_z data-y attribute" );
+      assert.close( x_z.dataset.z, 0, 1, "x_z data-z attribute" );
+      assert.close( x_z.dataset.rotateX, 90, 1, "x_z data-rotate-x" );
+      assert.close( x_z.dataset.rotateY, 0, 1, "x_z data-rotate-y" );
+      assert.close( x_z.dataset.rotateZ, 0, 1, "x_z data-rotate-z" );
+
+      assert.close( y.dataset.x, 0, 1, "y data-x attribute" );
+      assert.close( y.dataset.y, 0, 1, "y data-y attribute" );
+      assert.close( y.dataset.z, 0, 1, "y data-z attribute" );
+      assert.close( y.dataset.rotateX, 0, 1, "y data-rotate-x" );
+      assert.close( y.dataset.rotateY, 90, 1, "y data-rotate-y" );
+      assert.close( y.dataset.rotateZ, 0, 1, "y data-rotate-z" );
+
+      assert.close( y_x.dataset.x, 0, 1, "y_x data-x attribute" );
+      assert.close( y_x.dataset.y, 0, 1, "y_x data-y attribute" );
+      assert.close( y_x.dataset.z, -500, 1, "y_x data-z attribute" );
+      assert.close( y_x.dataset.rotateX, 0, 1, "y_x data-rotate-x" );
+      assert.close( y_x.dataset.rotateY, 90, 1, "y_x data-rotate-y" );
+      assert.close( y_x.dataset.rotateZ, 0, 1, "y_x data-rotate-z" );
+
+      assert.close( y_y.dataset.x, 0, 1, "y_y data-x attribute" );
+      assert.close( y_y.dataset.y, 500, 1, "y_y data-y attribute" );
+      assert.close( y_y.dataset.z, 0, 1, "y_y data-z attribute" );
+      assert.close( y_y.dataset.rotateX, 0, 1, "y_y data-rotate-x" );
+      assert.close( y_y.dataset.rotateY, 90, 1, "y_y data-rotate-y" );
+      assert.close( y_y.dataset.rotateZ, 0, 1, "y_y data-rotate-z" );
+
+      assert.close( y_z.dataset.x, 500, 1, "y_z data-x attribute" );
+      assert.close( y_z.dataset.y, 0, 1, "y_z data-y attribute" );
+      assert.close( y_z.dataset.z, 0, 1, "y_z data-z attribute" );
+      assert.close( y_z.dataset.rotateX, 0, 1, "y_z data-rotate-x" );
+      assert.close( y_z.dataset.rotateY, 90, 1, "y_z data-rotate-y" );
+      assert.close( y_z.dataset.rotateZ, 0, 1, "y_z data-rotate-z" );
+
+      assert.close( z.dataset.x, 0, 1, "z data-x attribute" );
+      assert.close( z.dataset.y, 0, 1, "z data-y attribute" );
+      assert.close( z.dataset.z, 0, 1, "z data-z attribute" );
+      assert.close( z.dataset.rotateX, 0, 1, "z data-rotate-x" );
+      assert.close( z.dataset.rotateY, 0, 1, "z data-rotate-y" );
+      assert.close( z.dataset.rotateZ, 90, 1, "z data-rotate-z" );
+
+      assert.close( z_x.dataset.x, 0, 1, "z_x data-x attribute" );
+      assert.close( z_x.dataset.y, 500, 1, "z_x data-y attribute" );
+      assert.close( z_x.dataset.z, 0, 1, "z_x data-z attribute" );
+      assert.close( z_x.dataset.rotateX, 0, 1, "z_x data-rotate-x" );
+      assert.close( z_x.dataset.rotateY, 0, 1, "z_x data-rotate-y" );
+      assert.close( z_x.dataset.rotateZ, 90, 1, "z_x data-rotate-z" );
+
+      assert.close( z_y.dataset.x, -500, 1, "z_y data-x attribute" );
+      assert.close( z_y.dataset.y, 0, 1, "z_y data-y attribute" );
+      assert.close( z_y.dataset.z, 0, 1, "z_y data-z attribute" );
+      assert.close( z_y.dataset.rotateX, 0, 1, "z_y data-rotate-x" );
+      assert.close( z_y.dataset.rotateY, 0, 1, "z_y data-rotate-y" );
+      assert.close( z_y.dataset.rotateZ, 90, 1, "z_y data-rotate-z" );
+
+      assert.close( z_z.dataset.x, 0, 1, "z_z data-x attribute" );
+      assert.close( z_z.dataset.y, 0, 1, "z_z data-y attribute" );
+      assert.close( z_z.dataset.z, 500, 1, "z_z data-z attribute" );
+      assert.close( z_z.dataset.rotateX, 0, 1, "z_z data-rotate-x" );
+      assert.close( z_z.dataset.rotateY, 0, 1, "z_z data-rotate-y" );
+      assert.close( z_z.dataset.rotateZ, 90, 1, "z_z data-rotate-z" );
+
+      assert.close( reset.dataset.x, 100, 1, "reset data-x attribute" );
+      assert.close( reset.dataset.y, 200, 1, "reset data-y attribute" );
+      assert.close( reset.dataset.z, 800, 1, "reset data-z attribute" );
+      assert.close( reset.dataset.rotateX, 0, 1, "reset data-rotate-x" );
+      assert.close( reset.dataset.rotateY, 0, 1, "reset data-rotate-y" );
+      assert.close( reset.dataset.rotateZ, 0, 1, "reset data-rotate-z" );
+
+      done();
+      console.log( "End padding test (sync)" );
+    } )
+  } ); // LoadIframe()
+} );
+
diff --git a/test/plugins/rel/padding_tests_presentation.html b/test/plugins/rel/padding_tests_presentation.html
new file mode 100644
index 0000000..6bcb424
--- /dev/null
+++ b/test/plugins/rel/padding_tests_presentation.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8" />
+    <title>The presentation steps used in an iframe in rel/padding_tests.js</title>
+    <style type="text/css" media="screen">
+.step {
+    position: relative;
+    width: 500px;
+    height: 500px;
+    padding: 40px 60px;
+    margin: 20px auto;
+
+    box-sizing:         border-box;
+
+    line-height: 1.5;
+
+    background-color: yellow;
+    border-radius: 10px;
+    box-shadow: 0 2px 6px rgba(0, 0, 0, .1);
+
+    text-shadow: 0 2px 2px rgba(0, 0, 0, .1);
+
+    font-family: 'Open Sans', Arial, sans-serif;
+    font-size: 40pt;
+    letter-spacing: -1px;
+    border: solid 1px red;
+    opacity: 50%;
+}
+    </style>
+  </head>
+
+  <body class="impress-not-supported">
+    <div id="impress">
+      <div id="origin"   class="step" data-rel-position="relative" data-x="0" data-y="0" data-z="0"></div>
+      <div id="origin_x" class="step" data-rel-to="origin" data-rel-reset data-rel-x="500"></div>
+      <div id="origin_y" class="step" data-rel-to="origin" data-rel-reset data-rel-y="500"></div>
+      <div id="origin_z" class="step" data-rel-to="origin" data-rel-reset data-rel-z="500"></div>
+
+      <div id="x" class="step" data-rel-reset="all" data-x="0" data-y="0" data-z="0" data-rotate-x="90"></div>
+      <div id="x_x" class="step" data-rel-reset data-rel-to="x" data-rel-x="500"></div>
+      <div id="x_y" class="step" data-rel-reset data-rel-to="x" data-rel-y="500"></div>
+      <div id="x_z" class="step" data-rel-reset data-rel-to="x" data-rel-z="500"></div>
+
+      <div id="y" class="step" data-rel-reset="all" data-x="0" data-y="0" data-z="0" data-rotate-y="90"></div>
+      <div id="y_x" class="step" data-rel-reset data-rel-to="y" data-rel-x="500"></div>
+      <div id="y_y" class="step" data-rel-reset data-rel-to="y" data-rel-y="500"></div>
+      <div id="y_z" class="step" data-rel-reset data-rel-to="y" data-rel-z="500"></div>
+
+      <div id="z" class="step" data-rel-reset="all" data-x="0" data-y="0" data-z="0" data-rotate-z="90"></div>
+      <div id="z_x" class="step" data-rel-reset data-rel-to="z" data-rel-x="500"></div>
+      <div id="z_y" class="step" data-rel-reset data-rel-to="z" data-rel-y="500"></div>
+      <div id="z_z" class="step" data-rel-reset data-rel-to="z" data-rel-z="500"></div>
+
+      <div id="reset" class="step" data-rel-reset="all" data-rel-x="100" data-rel-y="200" data-rel-z="300">
+          by data prel-reset="all", paddings should be calculated as if data-rotate-*=0
+      </div>
+
+      <div id="overview" class="step overview" data-x="0" data-y="-1000" data-z="100" data-scale="4" data-rotate-x="45">
+      </div>
+
+    </div>
+
+    <script src="../../../js/impress.js"></script>
+    <!-- <script>impress().init();</script> -->
+  </body>
+<html>
diff --git a/test/plugins/rel/rel_to_tests.js b/test/plugins/rel/rel_to_tests.js
new file mode 100644
index 0000000..86dd448
--- /dev/null
+++ b/test/plugins/rel/rel_to_tests.js
@@ -0,0 +1,147 @@
+QUnit.module( "rel plugin rel_to tests" );
+
+QUnit.test( "rel_to", function( assert ) {
+    window.console.log( "Begin rel_to" );
+    var done = assert.async();
+
+    loadIframe( "test/plugins/rel/rel_to_tests_presentation.html", assert, function() {
+        initPresentation( assert, function() {
+            var iframe = document.getElementById( "presentation-iframe" );
+            var iframeDoc = iframe.contentDocument;
+
+            var root  = iframeDoc.querySelector( "div#impress" );
+            var abs1 = iframeDoc.querySelector( "div#abs-1" );
+            var abs2 = iframeDoc.querySelector( "div#abs-2" );
+            var abs3 = iframeDoc.querySelector( "div#abs-3" );
+            var abs4 = iframeDoc.querySelector( "div#abs-4" );
+            var abs5 = iframeDoc.querySelector( "div#abs-5" );
+            var abs6 = iframeDoc.querySelector( "div#abs-6" );
+            var relative1 = iframeDoc.querySelector( "div#relative-1" );
+            var relative2 = iframeDoc.querySelector( "div#relative-2" );
+            var relative3 = iframeDoc.querySelector( "div#relative-3" );
+            var relative4 = iframeDoc.querySelector( "div#relative-4" );
+            var relative5 = iframeDoc.querySelector( "div#relative-5" );
+            var relative6 = iframeDoc.querySelector( "div#relative-6" );
+            var relative7 = iframeDoc.querySelector( "div#relative-7" );
+            var relative8 = iframeDoc.querySelector( "div#relative-8" );
+            var relative9 = iframeDoc.querySelector( "div#relative-9" );
+            var relative10 = iframeDoc.querySelector( "div#relative-10" );
+
+            assert.close( abs1.dataset.x, 0, 1, "abs-1 data-x attribute" );
+            assert.close( abs1.dataset.y, 0, 1, "abs-1 data-y attribute" );
+            assert.close( abs1.dataset.z, 0, 1, "abs-1 data-z attribute" );
+            assert.close( abs1.dataset.rotateX, 0, 1, "abs-1 data-rotate-x" );
+            assert.close( abs1.dataset.rotateY, 0, 1, "abs-1 data-rotate-y" );
+            assert.close( abs1.dataset.rotateZ, 0, 1, "abs-1 data-rotate-z" );
+
+            assert.close( abs2.dataset.x, 854, 1, "abs-2 data-x attribute" );
+            assert.close( abs2.dataset.y, -125, 1, "abs-2 data-y attribute" );
+            assert.close( abs2.dataset.z, -354, 1, "abs-2 data-z attribute" );
+            assert.close( abs2.dataset.rotateX, 0, 1, "abs-2 data-rotate-x attribute" );
+            assert.close( abs2.dataset.rotateY, 45, 1, "abs-2 data-rotate-y attribute" );
+            assert.close( abs2.dataset.rotateZ, 0, 1, "abs-2 data-rotate-z attribute" );
+
+            assert.close( abs3.dataset.x, 1708, 1, "abs-3 data-x attribute" );
+            assert.close( abs3.dataset.y, -250, 1, "abs-3 data-y attribute" );
+            assert.close( abs3.dataset.z, -708, 1, "abs-3 data-z attribute" );
+            assert.close( abs3.dataset.rotateX, 0, 1, "abs-3 data-rotate-x attribute" );
+            assert.close( abs3.dataset.rotateY, 45, 1, "abs-3 data-rotate-y attribute" );
+            assert.close( abs3.dataset.rotateZ, 0, 1, "abs-3 data-rotate-z attribute" );
+
+            assert.close( abs4.dataset.x, 1808, 1, "abs-4 data-x attribute" );
+            assert.close( abs4.dataset.y, -250, 1, "abs-4 data-y attribute" );
+            assert.close( abs4.dataset.z, -708, 1, "abs-4 data-z attribute" );
+            assert.close( abs4.dataset.rotateX, 0, 1, "abs-4 data-rotate-x attribute" );
+            assert.close( abs4.dataset.rotateY, 0, 1, "abs-4 data-rotate-y attribute" );
+            assert.close( abs4.dataset.rotateZ, 0, 1, "abs-4 data-rotate-z attribute" );
+
+            assert.close( abs5.dataset.x, 1708, 1, "abs-5 data-x attribute" );
+            assert.close( abs5.dataset.y, -250, 1, "abs-5 data-y attribute" );
+            assert.close( abs5.dataset.z, -708, 1, "abs-5 data-z attribute" );
+            assert.close( abs5.dataset.rotateX, 0, 1, "abs-5 data-rotate-x attribute" );
+            assert.close( abs5.dataset.rotateY, 0, 1, "abs-5 data-rotate-y attribute" );
+            assert.close( abs5.dataset.rotateZ, 0, 1, "abs-5 data-rotate-z attribute" );
+
+            assert.close( abs6.dataset.x, 1708, 1, "abs-6 data-x attribute" );
+            assert.close( abs6.dataset.y, -250, 1, "abs-6 data-y attribute" );
+            assert.close( abs6.dataset.z, -708, 1, "abs-6 data-z attribute" );
+            assert.close( abs6.dataset.rotateX, 0, 1, "abs-6 data-rotate-x attribute" );
+            assert.close( abs6.dataset.rotateY, 0, 1, "abs-6 data-rotate-y attribute" );
+            assert.close( abs6.dataset.rotateZ, 0, 1, "abs-6 data-rotate-z attribute" );
+
+            assert.close( relative1.dataset.x, 0, 1, "relative-1 data-x attribute" );
+            assert.close( relative1.dataset.y, 1000, 1, "relative-1 data-y attribute" );
+            assert.close( relative1.dataset.z, 0, 1, "relative-1 data-z attribute" );
+            assert.close( relative1.dataset.rotateX, 0, 1, "relative-1 data-rotate-x" );
+            assert.close( relative1.dataset.rotateY, 0, 1, "relative-1 data-rotate-y" );
+            assert.close( relative1.dataset.rotateZ, 0, 1, "relative-1 data-rotate-z" );
+
+            assert.close( relative2.dataset.x, 854, 1, "relative-2 data-x attribute" );
+            assert.close( relative2.dataset.y, 875, 1, "relative-2 data-y attribute" );
+            assert.close( relative2.dataset.z, -354, 1, "relative-2 data-z attribute" );
+            assert.close( relative2.dataset.rotateX, 0, 1, "relative-2 data-rotate-x attribute" );
+            assert.close( relative2.dataset.rotateY, 45, 1, "relative-2 data-rotate-y attribute" );
+            assert.close( relative2.dataset.rotateZ, 0, 1, "relative-2 data-rotate-z attribute" );
+
+            assert.close( relative3.dataset.x, 1208, 1, "relative-3 data-x attribute" );
+            assert.close( relative3.dataset.y, 750, 1, "relative-3 data-y attribute" );
+            assert.close( relative3.dataset.z, -1208, 1, "relative-3 data-z attribute" );
+            assert.close( relative3.dataset.rotateX, 0, 1, "relative-3 data-rotate-x attribute" );
+            assert.close( relative3.dataset.rotateY, 90, 1, "relative-3 data-rotate-y attribute" );
+            assert.close( relative3.dataset.rotateZ, 0, 1, "relative-3 data-rotate-z attribute" );
+
+            assert.close( relative4.dataset.x, 1308, 1, "relative-4 data-x attribute" );
+            assert.close( relative4.dataset.y, 750, 1, "relative-4 data-y attribute" );
+            assert.close( relative4.dataset.z, -1208, 1, "relative-4 data-z attribute" );
+            assert.close( relative4.dataset.rotateX, 0, 1, "relative-4 data-rotate-x attribute" );
+            assert.close( relative4.dataset.rotateY, 0, 1, "relative-4 data-rotate-y attribute" );
+            assert.close( relative4.dataset.rotateZ, 0, 1, "relative-4 data-rotate-z attribute" );
+
+            assert.close( relative5.dataset.x, 854, 1, "relative-5 data-x attribute" );
+            assert.close( relative5.dataset.y, 625, 1, "relative-5 data-y attribute" );
+            assert.close( relative5.dataset.z, -2062, 1, "relative-5 data-z attribute" );
+            assert.close( relative5.dataset.rotateX, 0, 1, "relative-5 data-rotate-x" );
+            assert.close( relative5.dataset.rotateY, 135, 1, "relative-5 data-rotate-y" );
+            assert.close( relative5.dataset.rotateZ, 0, 1, "relative-5 data-rotate-z" );
+
+            assert.close( relative6.dataset.x, 0, 1, "relative-6 data-x attribute" );
+            assert.close( relative6.dataset.y, 500, 1, "relative-6 data-y attribute" );
+            assert.close( relative6.dataset.z, -2416, 1, "relative-6 data-z attribute" );
+            assert.close( relative6.dataset.rotateX, 0, 1, "relative-6 data-rotate-x" );
+            assert.close( relative6.dataset.rotateY, 180, 1, "relative-6 data-rotate-y" );
+            assert.close( relative6.dataset.rotateZ, 0, 1, "relative-6 data-rotate-z" );
+
+            assert.close( relative7.dataset.x, 1208, 1, "relative-7 data-x attribute" );
+            assert.close( relative7.dataset.y, 750, 1, "relative-7 data-y attribute" );
+            assert.close( relative7.dataset.z, -1208, 1, "relative-7 data-z attribute" );
+            assert.close( relative7.dataset.rotateX, 0, 1, "relative-7 data-rotate-x" );
+            assert.close( relative7.dataset.rotateY, 90, 1, "relative-7 data-rotate-y" );
+            assert.close( relative7.dataset.rotateZ, 0, 1, "relative-7 data-rotate-z" );
+
+            assert.close( relative8.dataset.x, 1208, 1, "relative-8 data-x attribute" );
+            assert.close( relative8.dataset.y, 750, 1, "relative-8 data-y attribute" );
+            assert.close( relative8.dataset.z, -1208, 1, "relative-8 data-z attribute" );
+            assert.close( relative8.dataset.rotateX, 0, 1, "relative-8 data-rotate-x" );
+            assert.close( relative8.dataset.rotateY, 90, 1, "relative-8 data-rotate-y" );
+            assert.close( relative8.dataset.rotateZ, 0, 1, "relative-8 data-rotate-z" );
+
+            assert.close( relative9.dataset.x, 1208, 1, "relative-9 data-x attribute" );
+            assert.close( relative9.dataset.y, 750, 1, "relative-9 data-y attribute" );
+            assert.close( relative9.dataset.z, -1208, 1, "relative-9 data-z attribute" );
+            assert.close( relative9.dataset.rotateX, 0, 1, "relative-9 data-rotate-x" );
+            assert.close( relative9.dataset.rotateY, 0, 1, "relative-9 data-rotate-y" );
+            assert.close( relative9.dataset.rotateZ, 0, 1, "relative-9 data-rotate-z" );
+
+            assert.close( relative10.dataset.x, 1208, 1, "relative-10 data-x attribute" );
+            assert.close( relative10.dataset.y, 750, 1, "relative-10 data-y attribute" );
+            assert.close( relative10.dataset.z, -1208, 1, "relative-10 data-z attribute" );
+            assert.close( relative10.dataset.rotateX, 0, 1, "relative-10 data-rotate-x" );
+            assert.close( relative10.dataset.rotateY, 0, 1, "relative-10 data-rotate-y" );
+            assert.close( relative10.dataset.rotateZ, 0, 1, "relative-10 data-rotate-z" );
+
+            done();
+            console.log( "End rel_to test (sync)" );
+        } )
+    } ); // LoadIframe()
+} );
+
diff --git a/test/plugins/rel/rel_to_tests_presentation.html b/test/plugins/rel/rel_to_tests_presentation.html
new file mode 100644
index 0000000..3682bc1
--- /dev/null
+++ b/test/plugins/rel/rel_to_tests_presentation.html
@@ -0,0 +1,106 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8" />
+    <title>The presentation steps used in an iframe in rel/rotation_tests.js</title>
+    <style type="text/css" media="screen">
+.step {
+    position: relative;
+    width: 1000px;
+    height: 1000px;
+    padding: 40px 60px;
+    margin: 20px auto;
+
+    box-sizing:         border-box;
+
+    line-height: 1.5;
+
+    background-color: none;
+    border-radius: 10px;
+    box-shadow: 0 2px 6px rgba(0, 0, 0, .1);
+
+    text-shadow: 0 2px 2px rgba(0, 0, 0, .1);
+
+    font-family: 'Open Sans', Arial, sans-serif;
+    font-size: 40pt;
+    letter-spacing: -1px;
+    border: solid 1px red;
+}
+    </style>
+  </head>
+
+  <body class="impress-not-supported">
+    <div id="impress" data-width="1920" data-height="1200">
+      <div id="overview" class="step overview" data-x="0" data-y="-1000" data-z="100" data-scale="4" data-rotate-x="45">
+        <h1>Testing related to <code>data-rel-to</code></h1>
+      </div>
+
+      <div id="abs-1" class="step" data-x="0" data-y="0" data-z="0">
+        <p>Testing default rel-position</p>
+      </div>
+
+      <div id="abs-2" class="step" data-rel-rotate-y="45" data-rel-z="-354" data-rel-x="854" data-rel-y="-125">
+        <p>default rel-position, rel-rotate not work</p>
+      </div>
+
+      <div id="abs-3" class="step">
+        <p>Should inherit rel-x/y/z, not rel-rotate-y</p>
+      </div>
+
+      <div id="abs-4" class="step" data-rel-reset data-rel-x="100">
+        <p>position out of flow</p>
+      </div>
+
+      <div id="abs-5" class="step" data-rel-to="abs-3">
+        <p>Should re-position at abs-3, but doesn't inherit from it</p>
+      </div>
+
+      <div id="abs-6" class="step">
+        <p>Should be the same as abs-5</p>
+      </div>
+
+      <div id="relative-1" class="step" data-rel-reset="all" data-rel-position="relative" data-x="0" data-y="1000" data-z="0">
+        <p>Testing rel-position="relative"</p>
+      </div>
+
+      <div id="relative-2" class="step" data-rel-rotate-y="45" data-rel-z="-354" data-rel-x="854" data-rel-y="-125">
+        <p>All rel-* will be inherited from previous slide</p>
+      </div>
+
+      <div id="relative-3" class="step">
+        <p>inherit again</p>
+      </div>
+
+      <div id="relative-4" class="step" data-rel-reset="all" data-rel-x="100">
+        <p>position out of flow</p>
+      </div>
+
+      <div id="relative-5" class="step" data-rel-to="relative-3">
+        <p>Should re-position at relative-3, and inherit all relatives from it</p>
+      </div>
+
+      <div id="relative-6" class="step">
+        <p>keep inheriting</p>
+      </div>
+
+      <div id="relative-7" class="step" data-rel-to="relative-3" data-rel-reset>
+        <p>Should re-position at relative-3, but clear all relative attributes</p>
+      </div>
+
+      <div id="relative-8" class="step">
+        <p>keep inheriting</p>
+      </div>
+
+      <div id="relative-9" class="step" data-rel-to="relative-3" data-rel-reset="all">
+        <p>Should re-position at relative-3, but clear data-rotate-* in addition to all relative attributes</p>
+      </div>
+
+      <div id="relative-10" class="step">
+        <p>keep inheriting</p>
+      </div>
+    </div>
+
+    <script src="../../../js/impress.js"></script>
+    <!-- <script>impress().init();</script> -->
+  </body>
+<html>
diff --git a/test/plugins/rel/relative_to_screen_size_tests.js b/test/plugins/rel/relative_to_screen_size_tests.js
new file mode 100644
index 0000000..fb90dc0
--- /dev/null
+++ b/test/plugins/rel/relative_to_screen_size_tests.js
@@ -0,0 +1,45 @@
+QUnit.module( "rel plugin relative to screen size tests" );
+
+QUnit.test( "relative_to_screen_size", function( assert ) {
+  window.console.log( "Begin relative_to_screen_size" );
+  var done = assert.async();
+
+  loadIframe( "test/plugins/rel/relative_to_screen_size_tests_presentation.html", assert, function() {
+    initPresentation( assert, function() {
+      var iframe = document.getElementById( "presentation-iframe" );
+      var iframeDoc = iframe.contentDocument;
+
+      var root  = iframeDoc.querySelector( "div#impress" );
+
+      var origin = iframeDoc.querySelector( "div#origin" );
+      var step1 = iframeDoc.querySelector( "div#step1" );
+      var step2 = iframeDoc.querySelector( "div#step2" );
+      var step3 = iframeDoc.querySelector( "div#step3" );
+      var overview = iframeDoc.querySelector( "div#overview" );
+
+      assert.equal( origin.dataset.x, 0, "origin data-x attribute" );
+      assert.equal( origin.dataset.y, 0, "origin data-y attribute" );
+      assert.equal( origin.dataset.z, 0, "origin data-z attribute" );
+
+      assert.equal( step1.dataset.x, 2000, "step1 data-x attribute" );
+      assert.equal( step1.dataset.y, 1500, "step1 data-y attribute" );
+      assert.equal( step1.dataset.z, -2000, "step1 data-z attribute" );
+
+      assert.equal( step2.dataset.x, -3000, "step2 data-x attribute" );
+      assert.equal( step2.dataset.y, -4000, "step2 data-y attribute" );
+      assert.equal( step2.dataset.z, 3000, "step2 data-z attribute" );
+
+      assert.equal( step3.dataset.x, 1000, "step3 data-x attribute" );
+      assert.equal( step3.dataset.y, -750, "step3 data-y attribute" );
+      assert.equal( step3.dataset.z, 1000, "step3 data-z attribute" );
+
+      assert.equal( overview.dataset.x, 2000,  "overview data-x attribute" );
+      assert.equal( overview.dataset.y, -1500, "overview data-y attribute" );
+      assert.equal( overview.dataset.z, 1500,  "overview data-z attribute" );
+
+      done();
+      console.log( "End relative_to_screen_size test (sync)" );
+    } )
+  } ); // LoadIframe()
+} );
+
diff --git a/test/plugins/rel/relative_to_screen_size_tests_presentation.html b/test/plugins/rel/relative_to_screen_size_tests_presentation.html
new file mode 100644
index 0000000..df6afdd
--- /dev/null
+++ b/test/plugins/rel/relative_to_screen_size_tests_presentation.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8" />
+    <title>The presentation steps used in an iframe in rel/relative_to_screen_size_tests.js</title>
+    <style type="text/css" media="screen">
+.step {
+    position: relative;
+    width: 500px;
+    height: 500px;
+    padding: 40px 60px;
+    margin: 20px auto;
+
+    box-sizing:         border-box;
+
+    line-height: 1.5;
+
+    background-color: yellow;
+    border-radius: 10px;
+    box-shadow: 0 2px 6px rgba(0, 0, 0, .1);
+
+    text-shadow: 0 2px 2px rgba(0, 0, 0, .1);
+
+    font-family: 'Open Sans', Arial, sans-serif;
+    font-size: 40pt;
+    letter-spacing: -1px;
+    border: solid 1px red;
+    opacity: 50%;
+}
+    </style>
+  </head>
+
+  <body class="impress-not-supported">
+    <div id="impress" data-width="2000" data-height="1500">
+      <div id="origin"   class="step" data-rel-position="relative" data-x="0" data-y="0" data-z="0"></div>
+      <div id="step1" class="step" data-rel-to="origin" data-rel-x="1w" data-rel-y="1h" data-rel-z="-1w"></div>
+      <div id="step2" class="step" data-rel-to="origin" data-rel-x="-2h" data-rel-y="-2w" data-rel-z="2h"></div>
+      <div id="step3" class="step" data-rel-to="origin" data-rel-x="0.5w" data-rel-y="-0.5h" data-rel-z="0.5w"></div>
+
+      <div id="overview" class="step overview" data-x="1w" data-y="-1h" data-z="1h" data-scale="4" data-rotate-x="45">
+      </div>
+
+    </div>
+
+    <script src="../../../js/impress.js"></script>
+    <!-- <script>impress().init();</script> -->
+  </body>
+<html>
diff --git a/test/plugins/rel/rotation_tests.js b/test/plugins/rel/rotation_tests.js
new file mode 100644
index 0000000..acde093
--- /dev/null
+++ b/test/plugins/rel/rotation_tests.js
@@ -0,0 +1,101 @@
+QUnit.module( "rel plugin rotation tests" );
+
+QUnit.test( "rotation_relative", function( assert ) {
+  window.console.log( "Begin rotation_relative" );
+  var done = assert.async();
+
+  loadIframe( "test/plugins/rel/rotation_tests_presentation.html", assert, function() {
+    initPresentation( assert, function() {
+      var iframe = document.getElementById( "presentation-iframe" );
+      var iframeDoc = iframe.contentDocument;
+
+      var root  = iframeDoc.querySelector( "div#impress" );
+      var step1 = iframeDoc.querySelector( "div#step-1" );
+      var step2 = iframeDoc.querySelector( "div#step-2" );
+      var step3 = iframeDoc.querySelector( "div#step-3" );
+      var step4 = iframeDoc.querySelector( "div#step-4" );
+      var step5 = iframeDoc.querySelector( "div#step-5" );
+      var step6 = iframeDoc.querySelector( "div#step-6" );
+      var step7 = iframeDoc.querySelector( "div#step-7" );
+      var step8 = iframeDoc.querySelector( "div#step-8" );
+      var reset = iframeDoc.querySelector( "div#reset" );
+      var rotate = iframeDoc.querySelector( "div#rotate" );
+
+      assert.close( step1.dataset.x, 0, 1, "step-1 data-x attribute" );
+      assert.close( step1.dataset.y, 0, 1, "step-1 data-y attribute" );
+      assert.close( step1.dataset.z, 0, 1, "step-1 data-z attribute" );
+      assert.close( step1.dataset.rotateX, 0, 1, "step-1 data-rotate-x" );
+      assert.close( step1.dataset.rotateY, 0, 1, "step-1 data-rotate-y" );
+      assert.close( step1.dataset.rotateZ, 0, 1, "step-1 data-rotate-z" );
+
+      assert.close( step2.dataset.x, 854, 1, "step-2 data-x attribute" );
+      assert.close( step2.dataset.y, -125, 1, "step-2 data-y attribute" );
+      assert.close( step2.dataset.z, -354, 1, "step-2 data-z attribute" );
+      assert.close( step2.dataset.rotateX, 0, 1, "step-2 data-rotate-x attribute" );
+      assert.close( step2.dataset.rotateY, 45, 1, "step-2 data-rotate-y attribute" );
+      assert.close( step2.dataset.rotateZ, 0, 1, "step-2 data-rotate-z attribute" );
+
+      assert.close( step3.dataset.x, 1208, 1, "step-3 data-x attribute" );
+      assert.close( step3.dataset.y, -250, 1, "step-3 data-y attribute" );
+      assert.close( step3.dataset.z, -1208, 1, "step-3 data-z attribute" );
+      assert.close( step3.dataset.rotateX, 0, 1, "step-3 data-rotate-x attribute" );
+      assert.close( step3.dataset.rotateY, 90, 1, "step-3 data-rotate-y attribute" );
+      assert.close( step3.dataset.rotateZ, 0, 1, "step-3 data-rotate-z attribute" );
+
+      assert.close( step4.dataset.x, 854, 1, "step-4 data-x attribute" );
+      assert.close( step4.dataset.y, -375, 1, "step-4 data-y attribute" );
+      assert.close( step4.dataset.z, -2062, 1, "step-4 data-z attribute" );
+      assert.close( step4.dataset.rotateX, 0, 1, "step-4 data-rotate-x" );
+      assert.close( step4.dataset.rotateY, 135, 1, "step-4 data-rotate-y" );
+      assert.close( step4.dataset.rotateZ, 0, 1, "step-4 data-rotate-z" );
+
+      assert.close( step5.dataset.x, 0, 1, "step-5 data-x attribute" );
+      assert.close( step5.dataset.y, -500, 1, "step-5 data-y attribute" );
+      assert.close( step5.dataset.z, -2416, 1, "step-5 data-z attribute" );
+      assert.close( step5.dataset.rotateX, 0, 1, "step-5 data-rotate-x" );
+      assert.close( step5.dataset.rotateY, 180, 1, "step-5 data-rotate-y" );
+      assert.close( step5.dataset.rotateZ, 0, 1, "step-5 data-rotate-z" );
+
+      assert.close( step6.dataset.x, -854, 1, "step-6 data-x attribute" );
+      assert.close( step6.dataset.y, -375, 1, "step-6 data-y attribute" );
+      assert.close( step6.dataset.z, -2062, 1, "step-6 data-z attribute" );
+      assert.close( step6.dataset.rotateX, 0, 1, "step-6 data-rotate-x" );
+      assert.close( step6.dataset.rotateY, 225, 1, "step-6 data-rotate-y" );
+      assert.close( step6.dataset.rotateZ, 0, 1, "step-6 data-rotate-z" );
+
+      assert.close( step7.dataset.x, -1208, 1, "step-7 data-x attribute" );
+      assert.close( step7.dataset.y, -250, 1, "step-7 data-y attribute" );
+      assert.close( step7.dataset.z, -1208, 1, "step-7 data-z attribute" );
+      assert.close( step7.dataset.rotateX, 0, 1, "step-7 data-rotate-x attribute" );
+      assert.close( step7.dataset.rotateY, 270, 1, "step-7 data-rotate-y attribute" );
+      assert.close( step7.dataset.rotateZ, 0, 1, "step-7 data-rotate-z attribute" );
+
+      assert.close( step8.dataset.x, -854, 1, "step-8 data-x attribute" );
+      assert.close( step8.dataset.y, -125, 1, "step-8 data-y attribute" );
+      assert.close( step8.dataset.z, -354, 1, "step-8 data-z attribute" );
+      assert.close( step8.dataset.rotateX, 0, 1, "step-8 data-rotate-x attribute" );
+      assert.close( step8.dataset.rotateY, 315, 1, "step-8 data-rotate-y attribute" );
+      assert.close( step8.dataset.rotateZ, 0, 1, "step-8 data-rotate-z attribute" );
+
+      assert.equal( reset.dataset.x, 0, "reset data-x attribute" );
+      assert.equal( reset.dataset.y, 0, "reset data-y attribute" );
+      assert.equal( reset.dataset.z, 0, "reset data-z attribute" );
+      assert.equal( reset.dataset.rotateX, 0, "reset data-rotate-x" );
+      assert.equal( reset.dataset.rotateY, 0, "reset data-rotate-y" );
+      assert.equal( reset.dataset.rotateZ, 0, "reset data-rotate-z" );
+      assert.equal( reset.dataset.rotateOrder, "zyx", "reset data-rotate-order" );
+
+      assert.equal( rotate.dataset.x, 0, "rotate data-x attribute" );
+      assert.equal( rotate.dataset.y, 0, "rotate data-y attribute" );
+      assert.equal( rotate.dataset.z, 0, "rotate data-z attribute" );
+      assert.equal( rotate.dataset.rotateX, 0, "rotate data-rotate-x" );
+      assert.equal( rotate.dataset.rotateY, 0, "rotate data-rotate-y" );
+      assert.equal( rotate.dataset.rotateZ, 123, "rotate data-rotate-z" );
+      assert.equal( rotate.dataset.rotateOrder, "xyz", "rotate data-rotate-order" );
+
+      done();
+      console.log( "End rotation test (sync)" );
+    } )
+  } ); // LoadIframe()
+} );
+
diff --git a/test/plugins/rel/rotation_tests_presentation.html b/test/plugins/rel/rotation_tests_presentation.html
new file mode 100644
index 0000000..681f28d
--- /dev/null
+++ b/test/plugins/rel/rotation_tests_presentation.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8" />
+    <title>The presentation steps used in an iframe in rel/rotation_tests.js</title>
+    <style type="text/css" media="screen">
+.step {
+    position: relative;
+    width: 1000px;
+    height: 1000px;
+    padding: 40px 60px;
+    margin: 20px auto;
+
+    box-sizing:         border-box;
+
+    line-height: 1.5;
+
+    background-color: white;
+    border-radius: 10px;
+    box-shadow: 0 2px 6px rgba(0, 0, 0, .1);
+
+    text-shadow: 0 2px 2px rgba(0, 0, 0, .1);
+
+    font-family: 'Open Sans', Arial, sans-serif;
+    font-size: 40pt;
+    letter-spacing: -1px;
+    border: solid 1px red;
+}
+    </style>
+  </head>
+
+  <body class="impress-not-supported">
+    <div id="impress">
+      <div id="overview" class="step overview" data-x="0" data-y="-1000" data-z="100" data-scale="4" data-rotate-x="45">
+        <h1>3D Rotations Demo</h1>
+      </div>
+
+      <div id="step-1" class="step" data-x="0" data-y="0" data-z="0" data-goto-prev="step-8">
+        <p>Slide one</p>
+      </div>
+
+      <div id="step-2" class="step" data-rel-position="relative" data-rel-rotate-y="45" data-rel-z="-354" data-rel-x="854" data-rel-y="-125">
+        <p>Slide two</p>
+      </div>
+
+      <div id="step-3" class="step">
+        <p>Slide three</p>
+      </div>
+
+      <div id="step-4" class="step">
+        <p>Slide four</p>
+      </div>
+
+      <div id="step-5" class="step">
+        <p>Slide five</p>
+      </div>
+
+      <div id="step-6" class="step" data-rel-y="125">
+        <p>Slide six</p>
+      </div>
+
+      <div id="step-7" class="step">
+        <p>Slide seven</p>
+      </div>
+
+      <div id="step-8" class="step" data-goto-next="step-1">
+        <p>Slide eight</p>
+      </div>
+
+      <div id="reset" class="step" data-x=0 data-y=0 data-z=0 data-rotate-x=0 data-rotate-y=0 data-rotate-z=0 data-rotate-order="zyx">
+        <p>Reset all properties</p>
+      </div>
+
+      <div id="rotate" class="step" data-rotate=123>
+        <p>Testing the data-rotate attribute</p>
+      </div>
+    </div>
+
+    <script src="../../../js/impress.js"></script>
+    <!-- <script>impress().init();</script> -->
+  </body>
+<html>

Debdiff

File lists identical (after any substitutions)

No differences were encountered in the control files

More details

Full run details