Docs: build perfetto.dev with JS and add autopush

This CL achieves two goals:
1. Rewrites the build rules for the docs site using
   a custom JS script, similar to what we did recently
   for ui.perfetto.dev. This makes testing local docs
   changes easier. Previously it required the cloud SDK
   and caused problems to many devs.
2. Allows autopushing via Cloud Build, using the same
   plan of go/perfetto-ui-autopush.

Bug: 179864115
Change-Id: I28906d18b3591a0e94f31e6c16ce15710be851c1
diff --git a/BUILD.gn b/BUILD.gn
index 982272c..4f3dcf8 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -176,10 +176,6 @@
   group("ui") {
     deps = [ "ui" ]
   }
-
-  group("site") {
-    deps = [ "infra/perfetto.dev:site" ]
-  }
 }
 
 # In Android builds, we build the code of traced and traced_probes in one shared
diff --git a/docs/images/perfetto-stack.svg b/docs/images/perfetto-stack.svg
index 7b7fead..aa5b986 100644
--- a/docs/images/perfetto-stack.svg
+++ b/docs/images/perfetto-stack.svg
@@ -1,3 +1,3 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1652px" height="776px" viewBox="-0.5 -0.5 1652 776" content="&lt;mxfile host=&quot;app.diagrams.net&quot; modified=&quot;2020-05-22T22:41:34.812Z&quot; agent=&quot;5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36&quot; etag=&quot;QckB1rB-GYIfxBJ2Ru_L&quot; version=&quot;13.1.3&quot; type=&quot;device&quot;&gt;&lt;diagram id=&quot;7NN0wUOKmaAmGsXKK3Xs&quot; name=&quot;Page-1&quot;&gt;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&lt;/diagram&gt;&lt;/mxfile&gt;"><defs/><g><rect x="0" y="75" width="900" height="700" fill="#f8fbf3" stroke="none" pointer-events="all"/><g fill="#388E3C" font-family="Roboto" text-anchor="middle" font-size="36px"><text x="449.5" y="134.5">Record traces</text></g><rect x="600" y="150" width="300" height="600" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 298px; height: 1px; padding-top: 157px; margin-left: 601px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 32px; font-family: Roboto; color: #7cb342; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font face="roboto" style="font-size: 32px"><span style="font-size: 32px">In-app tracing</span></font></div></div></div></foreignObject><text x="750" y="189" fill="#7cb342" font-family="Roboto" font-size="32px" text-anchor="middle">In-app tracing</text></switch></g><ellipse cx="450" cy="50" rx="50" ry="50" fill="#4caf50" stroke="none" pointer-events="all"/><image x="417.5" y="17.5" width="64" height="64" xlink:href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0id2hpdGUiIHdpZHRoPSIxOHB4IiBoZWlnaHQ9IjE4cHgiPjxwYXRoIGQ9Ik0wIDBoMjR2MjRIMFYweiIgZmlsbD0ibm9uZSIvPjxwYXRoIGQ9Ik0xOCA0djFoLTJWNGMwLS41NS0uNDUtMS0xLTFIOWMtLjU1IDAtMSAuNDUtMSAxdjFINlY0YzAtLjU1LS40NS0xLTEtMXMtMSAuNDUtMSAxdjE2YzAgLjU1LjQ1IDEgMSAxczEtLjQ1IDEtMXYtMWgydjFjMCAuNTUuNDUgMSAxIDFoNmMuNTUgMCAxLS40NSAxLTF2LTFoMnYxYzAgLjU1LjQ1IDEgMSAxczEtLjQ1IDEtMVY0YzAtLjU1LS40NS0xLTEtMXMtMSAuNDUtMSAxek04IDE3SDZ2LTJoMnYyem0wLTRINnYtMmgydjJ6bTAtNEg2VjdoMnYyem0xMCA4aC0ydi0yaDJ2MnptMC00aC0ydi0yaDJ2MnptMC00aC0yVjdoMnYyeiIvPjwvc3ZnPg==" preserveAspectRatio="none" transform="rotate(90,450,50)"/><rect x="0" y="150" width="300" height="500" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 298px; height: 1px; padding-top: 157px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 32px; font-family: Roboto; color: #7cb342; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><span style="font-family: &quot;roboto&quot; ; font-size: 32px ; font-style: normal ; font-weight: 400 ; letter-spacing: normal ; text-indent: 0px ; text-transform: none ; word-spacing: 0px ; float: none ; display: inline">System </span><span style="font-family: &quot;roboto&quot; ; font-size: 32px ; font-style: normal ; font-weight: 400 ; letter-spacing: normal ; text-indent: 0px ; text-transform: none ; word-spacing: 0px ; float: none ; display: inline">tracing</span></div></div></div></foreignObject><text x="150" y="189" fill="#7cb342" font-family="Roboto" font-size="32px" text-anchor="middle">System tracing</text></switch></g><rect x="300" y="150" width="300" height="600" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 298px; height: 1px; padding-top: 157px; margin-left: 301px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 32px; font-family: Roboto; color: #7cb342; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font face="roboto" style="font-size: 32px"><span style="font-size: 32px">Chrome tracing</span></font></div></div></div></foreignObject><text x="450" y="189" fill="#7cb342" font-family="Roboto" font-size="32px" text-anchor="middle">Chrome tracing</text></switch></g><rect x="25" y="225" width="250" height="300" fill="#dcedc8" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 248px; height: 1px; padding-top: 522px; margin-left: 26px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 28px; font-family: Roboto; color: #1b5e20; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><span style="font-size: 28px">Data sources<br style="font-size: 28px" /></span><font style="font-size: 20px">Linux/Android</font></div></div></div></foreignObject><text x="150" y="522" fill="#1b5e20" font-family="Roboto" font-size="28px" text-anchor="middle">Data sources...</text></switch></g><a target="_top" xlink:href="/docs/data-sources/cpu-scheduling"><rect x="50" y="250" width="200" height="50" fill="#c5e1a5" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 198px; height: 1px; padding-top: 275px; margin-left: 51px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 25px; font-family: Roboto; color: #1b5e20; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><span style="font-size: 25px">Linux ftrace</span></div></div></div></foreignObject><text x="150" y="283" fill="#1b5e20" font-family="Roboto" font-size="25px" text-anchor="middle">Linux ftrace</text></switch></g></a><a target="_top" xlink:href="/docs/data-sources/memory-counters"><rect x="50" y="325" width="200" height="50" fill="#c5e1a5" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 198px; height: 1px; padding-top: 350px; margin-left: 51px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 25px; font-family: Roboto; color: #1b5e20; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font style="font-size: 25px">/proc </font><span style="font-size: 25px">pollers</span></div></div></div></foreignObject><text x="150" y="358" fill="#1b5e20" font-family="Roboto" font-size="25px" text-anchor="middle">/proc pollers</text></switch></g></a><a target="_top" xlink:href="/docs/data-sources/native-heap-profiler"><rect x="50" y="396.88" width="200" height="50" fill="#c5e1a5" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 198px; height: 1px; padding-top: 422px; margin-left: 51px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 25px; font-family: Roboto; color: #1b5e20; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><span style="font-size: 25px">Heap profilers</span></div></div></div></foreignObject><text x="150" y="429" fill="#1b5e20" font-family="Roboto" font-size="25px" text-anchor="middle">Heap profilers</text></switch></g></a><a target="_top" xlink:href="/docs/instrumentation/tracing-sdk"><rect x="25" y="650" width="850" height="100" fill="#dcedc8" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 848px; height: 1px; padding-top: 700px; margin-left: 26px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 32px; font-family: Roboto; color: #1b5e20; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font style="font-size: 36px">Tracing C++ Library<br /></font><div><font style="font-size: 20px">Android / Linux / MacOS / Windows</font></div></div></div></div></foreignObject><text x="450" y="710" fill="#1b5e20" font-family="Roboto" font-size="32px" text-anchor="middle">Tracing C++ Library...</text></switch></g></a><rect x="925" y="75" width="350" height="700" fill="#fff3e0" stroke="none" pointer-events="all"/><g fill="#FF9800" font-family="Roboto" text-anchor="middle" font-size="36px"><text x="1099.5" y="134.5">Analyze traces</text></g><ellipse cx="1100" cy="50" rx="50" ry="50" fill="#ff9800" stroke="none" pointer-events="all"/><image x="1067.5" y="17.5" width="64" height="64" xlink:href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0id2hpdGUiIHdpZHRoPSIxOHB4IiBoZWlnaHQ9IjE4cHgiPjxwYXRoIGQ9Ik0wIDBoMjR2MjRIMFYweiIgZmlsbD0ibm9uZSIvPjxwYXRoIGQ9Ik0xOSAzSDVjLTEuMSAwLTIgLjktMiAydjE0YzAgMS4xLjkgMiAyIDJoMTRjMS4xIDAgMi0uOSAyLTJWNWMwLTEuMS0uOS0yLTItMnpNOCAxN2MtLjU1IDAtMS0uNDUtMS0xdi01YzAtLjU1LjQ1LTEgMS0xczEgLjQ1IDEgMXY1YzAgLjU1LS40NSAxLTEgMXptNCAwYy0uNTUgMC0xLS40NS0xLTFWOGMwLS41NS40NS0xIDEtMXMxIC40NSAxIDF2OGMwIC41NS0uNDUgMS0xIDF6bTQgMGMtLjU1IDAtMS0uNDUtMS0xdi0yYzAtLjU1LjQ1LTEgMS0xczEgLjQ1IDEgMXYyYzAgLjU1LS40NSAxLTEgMXoiLz48L3N2Zz4=" preserveAspectRatio="none"/><a target="_top" xlink:href="/docs/analysis/trace-processor"><rect x="943.75" y="168.75" width="312.5" height="581.25" fill="#ffe0b2" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 311px; height: 1px; padding-top: 196px; margin-left: 945px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 32px; font-family: Roboto; color: #EA8600; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><span style="font-size: 36px">Trace Processor<br /></span><span style="font-size: 20px">Android / Linux / MacOS / Win</span></div></div></div></foreignObject><text x="1100" y="228" fill="#EA8600" font-family="Roboto" font-size="32px" text-anchor="middle">Trace Processor...</text></switch></g></a><rect x="1300" y="75" width="350" height="700" fill="#e8f0fe" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 348px; height: 1px; padding-top: 112px; margin-left: 1301px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 36px; font-family: Roboto; color: #4285F4; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font style="font-size: 36px ; font-style: normal ; font-weight: 400 ; letter-spacing: normal ; text-align: right ; text-indent: 0px ; text-transform: none ; word-spacing: 0px">Visualize </font><span style="font-size: 36px ; font-style: normal ; font-weight: 400 ; letter-spacing: normal ; text-align: right ; text-indent: 0px ; text-transform: none ; word-spacing: 0px ; float: none ; display: inline">traces</span></div></div></div></foreignObject><text x="1475" y="148" fill="#4285F4" font-family="Roboto" font-size="36px" text-anchor="middle">Visualize traces</text></switch></g><a target="_top" xlink:href="/docs/#trace-visualization"><rect x="1325" y="168.75" width="300" height="581.25" fill="#aecbfa" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 298px; height: 1px; padding-top: 196px; margin-left: 1326px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 28px; font-family: Roboto; color: #1A73E8; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font style="font-size: 36px">Perfetto UI<br /></font><span style="font-size: 20px">HTML / JS</span></div></div></div></foreignObject><text x="1475" y="224" fill="#1A73E8" font-family="Roboto" font-size="28px" text-anchor="middle">Perfetto UI...</text></switch></g></a><ellipse cx="1475" cy="50" rx="50" ry="50" fill="#4285f4" stroke="none" pointer-events="all"/><image x="1442.5" y="17.5" width="64" height="64" xlink:href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0id2hpdGUiIHdpZHRoPSIxOHB4IiBoZWlnaHQ9IjE4cHgiPjxwYXRoIGQ9Ik0yMCA0SDRjLTEuMSAwLTIgLjktMiAydjEyYzAgMS4xLjkgMiAyIDJoMTZjMS4xIDAgMi0uOSAyLTJWNmMwLTEuMS0uOS0yLTItMnpNNSAxMmgyYy41NSAwIDEgLjQ1IDEgMXMtLjQ1IDEtMSAxSDVjLS41NSAwLTEtLjQ1LTEtMXMuNDUtMSAxLTF6bTggNkg1Yy0uNTUgMC0xLS40NS0xLTFzLjQ1LTEgMS0xaDhjLjU1IDAgMSAuNDUgMSAxcy0uNDUgMS0xIDF6bTYgMGgtMmMtLjU1IDAtMS0uNDUtMS0xcy40NS0xIDEtMWgyYy41NSAwIDEgLjQ1IDEgMXMtLjQ1IDEtMSAxem0wLTRoLThjLS41NSAwLTEtLjQ1LTEtMXMuNDUtMSAxLTFoOGMuNTUgMCAxIC40NSAxIDFzLS40NSAxLTEgMXoiLz48L3N2Zz4=" preserveAspectRatio="none"/><rect x="965.63" y="325" width="268.75" height="100" fill="#ffcc80" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 267px; height: 1px; padding-top: 375px; margin-left: 967px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 28px; font-family: Roboto; color: #ac1900; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Trace importers<br /><span style="font-size: 20px">Protobuf, JSON, systrace</span></div></div></div></foreignObject><text x="1100" y="383" fill="#ac1900" font-family="Roboto" font-size="28px" text-anchor="middle">Trace importers...</text></switch></g><a target="_top" xlink:href="/docs/analysis/metrics"><rect x="965.63" y="625" width="268.75" height="100" fill="#ffcc80" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 267px; height: 1px; padding-top: 675px; margin-left: 967px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 28px; font-family: Roboto; color: #ac1900; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font style="font-size: 28px">Trace-based metrics<br /></font><font style="font-size: 20px">JSON / Protobuf / CSV</font></div></div></div></foreignObject><text x="1100" y="683" fill="#ac1900" font-family="Roboto" font-size="28px" text-anchor="middle">Trace-based metrics...</text></switch></g></a><a target="_top" xlink:href="/docs/analysis/sql-tables"><rect x="965.63" y="475" width="268.75" height="100" fill="#ffcc80" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 267px; height: 1px; padding-top: 525px; margin-left: 967px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 28px; font-family: Roboto; color: #ac1900; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">SQL query engine<br /><font style="font-size: 20px">Based on SQLite</font></div></div></div></foreignObject><text x="1100" y="533" fill="#ac1900" font-family="Roboto" font-size="28px" text-anchor="middle">SQL query engine...</text></switch></g></a><rect x="325" y="550" width="250" height="75" fill="#aed581" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 248px; height: 1px; padding-top: 588px; margin-left: 326px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 24px; font-family: Roboto; color: #1b5e20; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font style="font-size: 24px">Tracing service<br /><span style="font-size: 16px">Mojo</span><br /></font></div></div></div></foreignObject><text x="450" y="595" fill="#1b5e20" font-family="Roboto" font-size="24px" text-anchor="middle">Tracing service...</text></switch></g><rect x="325" y="225" width="250" height="200" fill="#dcedc8" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 248px; height: 1px; padding-top: 325px; margin-left: 326px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 24px; font-family: Roboto; color: #1b5e20; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font style="font-size: 24px">Chrome-specific<br />data-sources</font></div></div></div></foreignObject><text x="450" y="332" fill="#1b5e20" font-family="Roboto" font-size="24px" text-anchor="middle">Chrome-specific...</text></switch></g><a target="_top" xlink:href="/docs/instrumentation/tracing-sdk#in-process-mode"><rect x="625" y="550" width="250" height="75" fill="#aed581" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 248px; height: 1px; padding-top: 588px; margin-left: 626px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 24px; font-family: Roboto; color: #1b5e20; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font style="font-size: 24px">In-process<br />service thread</font></div></div></div></foreignObject><text x="750" y="595" fill="#1b5e20" font-family="Roboto" font-size="24px" text-anchor="middle">In-process...</text></switch></g></a><a target="_top" xlink:href="/docs/concepts/service-model"><rect x="25" y="550" width="250" height="75" fill="#aed581" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 248px; height: 1px; padding-top: 588px; margin-left: 26px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 24px; font-family: Roboto; color: #1b5e20; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Tracing daemon<br /><font style="font-size: 16px">UNIX socket</font></div></div></div></foreignObject><text x="150" y="595" fill="#1b5e20" font-family="Roboto" font-size="24px" text-anchor="middle">Tracing daemon...</text></switch></g></a><path d="M 300 150 L 296.7 626.4" fill="none" stroke="#8bc34a" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 600 149.3 L 596.7 625.7" fill="none" stroke="#8bc34a" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><a target="_top" xlink:href="/docs/instrumentation/track-events"><rect x="325" y="450" width="550" height="75" fill="#dcedc8" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 548px; height: 1px; padding-top: 488px; margin-left: 326px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 24px; font-family: Roboto; color: #1b5e20; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font>Track event library<br /><font style="font-size: 20px">TRACE_EVENT(...)</font><br /></font></div></div></div></foreignObject><text x="600" y="495" fill="#1b5e20" font-family="Roboto" font-size="24px" text-anchor="middle">Track event library...</text></switch></g></a><rect x="625" y="225" width="250" height="200" fill="#dcedc8" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 248px; height: 1px; padding-top: 325px; margin-left: 626px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 24px; font-family: Roboto; color: #1b5e20; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font style="font-size: 24px">App-specific<br />data-sources</font></div></div></div></foreignObject><text x="750" y="332" fill="#1b5e20" font-family="Roboto" font-size="24px" text-anchor="middle">App-specific...</text></switch></g><rect x="1350" y="325" width="250" height="103.12" fill="#669df6" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 248px; height: 1px; padding-top: 377px; margin-left: 1351px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 28px; font-family: Roboto; color: #ffffff; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Trace Processor<br /><font style="font-size: 20px">Web Assembly</font></div></div></div></foreignObject><text x="1475" y="385" fill="#ffffff" font-family="Roboto" font-size="28px" text-anchor="middle">Trace Processor...</text></switch></g><rect x="1350" y="475" width="250" height="103.12" fill="#669df6" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 248px; height: 1px; padding-top: 527px; margin-left: 1351px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 28px; font-family: Roboto; color: #ffffff; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font>ADB over WebUSB<br /></font><font style="font-size: 20px">For Android</font></div></div></div></foreignObject><text x="1475" y="535" fill="#ffffff" font-family="Roboto" font-size="28px" text-anchor="middle">ADB over WebUSB...</text></switch></g><rect x="1350" y="625" width="250" height="103.12" fill="#669df6" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 248px; height: 1px; padding-top: 677px; margin-left: 1351px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 28px; font-family: Roboto; color: #ffffff; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font>Works offline<br /></font><font style="font-size: 20px">After first visit</font></div></div></div></foreignObject><text x="1475" y="685" fill="#ffffff" font-family="Roboto" font-size="28px" text-anchor="middle">Works offline...</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://desk.draw.io/support/solutions/articles/16000042487" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Viewer does not support full SVG 1.1</text></a></switch></svg>
\ No newline at end of file
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1652px" height="776px" viewBox="-0.5 -0.5 1652 776" content="&lt;mxfile host=&quot;app.diagrams.net&quot; modified=&quot;2020-05-22T22:41:34.812Z&quot; agent=&quot;5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36&quot; etag=&quot;QckB1rB-GYIfxBJ2Ru_L&quot; version=&quot;13.1.3&quot; type=&quot;device&quot;&gt;&lt;diagram id=&quot;7NN0wUOKmaAmGsXKK3Xs&quot; name=&quot;Page-1&quot;&gt;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&lt;/diagram&gt;&lt;/mxfile&gt;"><defs/><g><rect x="0" y="75" width="900" height="700" fill="#f8fbf3" stroke="none" pointer-events="all"/><g fill="#388E3C" font-family="sans-serif" text-anchor="middle" font-size="36px"><text x="449.5" y="134.5">Record traces</text></g><rect x="600" y="150" width="300" height="600" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 298px; height: 1px; padding-top: 157px; margin-left: 601px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 32px; font-family: sans-serif; color: #7cb342; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font face="sans-serif" style="font-size: 32px"><span style="font-size: 32px">In-app tracing</span></font></div></div></div></foreignObject><text x="750" y="189" fill="#7cb342" font-family="sans-serif" font-size="32px" text-anchor="middle">In-app tracing</text></switch></g><ellipse cx="450" cy="50" rx="50" ry="50" fill="#4caf50" stroke="none" pointer-events="all"/><image x="417.5" y="17.5" width="64" height="64" xlink:href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0id2hpdGUiIHdpZHRoPSIxOHB4IiBoZWlnaHQ9IjE4cHgiPjxwYXRoIGQ9Ik0wIDBoMjR2MjRIMFYweiIgZmlsbD0ibm9uZSIvPjxwYXRoIGQ9Ik0xOCA0djFoLTJWNGMwLS41NS0uNDUtMS0xLTFIOWMtLjU1IDAtMSAuNDUtMSAxdjFINlY0YzAtLjU1LS40NS0xLTEtMXMtMSAuNDUtMSAxdjE2YzAgLjU1LjQ1IDEgMSAxczEtLjQ1IDEtMXYtMWgydjFjMCAuNTUuNDUgMSAxIDFoNmMuNTUgMCAxLS40NSAxLTF2LTFoMnYxYzAgLjU1LjQ1IDEgMSAxczEtLjQ1IDEtMVY0YzAtLjU1LS40NS0xLTEtMXMtMSAuNDUtMSAxek04IDE3SDZ2LTJoMnYyem0wLTRINnYtMmgydjJ6bTAtNEg2VjdoMnYyem0xMCA4aC0ydi0yaDJ2MnptMC00aC0ydi0yaDJ2MnptMC00aC0yVjdoMnYyeiIvPjwvc3ZnPg==" preserveAspectRatio="none" transform="rotate(90,450,50)"/><rect x="0" y="150" width="300" height="500" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 298px; height: 1px; padding-top: 157px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 32px; font-family: sans-serif; color: #7cb342; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><span style="font-family: sans-serif ; font-size: 32px ; font-style: normal ; font-weight: 400 ; letter-spacing: normal ; text-indent: 0px ; text-transform: none ; word-spacing: 0px ; float: none ; display: inline">System </span><span style="font-family: sans-serif ; font-size: 32px ; font-style: normal ; font-weight: 400 ; letter-spacing: normal ; text-indent: 0px ; text-transform: none ; word-spacing: 0px ; float: none ; display: inline">tracing</span></div></div></div></foreignObject><text x="150" y="189" fill="#7cb342" font-family="sans-serif" font-size="32px" text-anchor="middle">System tracing</text></switch></g><rect x="300" y="150" width="300" height="600" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 298px; height: 1px; padding-top: 157px; margin-left: 301px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 32px; font-family: sans-serif; color: #7cb342; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font face="sans-serif" style="font-size: 32px"><span style="font-size: 32px">Chrome tracing</span></font></div></div></div></foreignObject><text x="450" y="189" fill="#7cb342" font-family="sans-serif" font-size="32px" text-anchor="middle">Chrome tracing</text></switch></g><rect x="25" y="225" width="250" height="300" fill="#dcedc8" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 248px; height: 1px; padding-top: 522px; margin-left: 26px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 28px; font-family: sans-serif; color: #1b5e20; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><span style="font-size: 28px">Data sources<br style="font-size: 28px" /></span><font style="font-size: 20px">Linux/Android</font></div></div></div></foreignObject><text x="150" y="522" fill="#1b5e20" font-family="sans-serif" font-size="28px" text-anchor="middle">Data sources...</text></switch></g><a target="_top" xlink:href="/docs/data-sources/cpu-scheduling"><rect x="50" y="250" width="200" height="50" fill="#c5e1a5" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 198px; height: 1px; padding-top: 275px; margin-left: 51px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 25px; font-family: sans-serif; color: #1b5e20; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><span style="font-size: 25px">Linux ftrace</span></div></div></div></foreignObject><text x="150" y="283" fill="#1b5e20" font-family="sans-serif" font-size="25px" text-anchor="middle">Linux ftrace</text></switch></g></a><a target="_top" xlink:href="/docs/data-sources/memory-counters"><rect x="50" y="325" width="200" height="50" fill="#c5e1a5" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 198px; height: 1px; padding-top: 350px; margin-left: 51px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 25px; font-family: sans-serif; color: #1b5e20; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font style="font-size: 25px">/proc </font><span style="font-size: 25px">pollers</span></div></div></div></foreignObject><text x="150" y="358" fill="#1b5e20" font-family="sans-serif" font-size="25px" text-anchor="middle">/proc pollers</text></switch></g></a><a target="_top" xlink:href="/docs/data-sources/native-heap-profiler"><rect x="50" y="396.88" width="200" height="50" fill="#c5e1a5" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 198px; height: 1px; padding-top: 422px; margin-left: 51px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 25px; font-family: sans-serif; color: #1b5e20; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><span style="font-size: 25px">Heap profilers</span></div></div></div></foreignObject><text x="150" y="429" fill="#1b5e20" font-family="sans-serif" font-size="25px" text-anchor="middle">Heap profilers</text></switch></g></a><a target="_top" xlink:href="/docs/instrumentation/tracing-sdk"><rect x="25" y="650" width="850" height="100" fill="#dcedc8" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 848px; height: 1px; padding-top: 700px; margin-left: 26px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 32px; font-family: sans-serif; color: #1b5e20; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font style="font-size: 36px">Tracing C++ Library<br /></font><div><font style="font-size: 20px">Android / Linux / MacOS / Windows</font></div></div></div></div></foreignObject><text x="450" y="710" fill="#1b5e20" font-family="sans-serif" font-size="32px" text-anchor="middle">Tracing C++ Library...</text></switch></g></a><rect x="925" y="75" width="350" height="700" fill="#fff3e0" stroke="none" pointer-events="all"/><g fill="#FF9800" font-family="sans-serif" text-anchor="middle" font-size="36px"><text x="1099.5" y="134.5">Analyze traces</text></g><ellipse cx="1100" cy="50" rx="50" ry="50" fill="#ff9800" stroke="none" pointer-events="all"/><image x="1067.5" y="17.5" width="64" height="64" xlink:href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0id2hpdGUiIHdpZHRoPSIxOHB4IiBoZWlnaHQ9IjE4cHgiPjxwYXRoIGQ9Ik0wIDBoMjR2MjRIMFYweiIgZmlsbD0ibm9uZSIvPjxwYXRoIGQ9Ik0xOSAzSDVjLTEuMSAwLTIgLjktMiAydjE0YzAgMS4xLjkgMiAyIDJoMTRjMS4xIDAgMi0uOSAyLTJWNWMwLTEuMS0uOS0yLTItMnpNOCAxN2MtLjU1IDAtMS0uNDUtMS0xdi01YzAtLjU1LjQ1LTEgMS0xczEgLjQ1IDEgMXY1YzAgLjU1LS40NSAxLTEgMXptNCAwYy0uNTUgMC0xLS40NS0xLTFWOGMwLS41NS40NS0xIDEtMXMxIC40NSAxIDF2OGMwIC41NS0uNDUgMS0xIDF6bTQgMGMtLjU1IDAtMS0uNDUtMS0xdi0yYzAtLjU1LjQ1LTEgMS0xczEgLjQ1IDEgMXYyYzAgLjU1LS40NSAxLTEgMXoiLz48L3N2Zz4=" preserveAspectRatio="none"/><a target="_top" xlink:href="/docs/analysis/trace-processor"><rect x="943.75" y="168.75" width="312.5" height="581.25" fill="#ffe0b2" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 311px; height: 1px; padding-top: 196px; margin-left: 945px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 32px; font-family: sans-serif; color: #EA8600; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><span style="font-size: 36px">Trace Processor<br /></span><span style="font-size: 20px">Android / Linux / MacOS / Win</span></div></div></div></foreignObject><text x="1100" y="228" fill="#EA8600" font-family="sans-serif" font-size="32px" text-anchor="middle">Trace Processor...</text></switch></g></a><rect x="1300" y="75" width="350" height="700" fill="#e8f0fe" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 348px; height: 1px; padding-top: 112px; margin-left: 1301px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 36px; font-family: sans-serif; color: #4285F4; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font style="font-size: 36px ; font-style: normal ; font-weight: 400 ; letter-spacing: normal ; text-align: right ; text-indent: 0px ; text-transform: none ; word-spacing: 0px">Visualize </font><span style="font-size: 36px ; font-style: normal ; font-weight: 400 ; letter-spacing: normal ; text-align: right ; text-indent: 0px ; text-transform: none ; word-spacing: 0px ; float: none ; display: inline">traces</span></div></div></div></foreignObject><text x="1475" y="148" fill="#4285F4" font-family="sans-serif" font-size="36px" text-anchor="middle">Visualize traces</text></switch></g><a target="_top" xlink:href="/docs/#trace-visualization"><rect x="1325" y="168.75" width="300" height="581.25" fill="#aecbfa" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 298px; height: 1px; padding-top: 196px; margin-left: 1326px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 28px; font-family: sans-serif; color: #1A73E8; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font style="font-size: 36px">Perfetto UI<br /></font><span style="font-size: 20px">HTML / JS</span></div></div></div></foreignObject><text x="1475" y="224" fill="#1A73E8" font-family="sans-serif" font-size="28px" text-anchor="middle">Perfetto UI...</text></switch></g></a><ellipse cx="1475" cy="50" rx="50" ry="50" fill="#4285f4" stroke="none" pointer-events="all"/><image x="1442.5" y="17.5" width="64" height="64" xlink:href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0id2hpdGUiIHdpZHRoPSIxOHB4IiBoZWlnaHQ9IjE4cHgiPjxwYXRoIGQ9Ik0yMCA0SDRjLTEuMSAwLTIgLjktMiAydjEyYzAgMS4xLjkgMiAyIDJoMTZjMS4xIDAgMi0uOSAyLTJWNmMwLTEuMS0uOS0yLTItMnpNNSAxMmgyYy41NSAwIDEgLjQ1IDEgMXMtLjQ1IDEtMSAxSDVjLS41NSAwLTEtLjQ1LTEtMXMuNDUtMSAxLTF6bTggNkg1Yy0uNTUgMC0xLS40NS0xLTFzLjQ1LTEgMS0xaDhjLjU1IDAgMSAuNDUgMSAxcy0uNDUgMS0xIDF6bTYgMGgtMmMtLjU1IDAtMS0uNDUtMS0xcy40NS0xIDEtMWgyYy41NSAwIDEgLjQ1IDEgMXMtLjQ1IDEtMSAxem0wLTRoLThjLS41NSAwLTEtLjQ1LTEtMXMuNDUtMSAxLTFoOGMuNTUgMCAxIC40NSAxIDFzLS40NSAxLTEgMXoiLz48L3N2Zz4=" preserveAspectRatio="none"/><rect x="965.63" y="325" width="268.75" height="100" fill="#ffcc80" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 267px; height: 1px; padding-top: 375px; margin-left: 967px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 28px; font-family: sans-serif; color: #ac1900; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Trace importers<br /><span style="font-size: 20px">Protobuf, JSON, systrace</span></div></div></div></foreignObject><text x="1100" y="383" fill="#ac1900" font-family="sans-serif" font-size="28px" text-anchor="middle">Trace importers...</text></switch></g><a target="_top" xlink:href="/docs/analysis/metrics"><rect x="965.63" y="625" width="268.75" height="100" fill="#ffcc80" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 267px; height: 1px; padding-top: 675px; margin-left: 967px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 28px; font-family: sans-serif; color: #ac1900; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font style="font-size: 28px">Trace-based metrics<br /></font><font style="font-size: 20px">JSON / Protobuf / CSV</font></div></div></div></foreignObject><text x="1100" y="683" fill="#ac1900" font-family="sans-serif" font-size="28px" text-anchor="middle">Trace-based metrics...</text></switch></g></a><a target="_top" xlink:href="/docs/analysis/sql-tables"><rect x="965.63" y="475" width="268.75" height="100" fill="#ffcc80" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 267px; height: 1px; padding-top: 525px; margin-left: 967px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 28px; font-family: sans-serif; color: #ac1900; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">SQL query engine<br /><font style="font-size: 20px">Based on SQLite</font></div></div></div></foreignObject><text x="1100" y="533" fill="#ac1900" font-family="sans-serif" font-size="28px" text-anchor="middle">SQL query engine...</text></switch></g></a><rect x="325" y="550" width="250" height="75" fill="#aed581" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 248px; height: 1px; padding-top: 588px; margin-left: 326px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 24px; font-family: sans-serif; color: #1b5e20; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font style="font-size: 24px">Tracing service<br /><span style="font-size: 16px">Mojo</span><br /></font></div></div></div></foreignObject><text x="450" y="595" fill="#1b5e20" font-family="sans-serif" font-size="24px" text-anchor="middle">Tracing service...</text></switch></g><rect x="325" y="225" width="250" height="200" fill="#dcedc8" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 248px; height: 1px; padding-top: 325px; margin-left: 326px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 24px; font-family: sans-serif; color: #1b5e20; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font style="font-size: 24px">Chrome-specific<br />data-sources</font></div></div></div></foreignObject><text x="450" y="332" fill="#1b5e20" font-family="sans-serif" font-size="24px" text-anchor="middle">Chrome-specific...</text></switch></g><a target="_top" xlink:href="/docs/instrumentation/tracing-sdk#in-process-mode"><rect x="625" y="550" width="250" height="75" fill="#aed581" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 248px; height: 1px; padding-top: 588px; margin-left: 626px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 24px; font-family: sans-serif; color: #1b5e20; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font style="font-size: 24px">In-process<br />service thread</font></div></div></div></foreignObject><text x="750" y="595" fill="#1b5e20" font-family="sans-serif" font-size="24px" text-anchor="middle">In-process...</text></switch></g></a><a target="_top" xlink:href="/docs/concepts/service-model"><rect x="25" y="550" width="250" height="75" fill="#aed581" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 248px; height: 1px; padding-top: 588px; margin-left: 26px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 24px; font-family: sans-serif; color: #1b5e20; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Tracing daemon<br /><font style="font-size: 16px">UNIX socket</font></div></div></div></foreignObject><text x="150" y="595" fill="#1b5e20" font-family="sans-serif" font-size="24px" text-anchor="middle">Tracing daemon...</text></switch></g></a><path d="M 300 150 L 296.7 626.4" fill="none" stroke="#8bc34a" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 600 149.3 L 596.7 625.7" fill="none" stroke="#8bc34a" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><a target="_top" xlink:href="/docs/instrumentation/track-events"><rect x="325" y="450" width="550" height="75" fill="#dcedc8" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 548px; height: 1px; padding-top: 488px; margin-left: 326px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 24px; font-family: sans-serif; color: #1b5e20; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font>Track event library<br /><font style="font-size: 20px">TRACE_EVENT(...)</font><br /></font></div></div></div></foreignObject><text x="600" y="495" fill="#1b5e20" font-family="sans-serif" font-size="24px" text-anchor="middle">Track event library...</text></switch></g></a><rect x="625" y="225" width="250" height="200" fill="#dcedc8" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 248px; height: 1px; padding-top: 325px; margin-left: 626px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 24px; font-family: sans-serif; color: #1b5e20; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font style="font-size: 24px">App-specific<br />data-sources</font></div></div></div></foreignObject><text x="750" y="332" fill="#1b5e20" font-family="sans-serif" font-size="24px" text-anchor="middle">App-specific...</text></switch></g><rect x="1350" y="325" width="250" height="103.12" fill="#669df6" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 248px; height: 1px; padding-top: 377px; margin-left: 1351px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 28px; font-family: sans-serif; color: #ffffff; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Trace Processor<br /><font style="font-size: 20px">Web Assembly</font></div></div></div></foreignObject><text x="1475" y="385" fill="#ffffff" font-family="sans-serif" font-size="28px" text-anchor="middle">Trace Processor...</text></switch></g><rect x="1350" y="475" width="250" height="103.12" fill="#669df6" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 248px; height: 1px; padding-top: 527px; margin-left: 1351px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 28px; font-family: sans-serif; color: #ffffff; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font>ADB over WebUSB<br /></font><font style="font-size: 20px">For Android</font></div></div></div></foreignObject><text x="1475" y="535" fill="#ffffff" font-family="sans-serif" font-size="28px" text-anchor="middle">ADB over WebUSB...</text></switch></g><rect x="1350" y="625" width="250" height="103.12" fill="#669df6" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 248px; height: 1px; padding-top: 677px; margin-left: 1351px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 28px; font-family: sans-serif; color: #ffffff; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font>Works offline<br /></font><font style="font-size: 20px">After first visit</font></div></div></div></foreignObject><text x="1475" y="685" fill="#ffffff" font-family="sans-serif" font-size="28px" text-anchor="middle">Works offline...</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://desk.draw.io/support/solutions/articles/16000042487" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Viewer does not support full SVG 1.1</text></a></switch></svg>
diff --git a/infra/perfetto.dev/redirect/app.yaml b/docs/run-dev-server
old mode 100644
new mode 100755
similarity index 76%
rename from infra/perfetto.dev/redirect/app.yaml
rename to docs/run-dev-server
index ecd8a58..f5bc3c4
--- a/infra/perfetto.dev/redirect/app.yaml
+++ b/docs/run-dev-server
@@ -1,4 +1,5 @@
-# Copyright (C) 2020 The Android Open Source Project
+#!/bin/bash
+# Copyright (C) 2021 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -12,9 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-runtime: python37
-service: redirect
-handlers:
-- url: /.*
-  script: auto
-
+set -eu
+CUR_DIR="$(cd -P ${BASH_SOURCE[0]%/*}; pwd)"
+$CUR_DIR/../infra/perfetto.dev/run-dev-server
diff --git a/infra/perfetto.dev/.clang-format b/infra/perfetto.dev/.clang-format
new file mode 100644
index 0000000..265b562
--- /dev/null
+++ b/infra/perfetto.dev/.clang-format
@@ -0,0 +1,5 @@
+Language:         JavaScript
+BasedOnStyle:     Google
+ColumnLimit:      80
+BinPackArguments: false
+JavaScriptWrapImports: true
\ No newline at end of file
diff --git a/infra/perfetto.dev/.gcloudignore b/infra/perfetto.dev/.gcloudignore
deleted file mode 100644
index 2382779..0000000
--- a/infra/perfetto.dev/.gcloudignore
+++ /dev/null
@@ -1,12 +0,0 @@
-.firebase/
-.firebaserc
-.gcloudignore
-.git
-.gitignore
-BUILD.gn
-deploy
-firebase-debug.log
-node_modules/
-package-lock.json
-package.json
-run-dev-server
\ No newline at end of file
diff --git a/infra/perfetto.dev/BUILD.gn b/infra/perfetto.dev/BUILD.gn
deleted file mode 100644
index d3a5dc3..0000000
--- a/infra/perfetto.dev/BUILD.gn
+++ /dev/null
@@ -1,358 +0,0 @@
-# Copyright (C) 2020 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import("../../gn/perfetto.gni")
-
-# Prevent that this file is accidentally included in embedder builds.
-assert(enable_perfetto_ui)
-
-dist_dir = "$root_build_dir/site"
-gen_dir = "$target_out_dir/gen"
-nodejs_bin = rebase_path("//tools/node", root_build_dir)
-
-# +----------------------------------------------------------------------------+
-# | The outer "ui" target to just ninja -C out/xxx ui                          |
-# +----------------------------------------------------------------------------+
-
-group("site") {
-  deps = [
-    ":assets_dist",
-    ":index_dist",
-    ":markdown",
-    ":scss",
-  ]
-}
-
-# +----------------------------------------------------------------------------+
-# | Runs NodeJS using the hermetic node toolchain.                             |
-# +----------------------------------------------------------------------------+
-template("node_bin") {
-  action(target_name) {
-    forward_variables_from(invoker,
-                           [
-                             "inputs",
-                             "outputs",
-                             "depfile",
-                           ])
-    deps = [ ":node_modules" ]
-    if (defined(invoker.deps)) {
-      deps += invoker.deps
-    }
-    script = "../../gn/standalone/build_tool_wrapper.py"
-    _node_cmd = invoker.node_cmd
-    args = []
-    if (defined(invoker.suppress_stdout) && invoker.suppress_stdout) {
-      args += [ "--suppress_stdout" ]
-    }
-    if (defined(invoker.suppress_stderr) && invoker.suppress_stderr) {
-      args += [ "--suppress_stderr" ]
-    }
-    args += [
-              "--path=$nodejs_bin",
-              "node",
-              rebase_path("node_modules/.bin/$_node_cmd", root_build_dir),
-            ] + invoker.args
-  }
-}
-
-# +----------------------------------------------------------------------------+
-# | Installs the node modules secified in package.json                         |
-# +----------------------------------------------------------------------------+
-action("node_modules") {
-  script = "../../gn/standalone/build_tool_wrapper.py"
-  stamp_file = "$dist_dir/.$target_name.stamp"
-  cur_dir = rebase_path(".", root_build_dir)
-  args = [
-    "--stamp",
-    rebase_path(stamp_file, root_build_dir),
-    "--chdir=$cur_dir",
-    "--path=$nodejs_bin",
-    "npm",
-    "install",
-  ]
-  inputs = [
-    "package.json",
-    "package-lock.json",
-  ]
-  outputs = [ stamp_file ]
-}
-
-copy("assets_dist") {
-  sources = [
-    "node_modules/highlight.js/styles/tomorrow-night.css",
-    "node_modules/mermaid/dist/mermaid.min.js",
-    "src/assets/analysis.png",
-    "src/assets/app_tracing.png",
-    "src/assets/brand.png",
-    "src/assets/favicon.png",
-    "src/assets/home.png",
-    "src/assets/script.js",
-    "src/assets/sprite.png",
-    "src/assets/sys_profiling.png",
-    "src/assets/ui.png",
-  ]
-  outputs = [ "$dist_dir/assets/{{source_file_part}}" ]
-}
-
-node_bin("scss") {
-  inputs = [ "src/assets/style.scss" ]
-  outputs = [ "$dist_dir/assets/style.css" ]
-  node_cmd = "node-sass"
-  args = [
-    "--quiet",
-    rebase_path(inputs[0], root_build_dir),
-    rebase_path(outputs[0], root_build_dir),
-  ]
-}
-
-# +----------------------------------------------------------------------------+
-# | Markdown generation                                                        |
-# +----------------------------------------------------------------------------+
-
-html_templates = [
-  "src/template_header.html",
-  "src/template_footer.html",
-  "src/template_index.html",
-  "src/template_markdown.html",
-]
-
-# Renderers a markdown file into a HTML.
-# Args:
-#  markdown:        [in]  The source markdown file.
-#  html_template:   [in]  HTML template (optional).
-#  out_html:        [out] The generated HTML.
-template("md_to_html") {
-  action(target_name) {
-    js_src = "src/markdown_render.js"
-    script = "../../gn/standalone/build_tool_wrapper.py"
-    outputs = [ invoker.out_html ]
-    inputs = [ js_src ] + html_templates
-    args = [
-      "--path=$nodejs_bin",
-      "node",
-      rebase_path(js_src, root_build_dir),
-      "--odir",
-      rebase_path(dist_dir, root_build_dir),
-      "-o",
-      rebase_path(outputs[0], root_build_dir),
-    ]
-    if (defined(invoker.html_template)) {
-      args += [
-        "-t",
-        invoker.html_template,
-      ]
-      inputs += [ invoker.html_template ]
-    }
-    if (defined(invoker.markdown)) {
-      args += [
-        "-i",
-        rebase_path(invoker.markdown, root_build_dir),
-      ]
-      inputs += [ invoker.markdown ]
-    }
-    if (defined(invoker.deps)) {
-      deps = invoker.deps
-    }
-  }
-}
-
-all_proto_deps = "$target_out_dir/proto.deps"
-exec_script("../../gn/standalone/glob.py",
-            [
-              "--root=" + rebase_path("../../protos", root_build_dir),
-              "--filter=*.proto",
-              "--output=" + rebase_path(all_proto_deps),
-            ])
-
-# Generates a .md file from a .proto.
-# Args:
-#  proto_src: [in]
-#  proto_root_type: [in]
-#  markdown_out: [in]
-template("gen_proto_reference_md") {
-  action(target_name) {
-    js_src = "src/gen_proto_reference.js"
-    script = "../../gn/standalone/build_tool_wrapper.py"
-    inputs = [
-      invoker.proto_src,
-      js_src,
-    ]
-    inputs += read_file(all_proto_deps, "list lines")
-    outputs = [ invoker.markdown_out ]
-    args = [
-      "--path=$nodejs_bin",
-      "node",
-      rebase_path(js_src, root_build_dir),
-      "-o",
-      rebase_path(invoker.markdown_out, root_build_dir),
-      "-i",
-      rebase_path(invoker.proto_src, root_build_dir),
-      "-p",
-      invoker.proto_root_type,
-    ]
-  }
-}
-
-# +----------------------------------------------------------------------------+
-# | /reference/ auto-generated docs                                            |
-# +----------------------------------------------------------------------------+
-
-# Generates a .html from a proto (proto -> md -> html).
-template("gen_proto_reference_html") {
-  intermediate_md = "$target_out_dir/$target_name.md"
-  gen_proto_reference_md("${target_name}_md") {
-    proto_src = invoker.proto_src
-    proto_root_type = invoker.proto_root_type
-    markdown_out = intermediate_md
-  }
-  md_to_html(target_name) {
-    deps = [
-      ":${target_name}_md",
-      ":navmap",
-    ]
-    markdown = intermediate_md
-    out_html = invoker.out_html
-    html_template = rebase_path("src/template_markdown.html", root_build_dir)
-  }
-}
-
-gen_proto_reference_html("trace_config_reference") {
-  proto_src = "../../protos/perfetto/config/trace_config.proto"
-  proto_root_type = "perfetto.protos.TraceConfig"
-  out_html = "$dist_dir/docs/reference/trace-config-proto"
-}
-
-gen_proto_reference_html("trace_packet_reference") {
-  proto_src = "../../protos/perfetto/trace/trace_packet.proto"
-  proto_root_type = "perfetto.protos.TracePacket"
-  out_html = "$dist_dir/docs/reference/trace-packet-proto"
-}
-
-# Generates the HTML for the sidebar.
-md_to_html("navmap") {
-  markdown = "../../docs/toc.md"
-  out_html = "$dist_dir/docs/_nav.html"
-}
-
-# Generates the root index.html.
-md_to_html("index_dist") {
-  html_template = rebase_path("src/template_index.html", root_build_dir)
-  out_html = "$dist_dir/index.html"
-}
-
-tp_tables_list = "$target_out_dir/tables.deps"
-exec_script("../../gn/standalone/glob.py",
-            [
-              "--root=" + rebase_path("../../src/trace_processor/tables",
-                                      root_build_dir),
-              "--filter=*.h",
-              "--output=" + rebase_path(tp_tables_list),
-            ])
-
-action("sql_tables_reference_md") {
-  js_src = "src/gen_sql_tables_reference.js"
-  script = "../../gn/standalone/build_tool_wrapper.py"
-  tp_table_hdrs = read_file(tp_tables_list, "list lines")
-  inputs = tp_table_hdrs + [ js_src ]
-  outputs = [ "$target_out_dir/sql-tables.autogen" ]
-  args = [
-    "--path=$nodejs_bin",
-    "node",
-    rebase_path(js_src, root_build_dir),
-    "-o",
-    rebase_path(outputs[0], root_build_dir),
-  ]
-  foreach(table_hdr, tp_table_hdrs) {
-    args += [
-      "-i",
-      table_hdr,
-    ]
-  }
-}
-
-md_to_html("sql_tables_reference") {
-  deps = [
-    ":navmap",
-    ":sql_tables_reference_md",
-  ]
-  markdown = "$target_out_dir/sql-tables.autogen"
-  out_html = "$dist_dir/docs/analysis/sql-tables"
-  html_template = rebase_path("src/template_markdown.html", root_build_dir)
-}
-
-action("stats_reference_md") {
-  js_src = "src/gen_stats_reference.js"
-  script = "../../gn/standalone/build_tool_wrapper.py"
-  input = "../../src/trace_processor/storage/stats.h"
-  inputs = [
-    input,
-    js_src,
-  ]
-  outputs = [ "$target_out_dir/sql-stats.autogen" ]
-  args = [
-    "--path=$nodejs_bin",
-    "node",
-    rebase_path(js_src, root_build_dir),
-    "-o",
-    rebase_path(outputs[0], root_build_dir),
-    "-i",
-    "../../src/trace_processor/storage/stats.h",
-  ]
-}
-
-md_to_html("stats_reference") {
-  deps = [
-    ":navmap",
-    ":stats_reference_md",
-  ]
-  markdown = "$target_out_dir/sql-stats.autogen"
-  out_html = "$dist_dir/docs/analysis/sql-stats"
-  html_template = rebase_path("src/template_markdown.html", root_build_dir)
-}
-
-# Generates a HTML file for each //docs/**/*.md.
-md_file_list = "$target_out_dir/docs.deps"
-exec_script("../../gn/standalone/glob.py",
-            [
-              "--root=" + rebase_path("../../docs", root_build_dir),
-              "--filter=*.md",
-              "--output=" + rebase_path(md_file_list),
-            ],
-            "",
-            [ "../../docs/toc.md" ])
-all_md_targets = []
-foreach(source, read_file(md_file_list, "list lines")) {
-  target_name = "gen_$source"
-  all_md_targets += [ ":$target_name" ]
-  md_to_html(target_name) {
-    deps = [ ":navmap" ]
-    base_name = string_replace(rebase_path(source, "../../docs"), ".md", "")
-    if (base_name == "README") {
-      base_name = "index.html"
-    }
-    markdown = source
-    out_html = "$dist_dir/docs/$base_name"
-    html_template = rebase_path("src/template_markdown.html", root_build_dir)
-  }
-}
-
-group("markdown") {
-  deps = all_md_targets
-  deps += [
-    ":sql_tables_reference",
-    ":stats_reference",
-    ":trace_config_reference",
-    ":trace_packet_reference",
-  ]
-}
diff --git a/infra/perfetto.dev/app.yaml b/infra/perfetto.dev/app.yaml
deleted file mode 100644
index d20e18f..0000000
--- a/infra/perfetto.dev/app.yaml
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright (C) 2020 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-runtime: python37
-default_expiration: "5m"
-handlers:
-- url: /$
-  static_files: dist/index.html
-  upload: dist/index.html
-  secure: always
-  redirect_http_response_code: 301
-- url: /docs/?$
-  static_files: dist/docs/index.html
-  upload: dist/docs/index.html
-  mime_type: text/html
-  secure: always
-  redirect_http_response_code: 301
-- url: /docs/(.*\.svg)$
-  static_files: dist/docs/\1
-  mime_type: image/svg+xml
-  upload: dist/docs/.*\.svg$
-- url: /docs/(.*/[A-Za-z0-9-_]+)$
-  static_files: dist/docs/\1
-  mime_type: text/html
-  upload: dist/docs/.*/[A-Za-z0-9-_]+$
-  secure: always
-  redirect_http_response_code: 301
-- url: /assets/
-  static_dir: dist/assets
-  expiration: 60m
-- url: /
-  static_dir: dist/
-  secure: always
-  redirect_http_response_code: 301
diff --git a/infra/perfetto.dev/appengine/.gcloudignore b/infra/perfetto.dev/appengine/.gcloudignore
new file mode 100644
index 0000000..d671c50
--- /dev/null
+++ b/infra/perfetto.dev/appengine/.gcloudignore
@@ -0,0 +1,3 @@
+.gcloudignore
+.gitignore
+deploy
\ No newline at end of file
diff --git a/infra/perfetto.dev/appengine/README.md b/infra/perfetto.dev/appengine/README.md
new file mode 100644
index 0000000..3c2348a
--- /dev/null
+++ b/infra/perfetto.dev/appengine/README.md
@@ -0,0 +1,15 @@
+# www.perfetto.dev Cloud scripts
+
+The docs site follows the same architecture of ui.perfetto.dev.
+See [go/perfetto-ui-autopush](http://go/perfetto-ui-autopush) for docs.
+
+## /appengine : GAE <> GCS proxy
+
+The Google AppEngine instance that responds to www.perfetto.dev.
+It simply passes through the requests to the bucket gs://perfetto.dev .
+This should NOT be re-deployed when uploading new docs, as the actual
+artifacts live in GCS.
+
+We are using AppEngine for historical reasons, at some point this should
+be migrated to a Type 7 Google Cloud Load Balancer, which supports
+direct backing by a GCS bucket.
diff --git a/infra/perfetto.dev/appengine/app.yaml b/infra/perfetto.dev/appengine/app.yaml
new file mode 100644
index 0000000..1f4e65c
--- /dev/null
+++ b/infra/perfetto.dev/appengine/app.yaml
@@ -0,0 +1,5 @@
+runtime: python38
+instance_class: B1
+basic_scaling:
+  max_instances: 4
+  idle_timeout: 10m
diff --git a/infra/perfetto.dev/appengine/deploy b/infra/perfetto.dev/appengine/deploy
new file mode 100755
index 0000000..7cafa17
--- /dev/null
+++ b/infra/perfetto.dev/appengine/deploy
@@ -0,0 +1,49 @@
+#!/bin/bash
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This script deploys the AppEngine instance that acts as a proxy for the GCS
+# bucket gs://perfetto.dev. This does NOT need to be re-deployed when docs
+# change. See go/perfetto-ui-autopush for details.
+
+set -eu
+
+readonly CUR_DIR="$(cd -P ${BASH_SOURCE[0]%/*}; pwd)"
+
+cd $CUR_DIR
+
+VERSION=testing
+PROMOTE=--no-promote
+
+while [[ $# -gt 0 ]]; do
+  key="$1"
+  case $key in
+      --prod)
+      VERSION=prod
+      PROMOTE=--promote
+      shift
+      ;;
+      *)
+      echo "Usage: $0 [--prod]"
+      echo "    --prod      Deploy prod version"
+      echo "    -h|--help   Display this message"
+      exit 0
+      shift
+      ;;
+  esac
+done
+
+set -x
+gcloud app deploy app.yaml --project perfetto-site \
+    -v $VERSION $PROMOTE --stop-previous-version
diff --git a/infra/perfetto.dev/appengine/main.py b/infra/perfetto.dev/appengine/main.py
new file mode 100644
index 0000000..61e3fe1
--- /dev/null
+++ b/infra/perfetto.dev/appengine/main.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python3
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import flask
+import os
+
+from google.cloud import storage
+
+BUCKET_NAME = 'perfetto.dev'
+
+app = flask.Flask(__name__)
+bucket = None
+is_local_testing_instance = False
+
+
+@app.route('/_ah/<path:path>')
+def ignore_app_engine_lifecycle(path):
+  return flask.abort(404)
+
+
+# Serve the requests from the GCS bucket.
+@app.route('/', methods=['GET'])
+@app.route('/<path:path>', methods=['GET'])
+def main(path=''):
+  # Force redirect HTTP -> HTTPS.
+  if not flask.request.is_secure and not is_local_testing_instance:
+    https_url = flask.request.url.replace('http://', 'https://', 1)
+    return flask.redirect(https_url, code=301)
+  if flask.request.host == 'www.perfetto.dev':
+    return flask.redirect(
+        flask.request.url.replace('www.perfetto.dev', 'perfetto.dev'))
+  if flask.request.host == 'docs.perfetto.dev':
+    return flask.redirect('https://perfetto.dev/docs/')
+
+  path = '/' + path
+  path += 'index.html' if path.endswith('/') else ''
+  global bucket
+  if bucket is None:
+    bucket = storage.Client().get_bucket(BUCKET_NAME)
+  blob = bucket.get_blob(path[1:])
+  if blob is None:
+    return flask.abort(404)
+  data = blob.download_as_bytes()
+  resp = flask.Response(data)
+  resp.headers['Content-Type'] = blob.content_type
+  resp.headers['Content-Length'] = len(data)
+  resp.headers['Content-Encoding'] = blob.content_encoding
+  if os.path.splitext(path)[1] in ('.png', '.svg'):
+    resp.headers['Cache-Control'] = 'public, max-age=86400'  # 1 Day
+  else:
+    resp.headers['Cache-Control'] = 'public, max-age=600'  # 10 min
+  return resp
+
+
+def get_credentials_for_local_testing():
+  from google_auth_oauthlib import flow
+  flow = flow.InstalledAppFlow.from_client_config(
+      client_config={
+          'installed': {
+              # These aren't secret. Copied from gsutil's apitools sources.
+              'client_id': '1042881264118.apps.googleusercontent.com',
+              'client_secret': 'x_Tw5K8nnjoRAqULM9PFAC2b',
+              'redirect_uris': ['urn:ietf:wg:oauth:2.0:oob'],
+              'auth_uri': 'https://accounts.google.com/o/oauth2/auth',
+              'token_uri': 'https://accounts.google.com/o/oauth2/token'
+          }
+      },
+      scopes=['https://www.googleapis.com/auth/devstorage.read_only'])
+  creds = flow.run_console()
+  return creds
+
+
+if __name__ == '__main__':
+  # This is used when running locally only.
+  creds = get_credentials_for_local_testing()
+  storage_client = storage.Client(project='perfetto-site', credentials=creds)
+  bucket = storage_client.bucket(BUCKET_NAME)
+  is_local_testing_instance = True
+  app.run(host='127.0.0.1', port=8082, debug=False)
diff --git a/infra/perfetto.dev/appengine/requirements.txt b/infra/perfetto.dev/appengine/requirements.txt
new file mode 100644
index 0000000..9dc4af3
--- /dev/null
+++ b/infra/perfetto.dev/appengine/requirements.txt
@@ -0,0 +1,2 @@
+Flask==1.1.2
+google-cloud-storage
diff --git a/infra/perfetto.dev/build b/infra/perfetto.dev/build
new file mode 100755
index 0000000..59a1c35
--- /dev/null
+++ b/infra/perfetto.dev/build
@@ -0,0 +1,29 @@
+#!/bin/bash
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -eu
+
+# cd into the //infra/perfetto.dev dir, so this works uniformely when invoked by
+# other paths. the cd is required for npm install.
+cd -P ${BASH_SOURCE[0]%/*}
+
+# Ensure that `npm install` has been called and is current. Note that the set of
+# packages that the docs website requires is != the UI ones.
+if ! test node_modules/.stamp -nt package-lock.json; then
+  ../../tools/npm install
+  touch node_modules/.stamp
+fi
+
+../../tools/node ./build.js "$@"
diff --git a/infra/perfetto.dev/build.js b/infra/perfetto.dev/build.js
new file mode 100644
index 0000000..0e12180
--- /dev/null
+++ b/infra/perfetto.dev/build.js
@@ -0,0 +1,367 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+'use strict';
+
+// This script builds the perfetto.dev docs website.
+
+const argparse = require('argparse');
+const child_process = require('child_process');
+const fs = require('fs');
+const http = require('http');
+const path = require('path');
+const fswatch = require('node-watch');  // Like fs.watch(), but works on Linux.
+const pjoin = path.join;
+
+const ROOT_DIR = path.dirname(path.dirname(__dirname));  // The repo root.
+
+const cfg = {
+  watch: false,
+  verbose: false,
+  startHttpServer: false,
+
+  outDir: pjoin(ROOT_DIR, 'out/perfetto.dev'),
+};
+
+const RULES = [
+  {r: /infra\/perfetto.dev\/src\/assets\/((.*)\.png)/, f: copyAssets},
+  {r: /infra\/perfetto.dev\/src\/assets\/((.*)\.js)/, f: copyAssets},
+  {r: /infra\/perfetto.dev\/node_modules\/.*\/(.*\.css|.*\.js)/, f: copyAssets},
+  {r: /infra\/perfetto.dev\/src\/assets\/.+\.scss/, f: compileScss},
+  {
+    r: /protos\/perfetto\/config\/trace_config\.proto/,
+    f: s => genProtoReference(s, 'perfetto.protos.TraceConfig')
+  },
+  {
+    r: /protos\/perfetto\/trace\/trace_packet\.proto/,
+    f: s => genProtoReference(s, 'perfetto.protos.TracePacket')
+  },
+  {r: /src\/trace_processor\/storage\/stats\.h/, f: genSqlStatsReference},
+  {r: /src\/trace_processor\/tables\/.*\.h/, f: s => sqlTables.add(s)},
+  {r: /docs\/toc[.]md/, f: genNav},
+  {r: /docs\/.*[.]md/, f: renderDoc},
+];
+
+let sqlTables = new Set();
+let tasks = [];
+let tasksTot = 0, tasksRan = 0;
+let tStart = Date.now();
+
+function main() {
+  const parser = new argparse.ArgumentParser();
+  parser.add_argument('--out', {help: 'Output directory'});
+  parser.add_argument('--watch', '-w', {action: 'store_true'});
+  parser.add_argument('--serve', '-s', {action: 'store_true'});
+  parser.add_argument('--verbose', '-v', {action: 'store_true'});
+
+  const args = parser.parse_args();
+  cfg.outDir = path.resolve(ensureDir(args.out || cfg.outDir, /*clean=*/ true));
+  cfg.watch = !!args.watch;
+  cfg.verbose = !!args.verbose;
+  cfg.startHttpServer = args.serve;
+
+  // Check that deps are current before starting.
+  const installBuildDeps = pjoin(ROOT_DIR, 'tools/install-build-deps');
+  const depsArgs = ['--check-only', '/dev/null', '--ui'];
+  exec(installBuildDeps, depsArgs);
+
+  console.log('Entering', cfg.outDir);
+  process.chdir(cfg.outDir);
+
+  scanDir('infra/perfetto.dev/src/assets');
+  scanFile(
+      'infra/perfetto.dev/node_modules/highlight.js/styles/tomorrow-night.css');
+  scanFile('infra/perfetto.dev/node_modules/mermaid/dist/mermaid.min.js');
+  scanFile('docs/toc.md');
+  genIndex();
+  scanFile('src/trace_processor/storage/stats.h');
+  scanDir('src/trace_processor/tables');
+  scanDir('protos');
+  genSqlTableReference();
+  scanDir('docs');
+  if (args.serve) {
+    addTask(startServer);
+  }
+}
+
+// -----------
+// Build rules
+// -----------
+
+function copyAssets(src, dst) {
+  addTask(cp, [src, pjoin(cfg.outDir, 'assets', dst)]);
+}
+
+function compileScss() {
+  const src = pjoin(__dirname, 'src/assets/style.scss');
+  const dst = pjoin(cfg.outDir, 'assets/style.css');
+  // In watch mode, don't exit(1) if scss fails. It can easily happen by
+  // having a typo in the css. It will still print an errror.
+  const noErrCheck = !!cfg.watch;
+  addTask(
+      execNode,
+      ['node_modules/.bin/node-sass', ['--quiet', src, dst], {noErrCheck}]);
+}
+
+function md2html(src, dst, template) {
+  const script = pjoin(__dirname, 'src/markdown_render.js');
+  const args = ['-i', src, '--odir', cfg.outDir, '-o', dst];
+  ensureDir(path.dirname(dst));
+  if (template) args.push('-t', pjoin(__dirname, 'src', template));
+  execNode(script, args);
+}
+
+function proto2md(src, dst, protoRootType) {
+  const script = pjoin(__dirname, 'src/gen_proto_reference.js');
+  const args = ['-i', src, '-p', protoRootType, '-o', dst];
+  ensureDir(path.dirname(dst));
+  execNode(script, args);
+}
+
+function genNav(src) {
+  const dst = pjoin(cfg.outDir, 'docs', '_nav.html');
+  addTask(md2html, [src, dst]);
+}
+
+function genIndex() {
+  const dst = pjoin(cfg.outDir, 'index.html');
+  addTask(md2html, ['/dev/null', dst, 'template_index.html']);
+}
+
+function renderDoc(src) {
+  let dstRel = path.relative(ROOT_DIR, src);
+  dstRel = dstRel.replace('.md', '').replace(/\bREADME$/, 'index.html');
+  const dst = pjoin(cfg.outDir, dstRel);
+  addTask(md2html, [src, dst, 'template_markdown.html']);
+}
+
+function genProtoReference(src, protoRootType) {
+  const fname = path.basename(src);
+  const dstFname = fname.replace(/[._]/g, '-');
+  const dstHtml = pjoin(cfg.outDir, 'docs/reference', dstFname);
+  const dstMd = dstHtml + '.md';
+  addTask(proto2md, [src, dstMd, protoRootType]);
+  addTask(md2html, [dstMd, dstHtml, 'template_markdown.html']);
+  addTask(exec, ['rm', [dstMd]]);
+}
+
+function genSqlStatsReference(src) {
+  const dstDir = ensureDir(pjoin(cfg.outDir, 'docs/analysis'));
+  const dstHtml = pjoin(dstDir, 'sql-stats');
+  const dstMd = dstHtml + '.md';
+  const script = pjoin(__dirname, 'src/gen_stats_reference.js');
+  const args = ['-i', src, '-o', dstMd];
+  addTask(execNode, [script, args]);
+  addTask(md2html, [dstMd, dstHtml, 'template_markdown.html']);
+  addTask(exec, ['rm', [dstMd]]);
+}
+
+function genSqlTableReference() {
+  const dstDir = ensureDir(pjoin(cfg.outDir, 'docs/analysis'));
+  const dstHtml = pjoin(dstDir, 'sql-tables');
+  const dstMd = dstHtml + '.md';
+  const script = pjoin(__dirname, 'src/gen_sql_tables_reference.js');
+  const args = ['-o', dstMd];
+  sqlTables.forEach(f => args.push('-i', f));
+  addTask(execNode, [script, args]);
+  addTask(md2html, [dstMd, dstHtml, 'template_markdown.html']);
+  addTask(exec, ['rm', [dstMd]]);
+}
+
+function startServer() {
+  const port = 8082;
+  console.log(`Starting HTTP server on http://localhost:${port}`)
+  http.createServer(function(req, res) {
+        console.debug(req.method, req.url);
+        let uri = req.url.split('?', 1)[0];
+        uri += uri.endsWith('/') ? 'index.html' : '';
+
+        const absPath = path.normalize(path.join(cfg.outDir, uri));
+        fs.readFile(absPath, function(err, data) {
+          if (err) {
+            res.writeHead(404);
+            res.end(JSON.stringify(err));
+            return;
+          }
+          const mimeMap = {
+            'css': 'text/css',
+            'svg': 'image/svg+xml',
+            'js': 'application/javascript',
+          };
+          const contentType = mimeMap[uri.split('.').pop()] || 'text/html';
+          const head = {
+            'Content-Type': contentType,
+            'Content-Length': data.length,
+            'Cache-Control': 'no-cache',
+          };
+          res.writeHead(200, head);
+          res.end(data);
+        });
+      })
+      .listen(port);
+}
+
+
+// -----------------------
+// Task chaining functions
+// -----------------------
+
+function addTask(func, args) {
+  const task = new Task(func, args);
+  for (const t of tasks) {
+    if (t.identity === task.identity) {
+      return;
+    }
+  }
+  tasks.push(task);
+  setTimeout(runTasks, 0);
+}
+
+function runTasks() {
+  const snapTasks = tasks.splice(0);  // snap = std::move(tasks).
+  tasksTot += snapTasks.length;
+  for (const task of snapTasks) {
+    const DIM = '\u001b[2m';
+    const BRT = '\u001b[37m';
+    const RST = '\u001b[0m';
+    const ms = (new Date(Date.now() - tStart)).toISOString().slice(17, -1);
+    const ts = `[${DIM}${ms}${RST}]`;
+    const descr = task.description.substr(0, 80);
+    console.log(`${ts} ${BRT}${++tasksRan}/${tasksTot}${RST}\t${descr}`);
+    task.func.apply(/*this=*/ undefined, task.args);
+  }
+}
+
+// Executes the first rule in RULES that match the given |absPath|.
+function scanFile(file) {
+  const absPath = path.isAbsolute(file) ? file : pjoin(ROOT_DIR, file);
+  console.assert(fs.existsSync(absPath));
+  const normPath = path.relative(ROOT_DIR, absPath);
+  for (const rule of RULES) {
+    const match = rule.r.exec(normPath);
+    if (!match || match[0] !== normPath) continue;
+    const captureGroup = match.length > 1 ? match[1] : undefined;
+    rule.f(absPath, captureGroup);
+    return;
+  }
+}
+
+// Walks the passed |dir| recursively and, for each file, invokes the matching
+// RULES. If --watch is used, it also installs a fswatch() and re-triggers the
+// matching RULES on each file change.
+function scanDir(dir, regex) {
+  const filterFn = regex ? absPath => regex.test(absPath) : () => true;
+  const absDir = path.isAbsolute(dir) ? dir : pjoin(ROOT_DIR, dir);
+  // Add a fs watch if in watch mode.
+  if (cfg.watch) {
+    fswatch(absDir, {recursive: true}, (_eventType, filePath) => {
+      if (!filterFn(filePath)) return;
+      if (cfg.verbose) {
+        console.log('File change detected', _eventType, filePath);
+      }
+      if (fs.existsSync(filePath)) {
+        scanFile(filePath, filterFn);
+      }
+    });
+  }
+  walk(absDir, f => {
+    if (filterFn(f)) scanFile(f);
+  });
+}
+
+function exec(cmd, args, opts) {
+  opts = opts || {};
+  opts.stdout = opts.stdout || 'inherit';
+  if (cfg.verbose) console.log(`${cmd} ${args.join(' ')}\n`);
+  const spwOpts = {cwd: cfg.outDir, stdio: ['ignore', opts.stdout, 'inherit']};
+  const checkExitCode = (code, signal) => {
+    if (signal === 'SIGINT' || signal === 'SIGTERM') return;
+    if (code !== 0 && !opts.noErrCheck) {
+      console.error(`${cmd} ${args.join(' ')} failed with code ${code}`);
+      process.exit(1);
+    }
+  };
+  const spawnRes = child_process.spawnSync(cmd, args, spwOpts);
+  checkExitCode(spawnRes.status, spawnRes.signal);
+  return spawnRes;
+}
+
+function execNode(script, args, opts) {
+  const modPath = path.isAbsolute(script) ? script : pjoin(__dirname, script);
+  const nodeBin = pjoin(ROOT_DIR, 'tools/node');
+  args = [modPath].concat(args || []);
+  const argsJson = JSON.stringify(args);
+  return exec(nodeBin, args, opts);
+}
+
+// ------------------------------------------
+// File system & subprocess utility functions
+// ------------------------------------------
+
+class Task {
+  constructor(func, args) {
+    this.func = func;
+    this.args = args || [];
+    // |identity| is used to dedupe identical tasks in the queue.
+    this.identity = JSON.stringify([this.func.name, this.args]);
+  }
+
+  get description() {
+    const ret = this.func.name.startsWith('exec') ? [] : [this.func.name];
+    const flattenedArgs = [].concat.apply([], this.args);
+    for (const arg of flattenedArgs) {
+      const argStr = `${arg}`;
+      if (argStr.startsWith('/')) {
+        ret.push(path.relative(cfg.outDir, arg));
+      } else {
+        ret.push(argStr);
+      }
+    }
+    return ret.join(' ');
+  }
+}
+
+function walk(dir, callback, skipRegex) {
+  for (const child of fs.readdirSync(dir)) {
+    const childPath = pjoin(dir, child);
+    const stat = fs.lstatSync(childPath);
+    if (skipRegex !== undefined && skipRegex.test(child)) continue;
+    if (stat.isDirectory()) {
+      walk(childPath, callback, skipRegex);
+    } else if (!stat.isSymbolicLink()) {
+      callback(childPath);
+    }
+  }
+}
+
+function ensureDir(dirPath, clean) {
+  const exists = fs.existsSync(dirPath);
+  if (exists && clean) {
+    if (cfg.verbose) console.log('rm', dirPath);
+    fs.rmSync(dirPath, {recursive: true});
+  }
+  if (!exists || clean) fs.mkdirSync(dirPath, {recursive: true});
+  return dirPath;
+}
+
+function cp(src, dst) {
+  ensureDir(path.dirname(dst));
+  if (cfg.verbose) {
+    console.log(
+        'cp', path.relative(ROOT_DIR, src), '->', path.relative(ROOT_DIR, dst));
+  }
+  fs.copyFileSync(src, dst);
+}
+
+main();
diff --git a/infra/perfetto.dev/cloud_build_entrypoint.sh b/infra/perfetto.dev/cloud_build_entrypoint.sh
new file mode 100755
index 0000000..4497867
--- /dev/null
+++ b/infra/perfetto.dev/cloud_build_entrypoint.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -exu
+
+# This script will be run in /workspace after the Cloud Build environment has
+# pulled the GitHub repo in shallow mode. We want to build off the official
+# AOSP repo, not the GitHub mirror though, hence why the clone below.
+# GitHub is used only as a trigger. This is because Google Cloud Build doesn't
+# support yet triggering from Gerrit.
+# See go/perfetto-ui-autopush for more details.
+
+# The cd is really a safeguard against people running this script on their
+# workstation and hitting the rm -rf.
+cd /workspace/
+ls -A1 | xargs rm -rf
+UPSTREAM="https://android.googlesource.com/platform/external/perfetto.git"
+git clone --depth 1 $UPSTREAM upstream
+
+cd upstream/
+git rev-parse HEAD
+
+# Install only NodeJS, no need to install the other toolchains.
+tools/install-build-deps --ui --filter=nodejs
+
+# The deploy script takes care of building by invoking ./build internally.
+infra/perfetto.dev/deploy
diff --git a/infra/perfetto.dev/cloudbuild.yaml b/infra/perfetto.dev/cloudbuild.yaml
new file mode 100644
index 0000000..1acfb31
--- /dev/null
+++ b/infra/perfetto.dev/cloudbuild.yaml
@@ -0,0 +1,7 @@
+# See go/perfetto-ui-autopush for docs on how this works end-to-end.
+# Reuse the same Docker container of the UI autopusher.
+steps:
+- name: gcr.io/perfetto-ui/perfetto-ui-builder
+  args:
+  - 'infra/perfetto.dev/cloud_build_entrypoint.sh'
+  timeout: 1200s
diff --git a/infra/perfetto.dev/deploy b/infra/perfetto.dev/deploy
index 394dbb1..825f9e7 100755
--- a/infra/perfetto.dev/deploy
+++ b/infra/perfetto.dev/deploy
@@ -1,5 +1,5 @@
 #!/bin/bash
-# Copyright (C) 2018 The Android Open Source Project
+# Copyright (C) 2021 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -13,63 +13,61 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-set -e
+# This script builds the perfetto.dev docs website (via ./build) and pushes the
+# contents to the gs://perfetto.dev GCS bucket. It doesn't re-deploy the
+# AppEngine instance, as that doesn't depend on the contents (use
+# ./appengine/deploy for that).
+# This is ran by the Cloud Build infrastructure (./cloudbuild.yaml) whenever a
+# docs/ change is detected. See go/perfetto-ui-autopush for more details.
 
+set -eux
+
+# The directory that contains this script (//infra/perfetto.dev)
 readonly CUR_DIR="$(cd -P ${BASH_SOURCE[0]%/*}; pwd)"
+
+# The repo root.
 readonly ROOT_DIR=$(dirname $(dirname "$CUR_DIR"))
-readonly NPM="$ROOT_DIR/tools/npm"
 
-cd $CUR_DIR
+# The directory that will contain the static website artifacts.
+readonly OUT_DIR="$ROOT_DIR/out/perfetto.dev"
 
-function echo_and_do {
-  echo $@
-  $@
-}
+# Build first.
+"$CUR_DIR/build"
 
-CLEAN_OUT_DIR=true
-DEPLOY_PROD=false
-DEPLOY_STAGING=false
+# The markdown docs are rendered into extension-less HTML files to make the URLs
+# look nice (e.g., /docs/tracing rather than /docs/tracing.html). By default
+# gsutil infers the mime-type from the extension, falling back to octet/stream
+# for extension-less fiels. octect/stream causes the browser to download the
+# file rather than parsing it as a web page.
+# We set use_magicfile = True here, which causes gsutil to infer the MIME type
+# by invoking `file -b --mime /path/to/file`.
+# Unfortunately, that solves the HTML MIME problem but adds another one: the
+# standard `file` util doesn't deal with .css files and marks them as text/plain
+# causing the browser to ignore the CSS.
+# Here what we do is replacing the standard `file` util with a custom made one
+# (mime_util/file) which sets the right MIME types we want. We do this by
+# prepending our script to the PATH.
+export PATH="$CUR_DIR/mime_util:$PATH"
+export BOTO_CONFIG=/tmp/boto
+cat << EOF > $BOTO_CONFIG
+[GSUtil]
+use_magicfile = True
 
-while [[ $# -gt 0 ]]; do
-  key="$1"
-  case $key in
-      --no-clean)
-      CLEAN_OUT_DIR=false
-      shift
-      ;;
-      --prod)
-      DEPLOY_PROD=true
-      shift
-      ;;
-      --staging)
-      DEPLOY_STAGING=true
-      shift
-      ;;
-      -h|--help)
-      echo "Usage: $0 [--no-clean] [--prod] [--staging]"
-      echo "    --no-clean  Don't remove the out directory"
-      echo "    --prod      Deploy prod version (implies --release)"
-      echo "    --staging   Deploy staging version"
-      echo "    -h|--help   Display this message"
-      exit 0
-      shift
-      ;;
-  esac
-done
+EOF
 
-if [ "$CLEAN_OUT_DIR" = true ]; then
-  echo_and_do $NPM run clean
-fi
+# Basic checks before uploading. Test both the existence and the mime type.
+[ "$(file $OUT_DIR/index.html)" == "text/html" ]
+[ "$(file $OUT_DIR/assets/style.css)" == "text/css" ]
+[ "$(file $OUT_DIR/assets/home.png)" == "image/png" ]
+[ "$(file $OUT_DIR/docs/images/perfetto-stack.svg)" == "image/svg+xml" ]
+[ "$(file $OUT_DIR/docs/images/perfetto-stack.svg)" == "image/svg+xml" ]
+[ "$(file $OUT_DIR/docs/analysis/sql-tables)" == "text/html" ]
 
-echo_and_do $NPM run build
-
-if [ "$DEPLOY_PROD" = true ]; then
-  echo_and_do gcloud app deploy app.yaml --project perfetto-site \
-      -v prod --promote --stop-previous-version
-elif [ "$DEPLOY_STAGING" = true ]; then
-  echo_and_do gcloud app deploy app.yaml --project perfetto-site \
-      -v staging --no-promote --stop-previous-version
-else
-  echo_and_do gcloud app deploy app.yaml --project perfetto-site \
-      -v $USER --no-promote --stop-previous-version
-fi
+# -j: apply 'Content-Encoding: gzip' compression to passed extensions.
+# -d: mirror also deletetions.
+# -c: compare checksums, not mtimes.
+# -r: recursive.
+# The trailing slash appended to $OUT_DIR is to prevent that gsutil creates a
+# nested sub-directory inside gs://perfetto.dev/.
+gsutil -m rsync -j html,js,css,svg -d -c -r \
+  "$OUT_DIR/" gs://perfetto.dev/
diff --git a/infra/perfetto.dev/dispatch.yaml b/infra/perfetto.dev/dispatch.yaml
deleted file mode 100644
index 8315963..0000000
--- a/infra/perfetto.dev/dispatch.yaml
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright (C) 2020 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-dispatch:
-- url: "docs.perfetto.dev/*"
-  service: redirect
-- url: "www.perfetto.dev/*"
-  service: redirect
-- url: "*/*"
-  service: default
diff --git a/infra/perfetto.dev/dist b/infra/perfetto.dev/dist
deleted file mode 120000
index eac3128..0000000
--- a/infra/perfetto.dev/dist
+++ /dev/null
@@ -1 +0,0 @@
-../../out/perfetto.dev/site
\ No newline at end of file
diff --git a/infra/perfetto.dev/main.py b/infra/perfetto.dev/main.py
deleted file mode 100644
index 610b746..0000000
--- a/infra/perfetto.dev/main.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright (C) 2020 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Deliberately empty. The site is fully static and doesn't need any server-side
-# component. This is only to keep dev_appserver.py happy.
\ No newline at end of file
diff --git a/infra/perfetto.dev/mime_util/file b/infra/perfetto.dev/mime_util/file
new file mode 100755
index 0000000..ba687ec
--- /dev/null
+++ b/infra/perfetto.dev/mime_util/file
@@ -0,0 +1,31 @@
+#!/usr/bin/env python3
+
+import sys
+import os
+
+def main():
+  # Typically the target file argument is the last arg. gsutil invokes:
+  # `file -b --mime /path/to/file`. Rathter than depending on it, just pick
+  # the right-most argument which points to a valid file.
+  fname = None
+  for arg in reversed(sys.argv[1:]):
+    if os.path.exists(arg):
+      fname = arg
+      break
+  if fname is None:
+    raise 'File not found in ' + ' '.join(sys.argv)
+
+  ext = os.path.splitext(fname)[1].lower()
+  ext_map = {
+    '.html': 'text/html',
+    '.css': 'text/css',
+    '.js': 'text/javascript',
+    '.jpg': 'image/jpeg',
+    '.png': 'image/png',
+    '.svg': 'image/svg+xml',
+  }
+  print(ext_map.get(ext, 'text/html'))
+  return 0
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/infra/perfetto.dev/package-lock.json b/infra/perfetto.dev/package-lock.json
index 3c3f329..b722b8c 100644
--- a/infra/perfetto.dev/package-lock.json
+++ b/infra/perfetto.dev/package-lock.json
@@ -4,12 +4,6 @@
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
-    "@blakeembrey/deque": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/@blakeembrey/deque/-/deque-1.0.5.tgz",
-      "integrity": "sha512-6xnwtvp9DY1EINIKdTfvfeAtCYw4OqBZJhtiqkT3ivjnEfa25VQ3TsKvaFfKm8MyGIEfE95qLe+bNEt3nB0Ylg==",
-      "dev": true
-    },
     "@braintree/sanitize-url": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-3.1.0.tgz",
@@ -79,12 +73,6 @@
       "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=",
       "dev": true
     },
-    "@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
-    },
     "@types/long": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz",
@@ -92,9 +80,9 @@
       "dev": true
     },
     "@types/node": {
-      "version": "13.13.1",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.1.tgz",
-      "integrity": "sha512-uysqysLJ+As9jqI5yqjwP3QJrhOcUwBjHUlUxPxjbplwKoILvXVsmYWEhfmAQlrPfbRZmhJB007o4L9sKqtHqQ==",
+      "version": "13.13.41",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.41.tgz",
+      "integrity": "sha512-qLT9IvHiXJfdrje9VmsLzun7cQ65obsBTmtU3EOnCSLFOoSHx1hpiRHoBnpdbyFqnzqdUUIv81JcEJQCB8un9g==",
       "dev": true
     },
     "abbrev": {
@@ -104,9 +92,9 @@
       "dev": true
     },
     "ajv": {
-      "version": "6.11.0",
-      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.11.0.tgz",
-      "integrity": "sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA==",
+      "version": "6.12.6",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+      "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
       "dev": true,
       "requires": {
         "fast-deep-equal": "^3.1.1",
@@ -136,16 +124,6 @@
         "color-convert": "^1.9.0"
       }
     },
-    "anymatch": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
-      "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
-      "dev": true,
-      "requires": {
-        "normalize-path": "^3.0.0",
-        "picomatch": "^2.0.4"
-      }
-    },
     "aproba": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
@@ -162,18 +140,18 @@
         "readable-stream": "^2.0.6"
       }
     },
+    "argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+      "dev": true
+    },
     "array-find-index": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
       "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
       "dev": true
     },
-    "arrify": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
-      "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==",
-      "dev": true
-    },
     "asn1": {
       "version": "0.2.4",
       "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
@@ -189,6 +167,12 @@
       "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
       "dev": true
     },
+    "async": {
+      "version": "0.9.2",
+      "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz",
+      "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=",
+      "dev": true
+    },
     "async-foreach": {
       "version": "0.1.3",
       "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz",
@@ -214,9 +198,9 @@
       "dev": true
     },
     "aws4": {
-      "version": "1.9.1",
-      "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz",
-      "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==",
+      "version": "1.11.0",
+      "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
+      "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==",
       "dev": true
     },
     "balanced-match": {
@@ -234,21 +218,6 @@
         "tweetnacl": "^0.14.3"
       }
     },
-    "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
-    },
-    "block-stream": {
-      "version": "0.0.9",
-      "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
-      "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=",
-      "dev": true,
-      "requires": {
-        "inherits": "~2.0.0"
-      }
-    },
     "brace-expansion": {
       "version": "1.1.11",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -259,15 +228,6 @@
         "concat-map": "0.0.1"
       }
     },
-    "braces": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
-      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
-      "dev": true,
-      "requires": {
-        "fill-range": "^7.0.1"
-      }
-    },
     "buffer-from": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
@@ -313,34 +273,13 @@
         "ansi-styles": "^3.2.1",
         "escape-string-regexp": "^1.0.5",
         "supports-color": "^5.3.0"
-      },
-      "dependencies": {
-        "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,
-          "requires": {
-            "has-flag": "^3.0.0"
-          }
-        }
       }
     },
-    "chokidar": {
-      "version": "3.3.1",
-      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz",
-      "integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==",
-      "dev": true,
-      "requires": {
-        "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"
-      }
+    "chownr": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
+      "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
+      "dev": true
     },
     "clean-css": {
       "version": "4.2.3",
@@ -348,24 +287,51 @@
       "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==",
       "requires": {
         "source-map": "~0.6.0"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
-        }
       }
     },
     "cliui": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
-      "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
+      "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
       "dev": true,
       "requires": {
-        "string-width": "^1.0.1",
-        "strip-ansi": "^3.0.1",
-        "wrap-ansi": "^2.0.0"
+        "string-width": "^3.1.0",
+        "strip-ansi": "^5.2.0",
+        "wrap-ansi": "^5.1.0"
+      },
+      "dependencies": {
+        "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
+        },
+        "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
+        },
+        "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,
+          "requires": {
+            "emoji-regex": "^7.0.1",
+            "is-fullwidth-code-point": "^2.0.0",
+            "strip-ansi": "^5.1.0"
+          }
+        },
+        "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,
+          "requires": {
+            "ansi-regex": "^4.1.0"
+          }
+        }
       }
     },
     "code-point-at": {
@@ -399,9 +365,9 @@
       }
     },
     "commander": {
-      "version": "2.6.0",
-      "resolved": "https://registry.npmjs.org/commander/-/commander-2.6.0.tgz",
-      "integrity": "sha1-nfflL7Kgyw+4kFjugMMQQiXzfh0="
+      "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=="
     },
     "concat-map": {
       "version": "0.0.1",
@@ -409,23 +375,6 @@
       "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
       "dev": true
     },
-    "concurrently": {
-      "version": "3.6.1",
-      "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-3.6.1.tgz",
-      "integrity": "sha512-/+ugz+gwFSEfTGUxn0KHkY+19XPRTXR8+7oUK/HxgiN1n7FjeJmkrbSiXAJfyQ0zORgJYPaenmymwon51YXH9Q==",
-      "dev": true,
-      "requires": {
-        "chalk": "^2.4.1",
-        "commander": "2.6.0",
-        "date-fns": "^1.23.0",
-        "lodash": "^4.5.1",
-        "read-pkg": "^3.0.0",
-        "rx": "2.3.24",
-        "spawn-command": "^0.0.2-1",
-        "supports-color": "^3.2.3",
-        "tree-kill": "^1.1.0"
-      }
-    },
     "console-control-strings": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
@@ -439,21 +388,14 @@
       "dev": true
     },
     "cross-spawn": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz",
-      "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=",
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+      "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
       "dev": true,
       "requires": {
-        "lru-cache": "^4.0.1",
-        "which": "^1.2.9"
-      }
-    },
-    "crypto-random-string": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-3.2.0.tgz",
-      "integrity": "sha512-8vPu5bsKaq2uKRy3OL7h1Oo7RayAWB8sYexLKAqvCXVib8SxgbmoF1IN4QMKjBv8uI8mp5gPPMbiRah25GMrVQ==",
-      "requires": {
-        "type-fest": "^0.8.1"
+        "path-key": "^3.1.0",
+        "shebang-command": "^2.0.0",
+        "which": "^2.0.1"
       }
     },
     "css-b64-images": {
@@ -519,9 +461,9 @@
       "integrity": "sha512-ejINPfPSNdGFKEOAtnBtdkpr24c4d4jsei6Lg98mxf424ivoDP2956/5HDpIAtmHo85lqT4pruy+zEgvRUBqaQ=="
     },
     "d3-brush": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.1.5.tgz",
-      "integrity": "sha512-rEaJ5gHlgLxXugWjIkolTA0OyMvw8UWU1imYXy1v642XyyswmI1ybKOv05Ft+ewq+TFmdliD3VuK0pRp1VT/5A==",
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.1.6.tgz",
+      "integrity": "sha512-7RW+w7HfMCPyZLifTz/UnJmI5kdkXtpCbombUSs8xniAyo0vIbrDzDwUJB6eJOgl9u5DQOt2TQlYumxzD1SvYA==",
       "requires": {
         "d3-dispatch": "1",
         "d3-drag": "1",
@@ -582,14 +524,14 @@
       }
     },
     "d3-ease": {
-      "version": "1.0.6",
-      "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.6.tgz",
-      "integrity": "sha512-SZ/lVU7LRXafqp7XtIcBdxnWl8yyLpgOmzAk0mWBI9gXNzLDx5ybZgnRbH9dN/yY5tzVBqCQ9avltSnqVwessQ=="
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.7.tgz",
+      "integrity": "sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ=="
     },
     "d3-fetch": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-1.1.2.tgz",
-      "integrity": "sha512-S2loaQCV/ZeyTyIF2oP8D1K9Z4QizUzW7cWeAOAS4U88qOt3Ucf6GsmgthuYSdyB2HyEm4CeGvkQxWsmInsIVA==",
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-1.2.0.tgz",
+      "integrity": "sha512-yC78NBVcd2zFAyR/HnUiBS7Lf6inSCoWcSxFfw8FYL7ydiqe80SazNwoffcqOfs95XaLo7yebsmQqDKSsXUtvA==",
       "requires": {
         "d3-dsv": "1"
       }
@@ -606,14 +548,14 @@
       }
     },
     "d3-format": {
-      "version": "1.4.4",
-      "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.4.tgz",
-      "integrity": "sha512-TWks25e7t8/cqctxCmxpUuzZN11QxIA7YrMbram94zMQ0PXjE4LVIMe/f6a4+xxL8HQ3OsAFULOINQi1pE62Aw=="
+      "version": "1.4.5",
+      "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz",
+      "integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ=="
     },
     "d3-geo": {
-      "version": "1.12.0",
-      "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.12.0.tgz",
-      "integrity": "sha512-NalZVW+6/SpbKcnl+BCO67m8gX+nGeJdo6oGL9H6BRUGUL1e+AtPcP4vE4TwCQ/gl8y5KE7QvBzrLn+HsKIl+w==",
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.12.1.tgz",
+      "integrity": "sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg==",
       "requires": {
         "d3-array": "1"
       }
@@ -674,9 +616,9 @@
       }
     },
     "d3-selection": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.1.tgz",
-      "integrity": "sha512-BTIbRjv/m5rcVTfBs4AMBLKs4x8XaaLkwm28KWu9S2vKNqXkXt2AH2Qf0sdPZHjFxcWg/YL53zcqAz+3g4/7PA=="
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.2.tgz",
+      "integrity": "sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg=="
     },
     "d3-shape": {
       "version": "1.3.7",
@@ -692,9 +634,9 @@
       "integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA=="
     },
     "d3-time-format": {
-      "version": "2.2.3",
-      "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.2.3.tgz",
-      "integrity": "sha512-RAHNnD8+XvC4Zc4d2A56Uw0yJoM7bsvOlJR33bclxq399Rak/b9bhvu/InjxdWhPtkgU53JJcleJTGkNRnN6IA==",
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.3.0.tgz",
+      "integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==",
       "requires": {
         "d3-time": "1"
       }
@@ -763,18 +705,12 @@
         "assert-plus": "^1.0.0"
       }
     },
-    "date-fns": {
-      "version": "1.30.1",
-      "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz",
-      "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==",
-      "dev": true
-    },
     "debug": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
-      "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+      "version": "4.3.1",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+      "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
       "requires": {
-        "ms": "^2.1.1"
+        "ms": "2.1.2"
       }
     },
     "decamelize": {
@@ -806,15 +742,32 @@
       }
     },
     "ejs": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.0.1.tgz",
-      "integrity": "sha512-cuIMtJwxvzumSAkqaaoGY/L6Fc/t6YvoP9/VIaK0V/CyqKLEQ8sqODmYfy/cjXEdZ9+OOL8TecbJu+1RsofGDw==",
-      "dev": true
+      "version": "3.1.6",
+      "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz",
+      "integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==",
+      "dev": true,
+      "requires": {
+        "jake": "^10.6.1"
+      }
     },
     "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==",
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+      "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
+      "dev": true
+    },
+    "entity-decode": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/entity-decode/-/entity-decode-2.0.2.tgz",
+      "integrity": "sha512-5CCY/3ci4MC1m2jlumNjWd7VBFt4VfFnmSqSNmVcXq4gxM3Vmarxtt+SvmBnzwLS669MWdVuXboNVj1qN2esVg==",
+      "requires": {
+        "he": "^1.1.1"
+      }
+    },
+    "env-paths": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz",
+      "integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA==",
       "dev": true
     },
     "error-ex": {
@@ -832,11 +785,6 @@
       "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
       "dev": true
     },
-    "escaper": {
-      "version": "2.5.3",
-      "resolved": "https://registry.npmjs.org/escaper/-/escaper-2.5.3.tgz",
-      "integrity": "sha512-QGb9sFxBVpbzMggrKTX0ry1oiI4CSDAl9vIL702hzl1jGW8VZs7qfqTRX7WDOjoNDoEVGcEtu1ZOQgReSfT2kQ=="
-    },
     "extend": {
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
@@ -850,9 +798,9 @@
       "dev": true
     },
     "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==",
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
       "dev": true
     },
     "fast-json-stable-stringify": {
@@ -861,13 +809,13 @@
       "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
       "dev": true
     },
-    "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==",
+    "filelist": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz",
+      "integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==",
       "dev": true,
       "requires": {
-        "to-regex-range": "^5.0.1"
+        "minimatch": "^3.0.4"
       }
     },
     "find-up": {
@@ -898,15 +846,24 @@
       }
     },
     "fs-extra": {
-      "version": "9.0.0",
-      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz",
-      "integrity": "sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==",
+      "version": "9.1.0",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
+      "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
       "dev": true,
       "requires": {
         "at-least-node": "^1.0.0",
         "graceful-fs": "^4.2.0",
         "jsonfile": "^6.0.1",
-        "universalify": "^1.0.0"
+        "universalify": "^2.0.0"
+      }
+    },
+    "fs-minipass": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
+      "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
+      "dev": true,
+      "requires": {
+        "minipass": "^3.0.0"
       }
     },
     "fs.realpath": {
@@ -915,24 +872,11 @@
       "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
       "dev": true
     },
-    "fsevents": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz",
-      "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==",
-      "dev": true,
-      "optional": true
-    },
-    "fstream": {
-      "version": "1.0.12",
-      "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
-      "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==",
-      "dev": true,
-      "requires": {
-        "graceful-fs": "^4.1.2",
-        "inherits": "~2.0.0",
-        "mkdirp": ">=0.5 0",
-        "rimraf": "2"
-      }
+    "function-bind": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+      "dev": true
     },
     "gauge": {
       "version": "2.7.4",
@@ -960,9 +904,9 @@
       }
     },
     "get-caller-file": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
-      "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
       "dev": true
     },
     "get-stdin": {
@@ -994,19 +938,10 @@
         "path-is-absolute": "^1.0.0"
       }
     },
-    "glob-parent": {
-      "version": "5.1.0",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz",
-      "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==",
-      "dev": true,
-      "requires": {
-        "is-glob": "^4.0.1"
-      }
-    },
     "globule": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.0.tgz",
-      "integrity": "sha512-YlD4kdMqRCQHrhVdonet4TdRtv1/sZKepvoxNT4Nrhrp5HI8XFfc8kFlGlBn2myBo80aGp8Eft259mbcUJhgSg==",
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.2.tgz",
+      "integrity": "sha512-7IDTQTIu2xzXkT+6mlluidnWo+BypnbSoEVVQCGfzqnl5Ik8d3e1d4wycb8Rj9tWW+Z39uPWsdlquqiqPCd/pA==",
       "dev": true,
       "requires": {
         "glob": "~7.1.1",
@@ -1015,9 +950,9 @@
       }
     },
     "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==",
+      "version": "4.2.6",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
+      "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==",
       "dev": true
     },
     "graphlib": {
@@ -1035,15 +970,24 @@
       "dev": true
     },
     "har-validator": {
-      "version": "5.1.3",
-      "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
-      "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
+      "version": "5.1.5",
+      "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
+      "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
       "dev": true,
       "requires": {
-        "ajv": "^6.5.5",
+        "ajv": "^6.12.3",
         "har-schema": "^2.0.0"
       }
     },
+    "has": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+      "dev": true,
+      "requires": {
+        "function-bind": "^1.1.1"
+      }
+    },
     "has-ansi": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
@@ -1071,15 +1015,15 @@
       "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
     },
     "highlight.js": {
-      "version": "10.1.2",
-      "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.1.2.tgz",
-      "integrity": "sha512-Q39v/Mn5mfBlMff9r+zzA+gWxRsCRKwEMvYTiisLr/XUiFI/4puWt0Ojdko3R3JCNWGdOWaA5g/Yxqa23kC5AA==",
+      "version": "10.6.0",
+      "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.6.0.tgz",
+      "integrity": "sha512-8mlRcn5vk/r4+QcqerapwBYTe+iPL5ih6xrNylxrnBdHQiijDETfXX7VIxC3UiCRiINBJfANBAsPzAvRQj8RpQ==",
       "dev": true
     },
     "hosted-git-info": {
-      "version": "2.8.5",
-      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz",
-      "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==",
+      "version": "2.8.8",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
+      "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
       "dev": true
     },
     "html-minifier": {
@@ -1094,13 +1038,6 @@
         "param-case": "^2.1.1",
         "relateurl": "^0.2.7",
         "uglify-js": "^3.5.1"
-      },
-      "dependencies": {
-        "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=="
-        }
       }
     },
     "http-signature": {
@@ -1122,18 +1059,6 @@
         "safer-buffer": ">= 2.1.2 < 3"
       }
     },
-    "ignore": {
-      "version": "5.1.4",
-      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz",
-      "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==",
-      "dev": true
-    },
-    "in-publish": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz",
-      "integrity": "sha1-4g/146KvwmkDILbcVSaCqcf631E=",
-      "dev": true
-    },
     "indent-string": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
@@ -1159,33 +1084,21 @@
       "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
       "dev": true
     },
-    "invert-kv": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
-      "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=",
-      "dev": true
-    },
     "is-arrayish": {
       "version": "0.2.1",
       "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
       "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
       "dev": true
     },
-    "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==",
+    "is-core-module": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz",
+      "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==",
       "dev": true,
       "requires": {
-        "binary-extensions": "^2.0.0"
+        "has": "^1.0.3"
       }
     },
-    "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
-    },
     "is-finite": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz",
@@ -1201,26 +1114,6 @@
         "number-is-nan": "^1.0.0"
       }
     },
-    "is-glob": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
-      "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
-      "dev": true,
-      "requires": {
-        "is-extglob": "^2.1.1"
-      }
-    },
-    "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
-    },
-    "is-regexp": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz",
-      "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk="
-    },
     "is-typedarray": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
@@ -1251,10 +1144,22 @@
       "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
       "dev": true
     },
+    "jake": {
+      "version": "10.8.2",
+      "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz",
+      "integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==",
+      "dev": true,
+      "requires": {
+        "async": "0.9.x",
+        "chalk": "^2.4.2",
+        "filelist": "^1.0.1",
+        "minimatch": "^3.0.4"
+      }
+    },
     "js-base64": {
-      "version": "2.5.1",
-      "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.1.tgz",
-      "integrity": "sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==",
+      "version": "2.6.4",
+      "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz",
+      "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==",
       "dev": true
     },
     "jsbn": {
@@ -1263,12 +1168,6 @@
       "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
       "dev": true
     },
-    "json-parse-better-errors": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
-      "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
-      "dev": true
-    },
     "json-schema": {
       "version": "0.2.3",
       "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
@@ -1288,13 +1187,13 @@
       "dev": true
     },
     "jsonfile": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz",
-      "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==",
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+      "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
       "dev": true,
       "requires": {
         "graceful-fs": "^4.1.6",
-        "universalify": "^1.0.0"
+        "universalify": "^2.0.0"
       }
     },
     "jsprim": {
@@ -1309,40 +1208,46 @@
         "verror": "1.10.0"
       }
     },
-    "lcid": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
-      "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
-      "dev": true,
-      "requires": {
-        "invert-kv": "^1.0.0"
-      }
+    "khroma": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/khroma/-/khroma-1.2.0.tgz",
+      "integrity": "sha512-DlKk5y243dujy8fOH02aRnnewLfiHJV0s8aXaVrCohgBf3s7fEAn6gc6LLQ21agODlFZS8ufrn+juu70uCA9Tw=="
     },
     "load-json-file": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
-      "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
+      "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
       "dev": true,
       "requires": {
         "graceful-fs": "^4.1.2",
-        "parse-json": "^4.0.0",
-        "pify": "^3.0.0",
-        "strip-bom": "^3.0.0"
+        "parse-json": "^2.2.0",
+        "pify": "^2.0.0",
+        "pinkie-promise": "^2.0.0",
+        "strip-bom": "^2.0.0"
       }
     },
     "locate-path": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
-      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+      "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
       "dev": true,
       "requires": {
-        "p-locate": "^4.1.0"
+        "p-locate": "^3.0.0",
+        "path-exists": "^3.0.0"
+      },
+      "dependencies": {
+        "path-exists": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+          "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+          "dev": true
+        }
       }
     },
     "lodash": {
-      "version": "4.17.15",
-      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
-      "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
+      "version": "4.17.20",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
+      "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
     },
     "long": {
       "version": "4.0.0",
@@ -1366,13 +1271,12 @@
       "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw="
     },
     "lru-cache": {
-      "version": "4.1.5",
-      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
-      "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
       "dev": true,
       "requires": {
-        "pseudomap": "^1.0.2",
-        "yallist": "^2.1.2"
+        "yallist": "^4.0.0"
       }
     },
     "map-obj": {
@@ -1382,9 +1286,9 @@
       "dev": true
     },
     "marked": {
-      "version": "0.8.0",
-      "resolved": "https://registry.npmjs.org/marked/-/marked-0.8.0.tgz",
-      "integrity": "sha512-MyUe+T/Pw4TZufHkzAfDj6HarCBWia2y27/bhuYkTaiUnfDYFnCP3KUN+9oM7Wi6JA2rymtVYbQu3spE0GCmxQ==",
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/marked/-/marked-0.8.2.tgz",
+      "integrity": "sha512-EGwzEeCcLniFX51DhTpmTom+dSA/MG/OBUDjnWtHbEnjAH180VzUeAw+oE4+Zv+CoYBWyRlYOTR0N8SO9R1PVw==",
       "dev": true
     },
     "meow": {
@@ -1406,36 +1310,36 @@
       }
     },
     "mermaid": {
-      "version": "8.5.0",
-      "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-8.5.0.tgz",
-      "integrity": "sha512-fZf4GAzkqWuSwo5L+BmzaBwWPudHkxL3M/t1RmS9Dvc2mcnv6hdhMaeC7poARpHaSGwkpb74LL81qXj+vAsVBg==",
+      "version": "8.9.0",
+      "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-8.9.0.tgz",
+      "integrity": "sha512-J582tyE1vkdNu4BGgfwXnFo4Mu6jpuc4uK96mIenavaak9kr4T5gaMmYCo/7edwq/vTBkx/soZ5LcJo5WXZ1BQ==",
       "requires": {
         "@braintree/sanitize-url": "^3.1.0",
-        "crypto-random-string": "^3.0.1",
         "d3": "^5.7.0",
         "dagre": "^0.8.4",
         "dagre-d3": "^0.6.4",
+        "entity-decode": "^2.0.2",
         "graphlib": "^2.1.7",
         "he": "^1.2.0",
-        "lodash": "^4.17.11",
+        "khroma": "^1.1.0",
         "minify": "^4.1.1",
         "moment-mini": "^2.22.1",
-        "scope-css": "^1.2.1"
+        "stylis": "^3.5.2"
       }
     },
     "mime-db": {
-      "version": "1.43.0",
-      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz",
-      "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==",
+      "version": "1.45.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz",
+      "integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==",
       "dev": true
     },
     "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==",
+      "version": "2.1.28",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz",
+      "integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==",
       "dev": true,
       "requires": {
-        "mime-db": "1.43.0"
+        "mime-db": "1.45.0"
       }
     },
     "minify": {
@@ -1462,26 +1366,37 @@
       }
     },
     "minimist": {
-      "version": "1.2.0",
-      "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-      "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+      "version": "1.2.5",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+      "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
       "dev": true
     },
-    "mkdirp": {
-      "version": "0.5.1",
-      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
-      "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+    "minipass": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz",
+      "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==",
       "dev": true,
       "requires": {
-        "minimist": "0.0.8"
-      },
-      "dependencies": {
-        "minimist": {
-          "version": "0.0.8",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
-          "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
-          "dev": true
-        }
+        "yallist": "^4.0.0"
+      }
+    },
+    "minizlib": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
+      "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
+      "dev": true,
+      "requires": {
+        "minipass": "^3.0.0",
+        "yallist": "^4.0.0"
+      }
+    },
+    "mkdirp": {
+      "version": "0.5.5",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
+      "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
+      "dev": true,
+      "requires": {
+        "minimist": "^1.2.5"
       }
     },
     "moment-mini": {
@@ -1495,15 +1410,9 @@
       "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
     },
     "nan": {
-      "version": "2.14.0",
-      "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
-      "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
-      "dev": true
-    },
-    "nice-try": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
-      "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
+      "version": "2.14.2",
+      "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz",
+      "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==",
       "dev": true
     },
     "no-case": {
@@ -1515,54 +1424,54 @@
       }
     },
     "node-gyp": {
-      "version": "3.8.0",
-      "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz",
-      "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==",
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz",
+      "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==",
       "dev": true,
       "requires": {
-        "fstream": "^1.0.0",
-        "glob": "^7.0.3",
-        "graceful-fs": "^4.1.2",
-        "mkdirp": "^0.5.0",
-        "nopt": "2 || 3",
-        "npmlog": "0 || 1 || 2 || 3 || 4",
-        "osenv": "0",
-        "request": "^2.87.0",
-        "rimraf": "2",
-        "semver": "~5.3.0",
-        "tar": "^2.0.0",
-        "which": "1"
+        "env-paths": "^2.2.0",
+        "glob": "^7.1.4",
+        "graceful-fs": "^4.2.3",
+        "nopt": "^5.0.0",
+        "npmlog": "^4.1.2",
+        "request": "^2.88.2",
+        "rimraf": "^3.0.2",
+        "semver": "^7.3.2",
+        "tar": "^6.0.2",
+        "which": "^2.0.2"
       },
       "dependencies": {
         "semver": {
-          "version": "5.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
-          "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
-          "dev": true
+          "version": "7.3.4",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
+          "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
+          "dev": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
         }
       }
     },
     "node-sass": {
-      "version": "4.13.1",
-      "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.13.1.tgz",
-      "integrity": "sha512-TTWFx+ZhyDx1Biiez2nB0L3YrCZ/8oHagaDalbuBSlqXgUPsdkUSzJsVxeDO9LtPB49+Fh3WQl3slABo6AotNw==",
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-5.0.0.tgz",
+      "integrity": "sha512-opNgmlu83ZCF792U281Ry7tak9IbVC+AKnXGovcQ8LG8wFaJv6cLnRlc6DIHlmNxWEexB5bZxi9SZ9JyUuOYjw==",
       "dev": true,
       "requires": {
         "async-foreach": "^0.1.3",
         "chalk": "^1.1.1",
-        "cross-spawn": "^3.0.0",
+        "cross-spawn": "^7.0.3",
         "gaze": "^1.0.0",
         "get-stdin": "^4.0.1",
         "glob": "^7.0.3",
-        "in-publish": "^2.0.0",
         "lodash": "^4.17.15",
         "meow": "^3.7.0",
         "mkdirp": "^0.5.1",
         "nan": "^2.13.2",
-        "node-gyp": "^3.8.0",
+        "node-gyp": "^7.1.0",
         "npmlog": "^4.0.0",
         "request": "^2.88.0",
-        "sass-graph": "^2.2.4",
+        "sass-graph": "2.2.5",
         "stdout-stream": "^1.4.0",
         "true-case-path": "^1.0.2"
       },
@@ -1594,10 +1503,16 @@
         }
       }
     },
+    "node-watch": {
+      "version": "0.7.1",
+      "resolved": "https://registry.npmjs.org/node-watch/-/node-watch-0.7.1.tgz",
+      "integrity": "sha512-UWblPYuZYrkCQCW5PxAwYSxaELNBLUckrTBBk8xr1/bUgyOkYYTsUcV4e3ytcazFEOyiRyiUrsG37pu6I0I05g==",
+      "dev": true
+    },
     "nopt": {
-      "version": "3.0.6",
-      "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
-      "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
+      "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
       "dev": true,
       "requires": {
         "abbrev": "1"
@@ -1615,12 +1530,6 @@
         "validate-npm-package-license": "^3.0.1"
       }
     },
-    "normalize-path": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
-      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
-      "dev": true
-    },
     "npmlog": {
       "version": "4.1.2",
       "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
@@ -1660,99 +1569,22 @@
         "wrappy": "1"
       }
     },
-    "onchange": {
-      "version": "6.1.0",
-      "resolved": "https://registry.npmjs.org/onchange/-/onchange-6.1.0.tgz",
-      "integrity": "sha512-T0wvi3yzNd+Lut2ymJp2e6fTiob0TLrXnjqGaiK9MAFB8MYo/k/ZClx6ps7YhTtQ88dDm+hDHmtJXP1nJT5WNA==",
-      "dev": true,
-      "requires": {
-        "@blakeembrey/deque": "^1.0.3",
-        "arrify": "^2.0.0",
-        "chokidar": "^3.0.0",
-        "cross-spawn": "^6.0.0",
-        "ignore": "^5.1.4",
-        "minimist": "^1.2.0",
-        "supports-color": "^7.0.0",
-        "tree-kill": "^1.2.0"
-      },
-      "dependencies": {
-        "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,
-          "requires": {
-            "nice-try": "^1.0.4",
-            "path-key": "^2.0.1",
-            "semver": "^5.5.0",
-            "shebang-command": "^1.2.0",
-            "which": "^1.2.9"
-          }
-        },
-        "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
-        },
-        "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,
-          "requires": {
-            "has-flag": "^4.0.0"
-          }
-        }
-      }
-    },
-    "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
-    },
-    "os-locale": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
-      "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
-      "dev": true,
-      "requires": {
-        "lcid": "^1.0.0"
-      }
-    },
-    "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
-    },
-    "osenv": {
-      "version": "0.1.5",
-      "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
-      "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
-      "dev": true,
-      "requires": {
-        "os-homedir": "^1.0.0",
-        "os-tmpdir": "^1.0.0"
-      }
-    },
     "p-limit": {
-      "version": "2.2.2",
-      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz",
-      "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==",
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
       "dev": true,
       "requires": {
         "p-try": "^2.0.0"
       }
     },
     "p-locate": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
-      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+      "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
       "dev": true,
       "requires": {
-        "p-limit": "^2.2.0"
+        "p-limit": "^2.0.0"
       }
     },
     "p-try": {
@@ -1770,13 +1602,12 @@
       }
     },
     "parse-json": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
-      "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+      "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
       "dev": true,
       "requires": {
-        "error-ex": "^1.3.1",
-        "json-parse-better-errors": "^1.0.1"
+        "error-ex": "^1.2.0"
       }
     },
     "path-exists": {
@@ -1795,9 +1626,9 @@
       "dev": true
     },
     "path-key": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
-      "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
       "dev": true
     },
     "path-parse": {
@@ -1807,12 +1638,14 @@
       "dev": true
     },
     "path-type": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
-      "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
+      "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
       "dev": true,
       "requires": {
-        "pify": "^3.0.0"
+        "graceful-fs": "^4.1.2",
+        "pify": "^2.0.0",
+        "pinkie-promise": "^2.0.0"
       }
     },
     "performance-now": {
@@ -1821,16 +1654,10 @@
       "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
       "dev": true
     },
-    "picomatch": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.1.tgz",
-      "integrity": "sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==",
-      "dev": true
-    },
     "pify": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
-      "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+      "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
       "dev": true
     },
     "pinkie": {
@@ -1855,9 +1682,9 @@
       "dev": true
     },
     "protobufjs": {
-      "version": "6.9.0",
-      "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.9.0.tgz",
-      "integrity": "sha512-LlGVfEWDXoI/STstRDdZZKb/qusoAWUnmLg9R8OLSO473mBLWHowx8clbX5/+mKDEI+v7GzjoK9tRPZMMcoTrg==",
+      "version": "6.10.2",
+      "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.10.2.tgz",
+      "integrity": "sha512-27yj+04uF6ya9l+qfpH187aqEzfCF4+Uit0I9ZBQVqK09hk/SQzKa2MUqUpXaVa7LOFRg1TSSr3lVxGOk6c0SQ==",
       "dev": true,
       "requires": {
         "@protobufjs/aspromise": "^1.1.2",
@@ -1875,16 +1702,10 @@
         "long": "^4.0.0"
       }
     },
-    "pseudomap": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
-      "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
-      "dev": true
-    },
     "psl": {
-      "version": "1.7.0",
-      "resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz",
-      "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==",
+      "version": "1.8.0",
+      "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
+      "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==",
       "dev": true
     },
     "punycode": {
@@ -1893,15 +1714,21 @@
       "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
       "dev": true
     },
+    "qs": {
+      "version": "6.5.2",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+      "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
+      "dev": true
+    },
     "read-pkg": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
-      "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
+      "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
       "dev": true,
       "requires": {
-        "load-json-file": "^4.0.0",
+        "load-json-file": "^1.0.0",
         "normalize-package-data": "^2.3.2",
-        "path-type": "^3.0.0"
+        "path-type": "^1.0.0"
       }
     },
     "read-pkg-up": {
@@ -1912,67 +1739,6 @@
       "requires": {
         "find-up": "^1.0.0",
         "read-pkg": "^1.0.0"
-      },
-      "dependencies": {
-        "load-json-file": {
-          "version": "1.1.0",
-          "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
-          "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
-          "dev": true,
-          "requires": {
-            "graceful-fs": "^4.1.2",
-            "parse-json": "^2.2.0",
-            "pify": "^2.0.0",
-            "pinkie-promise": "^2.0.0",
-            "strip-bom": "^2.0.0"
-          }
-        },
-        "parse-json": {
-          "version": "2.2.0",
-          "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
-          "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
-          "dev": true,
-          "requires": {
-            "error-ex": "^1.2.0"
-          }
-        },
-        "path-type": {
-          "version": "1.1.0",
-          "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
-          "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
-          "dev": true,
-          "requires": {
-            "graceful-fs": "^4.1.2",
-            "pify": "^2.0.0",
-            "pinkie-promise": "^2.0.0"
-          }
-        },
-        "pify": {
-          "version": "2.3.0",
-          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
-          "dev": true
-        },
-        "read-pkg": {
-          "version": "1.1.0",
-          "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
-          "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
-          "dev": true,
-          "requires": {
-            "load-json-file": "^1.0.0",
-            "normalize-package-data": "^2.3.2",
-            "path-type": "^1.0.0"
-          }
-        },
-        "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,
-          "requires": {
-            "is-utf8": "^0.2.0"
-          }
-        }
       }
     },
     "readable-stream": {
@@ -1990,15 +1756,6 @@
         "util-deprecate": "~1.0.1"
       }
     },
-    "readdirp": {
-      "version": "3.3.0",
-      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz",
-      "integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==",
-      "dev": true,
-      "requires": {
-        "picomatch": "^2.0.7"
-      }
-    },
     "redent": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
@@ -2024,9 +1781,9 @@
       }
     },
     "request": {
-      "version": "2.88.0",
-      "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
-      "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
+      "version": "2.88.2",
+      "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
+      "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
       "dev": true,
       "requires": {
         "aws-sign2": "~0.7.0",
@@ -2036,7 +1793,7 @@
         "extend": "~3.0.2",
         "forever-agent": "~0.6.1",
         "form-data": "~2.3.2",
-        "har-validator": "~5.1.0",
+        "har-validator": "~5.1.3",
         "http-signature": "~1.2.0",
         "is-typedarray": "~1.0.0",
         "isstream": "~0.1.2",
@@ -2046,17 +1803,9 @@
         "performance-now": "^2.1.0",
         "qs": "~6.5.2",
         "safe-buffer": "^5.1.2",
-        "tough-cookie": "~2.4.3",
+        "tough-cookie": "~2.5.0",
         "tunnel-agent": "^0.6.0",
         "uuid": "^3.3.2"
-      },
-      "dependencies": {
-        "qs": {
-          "version": "6.5.2",
-          "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
-          "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
-          "dev": true
-        }
       }
     },
     "require-directory": {
@@ -2066,24 +1815,25 @@
       "dev": true
     },
     "require-main-filename": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
-      "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+      "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
       "dev": true
     },
     "resolve": {
-      "version": "1.14.1",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.14.1.tgz",
-      "integrity": "sha512-fn5Wobh4cxbLzuHaE+nphztHy43/b++4M6SsGFC2gB8uYwf0C8LcarfCz1un7UTW8OFQg9iNjZ4xpcFVGebDPg==",
+      "version": "1.20.0",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
+      "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
       "dev": true,
       "requires": {
+        "is-core-module": "^2.2.0",
         "path-parse": "^1.0.6"
       }
     },
     "rimraf": {
-      "version": "2.7.1",
-      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
-      "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+      "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
       "dev": true,
       "requires": {
         "glob": "^7.1.3"
@@ -2094,12 +1844,6 @@
       "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz",
       "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q="
     },
-    "rx": {
-      "version": "2.3.24",
-      "resolved": "https://registry.npmjs.org/rx/-/rx-2.3.24.tgz",
-      "integrity": "sha1-FPlQpCF9fjXapxu8vljv9o6ksrc=",
-      "dev": true
-    },
     "safe-buffer": {
       "version": "5.1.2",
       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
@@ -2112,63 +1856,15 @@
       "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
     },
     "sass-graph": {
-      "version": "2.2.4",
-      "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz",
-      "integrity": "sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=",
+      "version": "2.2.5",
+      "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.5.tgz",
+      "integrity": "sha512-VFWDAHOe6mRuT4mZRd4eKE+d8Uedrk6Xnh7Sh9b4NGufQLQjOrvf/MQoOdx+0s92L89FeyUUNfU597j/3uNpag==",
       "dev": true,
       "requires": {
         "glob": "^7.0.0",
         "lodash": "^4.0.0",
         "scss-tokenizer": "^0.2.3",
-        "yargs": "^7.0.0"
-      },
-      "dependencies": {
-        "camelcase": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
-          "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
-          "dev": true
-        },
-        "yargs": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz",
-          "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=",
-          "dev": true,
-          "requires": {
-            "camelcase": "^3.0.0",
-            "cliui": "^3.2.0",
-            "decamelize": "^1.1.1",
-            "get-caller-file": "^1.0.1",
-            "os-locale": "^1.4.0",
-            "read-pkg-up": "^1.0.1",
-            "require-directory": "^2.1.1",
-            "require-main-filename": "^1.0.1",
-            "set-blocking": "^2.0.0",
-            "string-width": "^1.0.2",
-            "which-module": "^1.0.0",
-            "y18n": "^3.2.1",
-            "yargs-parser": "^5.0.0"
-          }
-        },
-        "yargs-parser": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz",
-          "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=",
-          "dev": true,
-          "requires": {
-            "camelcase": "^3.0.0"
-          }
-        }
-      }
-    },
-    "scope-css": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/scope-css/-/scope-css-1.2.1.tgz",
-      "integrity": "sha512-UjLRmyEYaDNiOS673xlVkZFlVCtckJR/dKgr434VMm7Lb+AOOqXKdAcY7PpGlJYErjXXJzKN7HWo4uRPiZZG0Q==",
-      "requires": {
-        "escaper": "^2.5.3",
-        "slugify": "^1.3.1",
-        "strip-css-comments": "^3.0.0"
+        "yargs": "^13.3.2"
       }
     },
     "scss-tokenizer": {
@@ -2179,6 +1875,17 @@
       "requires": {
         "js-base64": "^2.1.8",
         "source-map": "^0.4.2"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.4.4",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
+          "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
+          "dev": true,
+          "requires": {
+            "amdefine": ">=0.0.4"
+          }
+        }
       }
     },
     "semver": {
@@ -2194,39 +1901,30 @@
       "dev": true
     },
     "shebang-command": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
-      "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
       "dev": true,
       "requires": {
-        "shebang-regex": "^1.0.0"
+        "shebang-regex": "^3.0.0"
       }
     },
     "shebang-regex": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
-      "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
       "dev": true
     },
     "signal-exit": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
-      "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
+      "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
       "dev": true
     },
-    "slugify": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.4.0.tgz",
-      "integrity": "sha512-FtLNsMGBSRB/0JOE2A0fxlqjI6fJsgHGS13iTuVT28kViI4JjUiNqp/vyis0ZXYcMnpR3fzGNkv+6vRlI2GwdQ=="
-    },
     "source-map": {
-      "version": "0.4.4",
-      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
-      "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
-      "dev": true,
-      "requires": {
-        "amdefine": ">=0.0.4"
-      }
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
     },
     "source-map-support": {
       "version": "0.5.19",
@@ -2235,25 +1933,12 @@
       "requires": {
         "buffer-from": "^1.0.0",
         "source-map": "^0.6.0"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
-        }
       }
     },
-    "spawn-command": {
-      "version": "0.0.2-1",
-      "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz",
-      "integrity": "sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A=",
-      "dev": true
-    },
     "spdx-correct": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
-      "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
+      "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==",
       "dev": true,
       "requires": {
         "spdx-expression-parse": "^3.0.0",
@@ -2261,15 +1946,15 @@
       }
     },
     "spdx-exceptions": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
-      "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==",
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
+      "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
       "dev": true
     },
     "spdx-expression-parse": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
-      "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
+      "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
       "dev": true,
       "requires": {
         "spdx-exceptions": "^2.1.0",
@@ -2277,9 +1962,9 @@
       }
     },
     "spdx-license-ids": {
-      "version": "3.0.5",
-      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
-      "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==",
+      "version": "3.0.7",
+      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz",
+      "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==",
       "dev": true
     },
     "sshpk": {
@@ -2330,7 +2015,7 @@
     },
     "strip-ansi": {
       "version": "3.0.1",
-      "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
       "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
       "dev": true,
       "requires": {
@@ -2338,17 +2023,12 @@
       }
     },
     "strip-bom": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
-      "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
-      "dev": true
-    },
-    "strip-css-comments": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/strip-css-comments/-/strip-css-comments-3.0.0.tgz",
-      "integrity": "sha1-elYl7/iisibPiUehElTaluE9rok=",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
+      "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
+      "dev": true,
       "requires": {
-        "is-regexp": "^1.0.0"
+        "is-utf8": "^0.2.0"
       }
     },
     "strip-indent": {
@@ -2360,89 +2040,62 @@
         "get-stdin": "^4.0.1"
       }
     },
+    "stylis": {
+      "version": "3.5.4",
+      "resolved": "https://registry.npmjs.org/stylis/-/stylis-3.5.4.tgz",
+      "integrity": "sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q=="
+    },
     "supports-color": {
-      "version": "3.2.3",
-      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
-      "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
       "dev": true,
       "requires": {
-        "has-flag": "^1.0.0"
+        "has-flag": "^3.0.0"
+      }
+    },
+    "tar": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz",
+      "integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==",
+      "dev": true,
+      "requires": {
+        "chownr": "^2.0.0",
+        "fs-minipass": "^2.0.0",
+        "minipass": "^3.0.0",
+        "minizlib": "^2.1.1",
+        "mkdirp": "^1.0.3",
+        "yallist": "^4.0.0"
       },
       "dependencies": {
-        "has-flag": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
-          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+        "mkdirp": {
+          "version": "1.0.4",
+          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+          "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
           "dev": true
         }
       }
     },
-    "tar": {
-      "version": "2.2.2",
-      "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz",
-      "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==",
-      "dev": true,
-      "requires": {
-        "block-stream": "*",
-        "fstream": "^1.0.12",
-        "inherits": "2"
-      }
-    },
     "terser": {
-      "version": "4.6.13",
-      "resolved": "https://registry.npmjs.org/terser/-/terser-4.6.13.tgz",
-      "integrity": "sha512-wMvqukYgVpQlymbnNbabVZbtM6PN63AzqexpwJL8tbh/mRT9LE5o+ruVduAGL7D6Fpjl+Q+06U5I9Ul82odAhw==",
+      "version": "4.8.0",
+      "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz",
+      "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==",
       "requires": {
         "commander": "^2.20.0",
         "source-map": "~0.6.1",
         "source-map-support": "~0.5.12"
-      },
-      "dependencies": {
-        "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=="
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
-        }
-      }
-    },
-    "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,
-      "requires": {
-        "is-number": "^7.0.0"
       }
     },
     "tough-cookie": {
-      "version": "2.4.3",
-      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
-      "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
+      "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
       "dev": true,
       "requires": {
-        "psl": "^1.1.24",
-        "punycode": "^1.4.1"
-      },
-      "dependencies": {
-        "punycode": {
-          "version": "1.4.1",
-          "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
-          "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
-          "dev": true
-        }
+        "psl": "^1.1.28",
+        "punycode": "^2.1.1"
       }
     },
-    "tree-kill": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
-      "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
-      "dev": true
-    },
     "trim-newlines": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
@@ -2483,30 +2136,15 @@
       "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
       "dev": true
     },
-    "type-fest": {
-      "version": "0.8.1",
-      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
-      "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA=="
-    },
     "uglify-js": {
-      "version": "3.9.2",
-      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.9.2.tgz",
-      "integrity": "sha512-zGVwKslUAD/EeqOrD1nQaBmXIHl1Vw371we8cvS8I6mYK9rmgX5tv8AAeJdfsQ3Kk5mGax2SVV/AizxdNGhl7Q==",
-      "requires": {
-        "commander": "~2.20.3"
-      },
-      "dependencies": {
-        "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=="
-        }
-      }
+      "version": "3.12.7",
+      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.12.7.tgz",
+      "integrity": "sha512-SIZhkoh+U/wjW+BHGhVwE9nt8tWJspncloBcFapkpGRwNPqcH8pzX36BXe3TPBjzHWPMUZotpCigak/udWNr1Q=="
     },
     "universalify": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
-      "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+      "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
       "dev": true
     },
     "upper-case": {
@@ -2515,9 +2153,9 @@
       "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg="
     },
     "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==",
+      "version": "4.4.1",
+      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+      "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
       "dev": true,
       "requires": {
         "punycode": "^2.1.0"
@@ -2557,18 +2195,18 @@
       }
     },
     "which": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
-      "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
       "dev": true,
       "requires": {
         "isexe": "^2.0.0"
       }
     },
     "which-module": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
-      "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+      "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
       "dev": true
     },
     "wide-align": {
@@ -2581,13 +2219,48 @@
       }
     },
     "wrap-ansi": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
-      "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
+      "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
       "dev": true,
       "requires": {
-        "string-width": "^1.0.1",
-        "strip-ansi": "^3.0.1"
+        "ansi-styles": "^3.2.0",
+        "string-width": "^3.0.0",
+        "strip-ansi": "^5.0.0"
+      },
+      "dependencies": {
+        "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
+        },
+        "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
+        },
+        "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,
+          "requires": {
+            "emoji-regex": "^7.0.1",
+            "is-fullwidth-code-point": "^2.0.0",
+            "strip-ansi": "^5.1.0"
+          }
+        },
+        "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,
+          "requires": {
+            "ansi-regex": "^4.1.0"
+          }
+        }
       }
     },
     "wrappy": {
@@ -2597,161 +2270,82 @@
       "dev": true
     },
     "y18n": {
-      "version": "3.2.1",
-      "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
-      "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz",
+      "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==",
       "dev": true
     },
     "yallist": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
-      "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
       "dev": true
     },
     "yargs": {
-      "version": "15.1.0",
-      "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.1.0.tgz",
-      "integrity": "sha512-T39FNN1b6hCW4SOIk1XyTOWxtXdcen0t+XYrysQmChzSipvhBO8Bj0nK1ozAasdk24dNWuMZvr4k24nz+8HHLg==",
+      "version": "13.3.2",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
+      "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
       "dev": true,
       "requires": {
-        "cliui": "^6.0.0",
-        "decamelize": "^1.2.0",
-        "find-up": "^4.1.0",
+        "cliui": "^5.0.0",
+        "find-up": "^3.0.0",
         "get-caller-file": "^2.0.1",
         "require-directory": "^2.1.1",
         "require-main-filename": "^2.0.0",
         "set-blocking": "^2.0.0",
-        "string-width": "^4.2.0",
+        "string-width": "^3.0.0",
         "which-module": "^2.0.0",
         "y18n": "^4.0.0",
-        "yargs-parser": "^16.1.0"
+        "yargs-parser": "^13.1.2"
       },
       "dependencies": {
         "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
-        },
-        "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,
-          "requires": {
-            "@types/color-name": "^1.1.1",
-            "color-convert": "^2.0.1"
-          }
-        },
-        "cliui": {
-          "version": "6.0.0",
-          "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
-          "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
-          "dev": true,
-          "requires": {
-            "string-width": "^4.2.0",
-            "strip-ansi": "^6.0.0",
-            "wrap-ansi": "^6.2.0"
-          }
-        },
-        "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,
-          "requires": {
-            "color-name": "~1.1.4"
-          }
-        },
-        "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==",
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
           "dev": true
         },
         "find-up": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
-          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+          "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
           "dev": true,
           "requires": {
-            "locate-path": "^5.0.0",
-            "path-exists": "^4.0.0"
+            "locate-path": "^3.0.0"
           }
         },
-        "get-caller-file": {
-          "version": "2.0.5",
-          "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
-          "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
-          "dev": true
-        },
         "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
-        },
-        "path-exists": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
-          "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
-          "dev": true
-        },
-        "require-main-filename": {
           "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
-          "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
           "dev": true
         },
         "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==",
+          "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,
           "requires": {
-            "emoji-regex": "^8.0.0",
-            "is-fullwidth-code-point": "^3.0.0",
-            "strip-ansi": "^6.0.0"
+            "emoji-regex": "^7.0.1",
+            "is-fullwidth-code-point": "^2.0.0",
+            "strip-ansi": "^5.1.0"
           }
         },
         "strip-ansi": {
-          "version": "6.0.0",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
-          "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+          "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
           "dev": true,
           "requires": {
-            "ansi-regex": "^5.0.0"
+            "ansi-regex": "^4.1.0"
           }
-        },
-        "which-module": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
-          "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
-          "dev": true
-        },
-        "wrap-ansi": {
-          "version": "6.2.0",
-          "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
-          "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^4.0.0",
-            "string-width": "^4.1.0",
-            "strip-ansi": "^6.0.0"
-          }
-        },
-        "y18n": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
-          "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
-          "dev": true
         }
       }
     },
     "yargs-parser": {
-      "version": "16.1.0",
-      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-16.1.0.tgz",
-      "integrity": "sha512-H/V41UNZQPkUMIT5h5hiwg4QKIY1RPvoBV4XcjUbRM8Bk2oKqqyZ0DIEbTFZB0XjbtSPG8SAa/0DxCQmiRgzKg==",
+      "version": "13.1.2",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
+      "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
       "dev": true,
       "requires": {
         "camelcase": "^5.0.0",
diff --git a/infra/perfetto.dev/package.json b/infra/perfetto.dev/package.json
index 1607812..dbf62d1 100644
--- a/infra/perfetto.dev/package.json
+++ b/infra/perfetto.dev/package.json
@@ -10,22 +10,13 @@
     "mermaid": "^8.5.0"
   },
   "devDependencies": {
-    "concurrently": "^3.5.0",
+    "argparse": "^2.0.1",
     "ejs": "^3.0.1",
     "fs-extra": "^9.0.0",
     "highlight.js": "^10.1.2",
     "marked": "^0.8.0",
-    "node-sass": "^4.13.1",
-    "onchange": "^6.1.0",
-    "protobufjs": "^6.9.0",
-    "yargs": "^15.1.0"
-  },
-  "scripts": {
-    "clean": "../../tools/gn clean ../../out/perfetto.dev",
-    "setup": "ln -fns ../../out/perfetto.dev/site dist",
-    "serve": "npm run setup; dev_appserver.py .",
-    "build": "npm run setup; ../../tools/gn gen --args='' ../../out/perfetto.dev; ../../tools/ninja -C ../../out/perfetto.dev infra/perfetto.dev:node_modules; ../../tools/ninja -C ../../out/perfetto.dev site",
-    "watch": "onchange -v '../../docs/**' '**' '../../src/trace_processor/tables/**' '../../src/trace_processor/storage/stats.h' '../../protos/**' -e 'dist' -e 'dist/**' -- npm run build",
-    "start": "npm run build; concurrently \"npm run serve\" \"npm run watch\""
+    "node-sass": "^5.0.0",
+    "node-watch": "^0.7.1",
+    "protobufjs": "^6.9.0"
   }
 }
diff --git a/infra/perfetto.dev/redirect/.gcloudignore b/infra/perfetto.dev/redirect/.gcloudignore
deleted file mode 100644
index dba30e9..0000000
--- a/infra/perfetto.dev/redirect/.gcloudignore
+++ /dev/null
@@ -1,13 +0,0 @@
-__pycache__/
-.firebase/
-.firebaserc
-.gcloudignore
-.git
-.gitignore
-BUILD.gn
-deploy
-firebase-debug.log
-node_modules/
-package-lock.json
-package.json
-run-dev-server
diff --git a/infra/perfetto.dev/redirect/main.py b/infra/perfetto.dev/redirect/main.py
deleted file mode 100644
index 2b72cd3..0000000
--- a/infra/perfetto.dev/redirect/main.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2020 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from flask import Flask, redirect
-
-app = Flask(__name__)
-
-
-@app.route('/', defaults={'path': ''})
-@app.route('/<path:path>')
-def main(path):
-  return redirect('https://perfetto.dev/' + path)
-
-
-if __name__ == '__main__':
-  app.run(host='127.0.0.1', port=8080, debug=True)
diff --git a/infra/perfetto.dev/redirect/requirements.txt b/infra/perfetto.dev/redirect/requirements.txt
deleted file mode 100644
index 46a48dd..0000000
--- a/infra/perfetto.dev/redirect/requirements.txt
+++ /dev/null
@@ -1 +0,0 @@
-Flask==1.1.2
diff --git a/infra/perfetto.dev/run-dev-server b/infra/perfetto.dev/run-dev-server
index 83b9f96..6a213ad 100755
--- a/infra/perfetto.dev/run-dev-server
+++ b/infra/perfetto.dev/run-dev-server
@@ -1,5 +1,5 @@
 #!/bin/bash
-# Copyright (C) 2020 The Android Open Source Project
+# Copyright (C) 2021 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-set -e
-readonly CUR_DIR="$(cd -P ${BASH_SOURCE[0]%/*}; pwd)"
-readonly ROOT_DIR=$(dirname $(dirname "$CUR_DIR"))
-"$ROOT_DIR/tools/npm" run start
+set -eu
+CUR_DIR="$(cd -P ${BASH_SOURCE[0]%/*}; pwd)"
+$CUR_DIR/build --serve --watch
diff --git a/infra/perfetto.dev/src/markdown_render.js b/infra/perfetto.dev/src/markdown_render.js
index ebb34d8..4bad17b 100644
--- a/infra/perfetto.dev/src/markdown_render.js
+++ b/infra/perfetto.dev/src/markdown_render.js
@@ -200,7 +200,7 @@
     const templateData = {
       markdown: markdownHtml,
       title: title ? `${title} - Perfetto Tracing Docs` : fallbackTitle,
-      fileName: '/' + outFile.split('/').slice(1).join('/'),
+      fileName: '/' + path.relative(outDir, outFile),
     };
     if (fs.existsSync(navFilePath)) {
       templateData['nav'] = fs.readFileSync(navFilePath, 'utf8');
diff --git a/tools/install-build-deps b/tools/install-build-deps
index 581758e..6f5ceec 100755
--- a/tools/install-build-deps
+++ b/tools/install-build-deps
@@ -462,6 +462,7 @@
   parser.add_argument('--android', action='store_true')
   parser.add_argument('--ui', action='store_true')
   parser.add_argument('--check-only')
+  parser.add_argument('--filter', default='')
   parser.add_argument('--verify', help='Check all URLs', action='store_true')
   args = parser.parse_args()
   if args.verify:
@@ -482,6 +483,8 @@
     if (dep.target_platform != 'all' and
         dep.target_platform != system().lower()):
       continue
+    if args.filter and args.filter not in dep.target_folder:
+      continue
     local_path = os.path.join(ROOT_DIR, dep.target_folder)
     if dep.source_url.endswith('.git'):
       deps_updated |= CheckoutGitRepo(local_path, dep.source_url, dep.checksum,