Merge inbound to mozilla-central. a=merge
authorNarcis Beleuzu <nbeleuzu@mozilla.com>
Fri, 23 Mar 2018 11:51:38 +0200
changeset 463175 9cb650de48f9339b8b1499aeb9fe68f15f122aa2
parent 463114 9b72102a99b3a0177c7bd476c2d4ab96792520be (current diff)
parent 463174 7ce6b5f442f03c0f6fc886a8543ef823061c745b (diff)
child 463176 d2bf7b9c80a7f6a23f40d09f119d150e29a14d68
child 463185 42db8fd95d5fc5aa6ceebd0475535168b82af775
child 463223 c39cffd362b36b404f82a985e3c9a86cc5089faf
push id9165
push userasasaki@mozilla.com
push dateThu, 26 Apr 2018 21:04:54 +0000
treeherdermozilla-beta@064c3804de2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone61.0a1
first release with
nightly linux32
9cb650de48f9 / 61.0a1 / 20180323100142 / files
nightly linux64
9cb650de48f9 / 61.0a1 / 20180323100142 / files
nightly mac
9cb650de48f9 / 61.0a1 / 20180323100142 / files
nightly win32
9cb650de48f9 / 61.0a1 / 20180323100142 / files
nightly win64
9cb650de48f9 / 61.0a1 / 20180323100142 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
browser/base/content/test/performance/browser_appmenu_reflows.js
browser/base/content/test/performance/browser_tabclose_grow_reflows.js
browser/base/content/test/performance/browser_tabclose_reflows.js
browser/base/content/test/performance/browser_tabopen_reflows.js
browser/base/content/test/performance/browser_tabopen_squeeze_reflows.js
browser/base/content/test/performance/browser_tabstrip_overflow_underflow_reflows.js
browser/base/content/test/performance/browser_tabswitch_reflows.js
browser/base/content/test/performance/browser_urlbar_keyed_search_reflows.js
browser/base/content/test/performance/browser_urlbar_search_reflows.js
browser/base/content/test/performance/browser_window_resize_reflows.js
browser/base/content/test/performance/browser_windowclose_reflows.js
browser/base/content/test/performance/browser_windowopen_reflows.js
mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/NativePanZoomController.java
modules/libpref/init/all.js
--- a/accessible/generic/Accessible.h
+++ b/accessible/generic/Accessible.h
@@ -161,21 +161,17 @@ public:
    * Return frame for this accessible.
    */
   virtual nsIFrame* GetFrame() const;
 
   /**
    * Return DOM node associated with the accessible.
    */
   virtual nsINode* GetNode() const;
-  inline already_AddRefed<nsIDOMNode> DOMNode() const
-  {
-    nsCOMPtr<nsIDOMNode> DOMNode = do_QueryInterface(GetNode());
-    return DOMNode.forget();
-  }
+
   nsIContent* GetContent() const { return mContent; }
   mozilla::dom::Element* Elm() const
     { return mContent && mContent->IsElement() ? mContent->AsElement() : nullptr; }
 
   /**
    * Return node type information of DOM node associated with the accessible.
    */
   bool IsContent() const
--- a/accessible/ipc/win/ProxyAccessible.cpp
+++ b/accessible/ipc/win/ProxyAccessible.cpp
@@ -17,17 +17,17 @@
 #include "mozilla/Unused.h"
 #include "mozilla/a11y/Platform.h"
 #include "RelationType.h"
 #include "mozilla/a11y/Role.h"
 #include "xpcAccessibleDocument.h"
 
 #include <comutil.h>
 
-static const VARIANT kChildIdSelf = {VT_I4};
+static const VARIANT kChildIdSelf = {{{VT_I4}}};
 
 namespace mozilla {
 namespace a11y {
 
 bool
 ProxyAccessible::GetCOMInterface(void** aOutAccessible) const
 {
   if (!aOutAccessible) {
@@ -37,17 +37,17 @@ ProxyAccessible::GetCOMInterface(void** 
   if (!mCOMProxy && mSafeToRecurse) {
     // See if we can lazily obtain a COM proxy
     AccessibleWrap* wrap = WrapperFor(this);
     bool isDefunct = false;
     ProxyAccessible* thisPtr = const_cast<ProxyAccessible*>(this);
     // NB: Don't pass CHILDID_SELF here, use the absolute MSAA ID. Otherwise
     // GetIAccessibleFor will recurse into this function and we will just
     // overflow the stack.
-    VARIANT realId = {VT_I4};
+    VARIANT realId = {{{VT_I4}}};
     realId.ulVal = wrap->GetExistingID();
     thisPtr->mCOMProxy = wrap->GetIAccessibleFor(realId, &isDefunct);
   }
 
   RefPtr<IAccessible> addRefed = mCOMProxy;
   addRefed.forget(aOutAccessible);
   return !!mCOMProxy;
 }
--- a/accessible/ipc/win/handler/AccessibleHandler.cpp
+++ b/accessible/ipc/win/handler/AccessibleHandler.cpp
@@ -401,17 +401,17 @@ AccessibleHandler::QueryHandlerInterface
 
   if (aIid == IID_IProvideClassInfo) {
     RefPtr<IProvideClassInfo> clsInfo(this);
     clsInfo.forget(aOutInterface);
     return S_OK;
   }
 
   if (aIid == IID_IEnumVARIANT && mCachedData.mGeckoBackChannel) {
-    if (&mCachedData.mDynamicData.mChildCount == 0) {
+    if (mCachedData.mDynamicData.mChildCount == 0) {
       return E_NOINTERFACE;
     }
     RefPtr<IEnumVARIANT> childEnum(
       new HandlerChildEnumerator(this, mCachedData.mGeckoBackChannel));
     childEnum.forget(aOutInterface);
     return S_OK;
   }
 
--- a/accessible/xul/XULTabAccessible.cpp
+++ b/accessible/xul/XULTabAccessible.cpp
@@ -109,17 +109,17 @@ XULTabAccessible::RelationByType(Relatio
     return rel;
 
   // Expose 'LABEL_FOR' relation on tab accessible for tabpanel accessible.
   nsCOMPtr<nsIDOMXULRelatedElement> tabsElm =
     do_QueryInterface(mContent->GetParent());
   if (!tabsElm)
     return rel;
 
-  nsCOMPtr<nsIDOMNode> domNode(DOMNode());
+  nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(GetNode()));
   nsCOMPtr<nsIDOMNode> tabpanelNode;
   tabsElm->GetRelatedElement(domNode, getter_AddRefs(tabpanelNode));
   if (!tabpanelNode)
     return rel;
 
   nsCOMPtr<nsIContent> tabpanelContent(do_QueryInterface(tabpanelNode));
   rel.AppendTarget(mDoc, tabpanelContent);
   return rel;
@@ -196,17 +196,17 @@ XULTabpanelAccessible::RelationByType(Re
     return rel;
 
   // Expose 'LABELLED_BY' relation on tabpanel accessible for tab accessible.
   nsCOMPtr<nsIDOMXULRelatedElement> tabpanelsElm =
     do_QueryInterface(mContent->GetParent());
   if (!tabpanelsElm)
     return rel;
 
-  nsCOMPtr<nsIDOMNode> domNode(DOMNode());
+  nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(GetNode()));
   nsCOMPtr<nsIDOMNode> tabNode;
   tabpanelsElm->GetRelatedElement(domNode, getter_AddRefs(tabNode));
   if (!tabNode)
     return rel;
 
   nsCOMPtr<nsIContent> tabContent(do_QueryInterface(tabNode));
   rel.AppendTarget(mDoc, tabContent);
   return rel;
--- a/browser/base/content/browser-safebrowsing.js
+++ b/browser/base/content/browser-safebrowsing.js
@@ -24,20 +24,30 @@ var gSafeBrowsing = {
             .hidden = !isPhishingPage;
 
     // Now look at the currentURI to learn which page we were trying
     // to browse to.
     const uri = gBrowser.currentURI;
     const isReportablePage = uri && (uri.schemeIs("http") || uri.schemeIs("https"));
 
     const disabledByPolicy = !Services.policies.isAllowed("feedbackCommands");
-    document.getElementById("reportPhishingBroadcaster")
-            .disabled = disabledByPolicy || isPhishingPage || !isReportablePage;
-    document.getElementById("reportPhishingErrorBroadcaster")
-            .disabled = disabledByPolicy || !isPhishingPage || !isReportablePage;
+
+    const reportBroadcaster = document.getElementById("reportPhishingBroadcaster");
+    if (disabledByPolicy || isPhishingPage || !isReportablePage) {
+      reportBroadcaster.setAttribute("disabled", "true");
+    } else {
+      reportBroadcaster.removeAttribute("disabled");
+    }
+
+    const reportErrorBroadcaster = document.getElementById("reportPhishingErrorBroadcaster");
+    if (disabledByPolicy || !isPhishingPage || !isReportablePage) {
+      reportErrorBroadcaster.setAttribute("disabled", "true");
+    } else {
+      reportErrorBroadcaster.removeAttribute("disabled");
+    }
   },
 
   /**
    * Used to report a phishing page or a false positive
    *
    * @param name
    *        String One of "PhishMistake", "MalwareMistake", or "Phish"
    * @param info
--- a/browser/base/content/moz.build
+++ b/browser/base/content/moz.build
@@ -35,17 +35,17 @@ with Files("test/forms/**"):
     BUG_COMPONENT = ("Core", "Layout: Form Controls")
 
 with Files("test/pageinfo/**"):
     BUG_COMPONENT = ("Firefox", "Page Info Window")
 
 with Files("test/performance/**"):
     BUG_COMPONENT = ("Firefox", "General")
 
-with Files("test/performance/browser_appmenu_reflows.js"):
+with Files("test/performance/browser_appmenu.js"):
     BUG_COMPONENT = ("Firefox", "Menus")
 
 with Files("test/permissions/**"):
     BUG_COMPONENT = ("Firefox", "Preferences")
 
 with Files("test/plugins/**"):
     BUG_COMPONENT = ("Core", "Plug-ins")
 
--- a/browser/base/content/test/performance/browser.ini
+++ b/browser/base/content/test/performance/browser.ini
@@ -7,33 +7,31 @@
 prefs =
   # Skip migration work in BG__migrateUI for browser_startup.js since it isn't
   # representative of common startup.
   browser.migration.version=9999999
   browser.startup.record=true
   gfx.canvas.willReadFrequently.enable=true
 support-files =
   head.js
-[browser_appmenu_reflows.js]
-skip-if = asan || debug # Bug 1382809, bug 1369959
+[browser_appmenu.js]
+skip-if = asan || debug || (os == 'win' && bits == 32) # Bug 1382809, bug 1369959, Win32 because of intermittent OOM failures
 [browser_preferences_usage.js]
 skip-if = !debug
 [browser_startup.js]
 [browser_startup_content.js]
 skip-if = !e10s
 [browser_startup_flicker.js]
 run-if = debug || devedition || nightly_build # Requires startupRecorder.js, which isn't shipped everywhere by default
-[browser_tabclose_grow_reflows.js]
-[browser_tabclose_reflows.js]
-[browser_tabopen_reflows.js]
-[browser_tabopen_squeeze_reflows.js]
-[browser_tabstrip_overflow_underflow_reflows.js]
-[browser_tabswitch_reflows.js]
+[browser_tabclose_grow.js]
+[browser_tabclose.js]
+[browser_tabopen.js]
+[browser_tabopen_squeeze.js]
+[browser_tabstrip_overflow_underflow.js]
+[browser_tabswitch.js]
 [browser_toolbariconcolor_restyles.js]
-[browser_urlbar_keyed_search_reflows.js]
+[browser_urlbar_keyed_search.js]
 skip-if = (os == 'linux') || (os == 'win' && debug) # Disabled on Linux and Windows debug due to perma failures. Bug 1392320.
-[browser_urlbar_search_reflows.js]
+[browser_urlbar_search.js]
 skip-if = (debug || ccov) && (os == 'linux' || os == 'win') # Disabled on Linux and Windows debug and ccov due to intermittent timeouts. Bug 1414126, bug 1426611.
-[browser_window_resize_reflows.js]
-[browser_windowclose_reflows.js]
-[browser_windowopen_flicker.js]
-skip-if = (debug && os == 'win') # Disabled on windows debug for intermittent leaks
-[browser_windowopen_reflows.js]
+[browser_window_resize.js]
+[browser_windowclose.js]
+[browser_windowopen.js]
rename from browser/base/content/test/performance/browser_appmenu_reflows.js
rename to browser/base/content/test/performance/browser_appmenu.js
--- a/browser/base/content/test/performance/browser_appmenu_reflows.js
+++ b/browser/base/content/test/performance/browser_appmenu.js
@@ -44,27 +44,49 @@ const EXPECTED_APPMENU_OPEN_REFLOWS = [
 
     maxCount: 6, // This number should only ever go down - never up.
   },
 ];
 
 add_task(async function() {
   await ensureNoPreloadedBrowser();
 
+  let textBoxRect = document.getAnonymousElementByAttribute(gURLBar,
+    "anonid", "textbox-input-box").getBoundingClientRect();
+  let menuButtonRect =
+    document.getElementById("PanelUI-menu-button").getBoundingClientRect();
+  let frameExpectations = {
+    filter: rects => rects.filter(r => !(
+      // We expect the menu button to get into the active state.
+      r.y1 >= menuButtonRect.top && r.y2 <= menuButtonRect.bottom &&
+      r.x1 >= menuButtonRect.left && r.x2 <= menuButtonRect.right
+      // XXX For some reason the menu panel isn't in our screenshots,
+      // but that's where we actually expect many changes.
+    )),
+    exceptions: [
+      {name: "the urlbar placeolder moves up and down by a few pixels",
+       condition: r =>
+         r.x1 >= textBoxRect.left && r.x2 <= textBoxRect.right &&
+         r.y1 >= textBoxRect.top && r.y2 <= textBoxRect.bottom
+      }
+    ]
+  };
+
   // First, open the appmenu.
-  await withReflowObserver(async function() {
+  await withPerfObserver(async function() {
     let popupShown =
       BrowserTestUtils.waitForEvent(PanelUI.panel, "popupshown");
     await PanelUI.show();
     await popupShown;
-  }, EXPECTED_APPMENU_OPEN_REFLOWS);
+  }, {expectedReflows: EXPECTED_APPMENU_OPEN_REFLOWS,
+      frames: frameExpectations});
 
   // Now open a series of subviews, and then close the appmenu. We
   // should not reflow during any of this.
-  await withReflowObserver(async function() {
+  await withPerfObserver(async function() {
     // This recursive function will take the current main or subview,
     // find all of the buttons that navigate to subviews inside it,
     // and click each one individually. Upon entering the new view,
     // we recurse. When the subviews within a view have been
     // exhausted, we go back up a level.
     async function openSubViewsRecursively(currentView) {
       let navButtons = Array.from(currentView.querySelectorAll(".subviewbutton-nav"));
       if (!navButtons) {
@@ -98,10 +120,10 @@ add_task(async function() {
       }
     }
 
     await openSubViewsRecursively(PanelUI.mainView);
 
     let hidden = BrowserTestUtils.waitForEvent(PanelUI.panel, "popuphidden");
     PanelUI.hide();
     await hidden;
-  }, []);
+  }, {expectedReflows: [], frames: frameExpectations});
 });
rename from browser/base/content/test/performance/browser_tabclose_reflows.js
rename to browser/base/content/test/performance/browser_tabclose.js
--- a/browser/base/content/test/performance/browser_tabclose_reflows.js
+++ b/browser/base/content/test/performance/browser_tabclose.js
@@ -17,21 +17,74 @@ const EXPECTED_REFLOWS = [
 
 /*
  * This test ensures that there are no unexpected
  * uninterruptible reflows when closing new tabs.
  */
 add_task(async function() {
   await ensureNoPreloadedBrowser();
 
+  let firstTabRect = gBrowser.selectedTab.getBoundingClientRect();
+
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
   await BrowserTestUtils.waitForCondition(() => tab._fullyOpen);
 
+  let tabStripRect = gBrowser.tabContainer.arrowScrollbox.getBoundingClientRect();
+  let newTabButtonRect =
+    document.getAnonymousElementByAttribute(gBrowser.tabContainer,
+                                            "anonid", "tabs-newtab-button")
+            .getBoundingClientRect();
+
   // Add a reflow observer and open a new tab.
-  await withReflowObserver(async function() {
+  await withPerfObserver(async function() {
     let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone");
     gBrowser.removeTab(tab, { animate: true });
     await BrowserTestUtils.waitForEvent(tab, "transitionend",
         false, e => e.propertyName === "max-width");
     await switchDone;
-  }, EXPECTED_REFLOWS);
+  }, {expectedReflows: EXPECTED_REFLOWS,
+      frames: {
+        filter: rects => rects.filter(r => !(
+          // We expect all changes to be within the tab strip.
+          r.y1 >= tabStripRect.top && r.y2 <= tabStripRect.bottom &&
+          r.x1 >= tabStripRect.left && r.x2 <= tabStripRect.right && (
+          // The closed tab should disappear at the same time as the previous
+          // tab gets selected, causing both tab areas to change color at once:
+          // this should be a single rect of the width of 2 tabs, and can
+          // include the '+' button if it starts its animation.
+          (r.w > gBrowser.selectedTab.clientWidth &&
+           r.x2 <= newTabButtonRect.right) ||
+          // The '+' icon moves with an animation. At the end of the animation
+          // the former and new positions can touch each other causing the rect
+          // to have twice the icon's width.
+          (r.h == 14 && r.w <= 2 * 14 + kMaxEmptyPixels) ||
+          // We sometimes have a rect for the right most 2px of the '+' button.
+          (r.h == 2 && r.w == 2)
+        ))),
+        exceptions: [
+          {name: "bug 1444886 - the next tab should be selected at the same time" +
+                 " as the closed one disappears",
+           condition: r =>
+             // In tab strip
+             r.y1 >= tabStripRect.top && r.y2 <= tabStripRect.bottom &&
+             r.x1 >= tabStripRect.left && r.x2 <= tabStripRect.right &&
+             // Width of one tab.
+             r.w == gBrowser.selectedTab.clientWidth
+          },
+          {name: "bug 1446454 - the border between tabs should be painted at" +
+                 " the same time as the tab switch",
+           condition: r =>
+             // In tab strip
+             r.y1 >= tabStripRect.top && r.y2 <= tabStripRect.bottom &&
+             // 1px border, 1px before the end of the first tab.
+             r.w == 1 && r.x1 == firstTabRect.right - 1
+          },
+          {name: "bug 1446449 - spurious tab switch spinner",
+           condition: r =>
+             AppConstants.DEBUG &&
+             // In the content area
+             r.y1 >= document.getElementById("appcontent").getBoundingClientRect().top
+          },
+        ]
+      }
+     });
   is(EXPECTED_REFLOWS.length, 0, "No reflows are expected when closing a tab");
 });
rename from browser/base/content/test/performance/browser_tabclose_grow_reflows.js
rename to browser/base/content/test/performance/browser_tabclose_grow.js
--- a/browser/base/content/test/performance/browser_tabclose_grow_reflows.js
+++ b/browser/base/content/test/performance/browser_tabclose_grow.js
@@ -34,19 +34,34 @@ add_task(async function() {
   // remaining tabs will grow to fill the remaining space in the
   // tabstrip.
   const TAB_COUNT_FOR_GROWTH = computeMaxTabCount();
   await createTabs(TAB_COUNT_FOR_GROWTH);
 
   let lastTab = gBrowser.tabs[gBrowser.tabs.length - 1];
   await BrowserTestUtils.switchTab(gBrowser, lastTab);
 
-  await withReflowObserver(async function() {
+  let tabStripRect = gBrowser.tabContainer.arrowScrollbox.getBoundingClientRect();
+
+  await withPerfObserver(async function() {
     let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone");
     let tab = gBrowser.tabs[gBrowser.tabs.length - 1];
     gBrowser.removeTab(tab, { animate: true });
     await BrowserTestUtils.waitForEvent(tab, "transitionend",
       false, e => e.propertyName === "max-width");
     await switchDone;
-  }, EXPECTED_REFLOWS);
+  }, {expectedReflows: EXPECTED_REFLOWS,
+      frames: {
+        filter: rects => rects.filter(r => !(
+          // We expect plenty of changed rects within the tab strip.
+          r.y1 >= tabStripRect.top && r.y2 <= tabStripRect.bottom &&
+          r.x1 >= tabStripRect.left && r.x2 <= tabStripRect.right &&
+          // It would make sense for each rect to have a width smaller than
+          // a tab (ie. tabstrip.width / tabcount), but tabs are small enough
+          // that they sometimes get reported in the same rect.
+          // So we accept up to the width of n-1 tabs.
+          r.w <= (gBrowser.tabs.length - 1) * Math.ceil(tabStripRect.width / gBrowser.tabs.length)
+        ))
+      }
+     });
 
   await removeAllButFirstTab();
 });
rename from browser/base/content/test/performance/browser_tabopen_reflows.js
rename to browser/base/content/test/performance/browser_tabopen.js
--- a/browser/base/content/test/performance/browser_tabopen_reflows.js
+++ b/browser/base/content/test/performance/browser_tabopen.js
@@ -8,37 +8,87 @@
  * is a whitelist that should slowly go away as we improve the performance of
  * the front-end. Instead of adding more reflows to the whitelist, you should
  * be modifying your code to avoid the reflow.
  *
  * See https://developer.mozilla.org/en-US/Firefox/Performance_best_practices_for_Firefox_fe_engineers
  * for tips on how to do that.
  */
 const EXPECTED_REFLOWS = [
-  // selection change notification may cause querying the focused editor content
-  // by IME and that will cause reflow.
-  {
-    stack: [
-      "select@chrome://global/content/bindings/textbox.xml",
-    ],
-  }
+  /**
+   * Nothing here! Please don't add anything new!
+   */
 ];
 
 /*
  * This test ensures that there are no unexpected
  * uninterruptible reflows when opening new tabs.
  */
 add_task(async function() {
   await ensureNoPreloadedBrowser();
 
+  // Prepare the window to avoid flicker and reflow that's unrelated to our
+  // tab opening operation.
+  await ensureFocusedUrlbar();
+
+  let tabStripRect = gBrowser.tabContainer.arrowScrollbox.getBoundingClientRect();
+  let firstTabRect = gBrowser.selectedTab.getBoundingClientRect();
+  let textBoxRect = document.getAnonymousElementByAttribute(gURLBar,
+    "anonid", "textbox-input-box").getBoundingClientRect();
+  let inRange = (val, min, max) => min <= val && val <= max;
+
   // Add a reflow observer and open a new tab.
-  await withReflowObserver(async function() {
+  await withPerfObserver(async function() {
     let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone");
     BrowserOpenTab();
     await BrowserTestUtils.waitForEvent(gBrowser.selectedTab, "transitionend",
-        false, e => e.propertyName === "max-width");
+                                        false, e => e.propertyName === "max-width");
     await switchDone;
-  }, EXPECTED_REFLOWS);
+  }, {expectedReflows: EXPECTED_REFLOWS,
+      frames: {
+        filter: rects => rects.filter(r => !(
+          // We expect all changes to be within the tab strip.
+          r.y1 >= tabStripRect.top && r.y2 <= tabStripRect.bottom &&
+          r.x1 >= tabStripRect.left && r.x2 <= tabStripRect.right && (
+          // The first tab should get deselected at the same time as the next
+          // tab starts appearing, so we should have one rect that includes the
+          // first tab but is wider.
+          (inRange(r.w, firstTabRect.width, firstTabRect.width * 2) &&
+           r.x1 == firstTabRect.x) ||
+          // The second tab gets painted several times due to tabopen animation.
+          (inRange(r.x1, firstTabRect.right - 1, // -1 for the border on Win7
+                   firstTabRect.right + firstTabRect.width) &&
+           r.x2 < firstTabRect.right + firstTabRect.width +
+                  25) || // The + 25 is because sometimes the '+' is in the same rect.
+          // The '+' icon moves with an animation. At the end of the animation
+          // the former and new positions can touch each other causing the rect
+          // to have twice the icon's width.
+          (r.h == 14 && r.w <= 2 * 14 + kMaxEmptyPixels) ||
+          // We sometimes have a rect for the right most 2px of the '+' button.
+          (r.h == 2 && r.w == 2) ||
+          // Same for the 'X' icon.
+          (r.h == 10 && r.w <= 2 * 10)
+        ))),
+        exceptions: [
+          {name: "bug 1446452 - the new tab should appear at the same time as the" +
+                 " previous one gets deselected",
+           condition: r =>
+             // In tab strip
+             r.y1 >= tabStripRect.top && r.y2 <= tabStripRect.bottom &&
+             // Position and size of the first tab.
+             r.x1 == firstTabRect.left &&
+             inRange(r.w, firstTabRect.width - 1, // -1 as the border doesn't change
+                     firstTabRect.width)
+          },
+          {name: "the urlbar placeolder moves up and down by a few pixels",
+           // This seems to only happen on the second run in --verify
+           condition: r =>
+             r.x1 >= textBoxRect.left && r.x2 <= textBoxRect.right &&
+             r.y1 >= textBoxRect.top && r.y2 <= textBoxRect.bottom
+          }
+        ]
+      }
+     });
 
   let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone");
   BrowserTestUtils.removeTab(gBrowser.selectedTab);
   await switchDone;
 });
rename from browser/base/content/test/performance/browser_tabopen_squeeze_reflows.js
rename to browser/base/content/test/performance/browser_tabopen_squeeze.js
--- a/browser/base/content/test/performance/browser_tabopen_squeeze_reflows.js
+++ b/browser/base/content/test/performance/browser_tabopen_squeeze.js
@@ -5,23 +5,19 @@
  * is a whitelist that should slowly go away as we improve the performance of
  * the front-end. Instead of adding more reflows to the whitelist, you should
  * be modifying your code to avoid the reflow.
  *
  * See https://developer.mozilla.org/en-US/Firefox/Performance_best_practices_for_Firefox_fe_engineers
  * for tips on how to do that.
  */
 const EXPECTED_REFLOWS = [
-  {
-    stack: [
-      "select@chrome://global/content/bindings/textbox.xml",
-      "focusAndSelectUrlBar@chrome://browser/content/browser.js",
-      "_adjustFocusAfterTabSwitch@chrome://browser/content/tabbrowser.js",
-    ],
-  }
+  /**
+   * Nothing here! Please don't add anything new!
+   */
 ];
 
 /*
  * This test ensures that there are no unexpected
  * uninterruptible reflows when opening a new tab that will
  * cause the existing tabs to squeeze smaller.
  */
 add_task(async function() {
@@ -30,18 +26,44 @@ add_task(async function() {
   // Compute the number of tabs we can put into the strip without
   // overflowing, and remove one, so that we can create
   // TAB_COUNT_FOR_SQUEEE tabs, and then one more, which should
   // cause the tab to squeeze to a smaller size rather than overflow.
   const TAB_COUNT_FOR_SQUEEZE = computeMaxTabCount() - 1;
 
   await createTabs(TAB_COUNT_FOR_SQUEEZE);
 
-  await withReflowObserver(async function() {
+  await ensureFocusedUrlbar();
+
+  let tabStripRect = gBrowser.tabContainer.arrowScrollbox.getBoundingClientRect();
+  let textBoxRect = document.getAnonymousElementByAttribute(gURLBar,
+    "anonid", "textbox-input-box").getBoundingClientRect();
+
+  await withPerfObserver(async function() {
     let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone");
     BrowserOpenTab();
     await BrowserTestUtils.waitForEvent(gBrowser.selectedTab, "transitionend",
       false, e => e.propertyName === "max-width");
     await switchDone;
-  }, EXPECTED_REFLOWS);
+  }, {expectedReflows: EXPECTED_REFLOWS,
+      frames: {
+        filter: rects => rects.filter(r => !(
+          // We expect plenty of changed rects within the tab strip.
+          r.y1 >= tabStripRect.top && r.y2 <= tabStripRect.bottom &&
+          r.x1 >= tabStripRect.left && r.x2 <= tabStripRect.right &&
+          // It would make sense for each rect to have a width smaller than
+          // a tab (ie. tabstrip.width / tabcount), but tabs are small enough
+          // that they sometimes get reported in the same rect.
+          // So we accept up to the width of n-1 tabs.
+          r.w <= (gBrowser.tabs.length - 1) * Math.ceil(tabStripRect.width / gBrowser.tabs.length)
+        )),
+        exceptions: [
+          {name: "the urlbar placeolder moves up and down by a few pixels",
+           condition: r =>
+             r.x1 >= textBoxRect.left && r.x2 <= textBoxRect.right &&
+             r.y1 >= textBoxRect.top && r.y2 <= textBoxRect.bottom
+          }
+        ]
+      }
+     });
 
   await removeAllButFirstTab();
 });
rename from browser/base/content/test/performance/browser_tabstrip_overflow_underflow_reflows.js
rename to browser/base/content/test/performance/browser_tabstrip_overflow_underflow.js
--- a/browser/base/content/test/performance/browser_tabstrip_overflow_underflow_reflows.js
+++ b/browser/base/content/test/performance/browser_tabstrip_overflow_underflow.js
@@ -5,23 +5,19 @@
  * is a whitelist that should slowly go away as we improve the performance of
  * the front-end. Instead of adding more reflows to the whitelist, you should
  * be modifying your code to avoid the reflow.
  *
  * See https://developer.mozilla.org/en-US/Firefox/Performance_best_practices_for_Firefox_fe_engineers
  * for tips on how to do that.
  */
 const EXPECTED_OVERFLOW_REFLOWS = [
-  {
-    stack: [
-      "select@chrome://global/content/bindings/textbox.xml",
-      "focusAndSelectUrlBar@chrome://browser/content/browser.js",
-      "_adjustFocusAfterTabSwitch@chrome://browser/content/tabbrowser.js",
-    ]
-  },
+  /**
+   * Nothing here! Please don't add anything new!
+   */
 ];
 
 const EXPECTED_UNDERFLOW_REFLOWS = [
   /**
    * Nothing here! Please don't add anything new!
    */
 ];
 
@@ -34,66 +30,92 @@ const EXPECTED_UNDERFLOW_REFLOWS = [
  */
 add_task(async function() {
   await ensureNoPreloadedBrowser();
 
   const TAB_COUNT_FOR_OVERFLOW = computeMaxTabCount();
 
   await createTabs(TAB_COUNT_FOR_OVERFLOW);
 
-  await withReflowObserver(async function(dirtyFrame) {
+  await ensureFocusedUrlbar();
+
+  let tabStripRect = gBrowser.tabContainer.arrowScrollbox.getBoundingClientRect();
+  let textBoxRect = document.getAnonymousElementByAttribute(gURLBar,
+    "anonid", "textbox-input-box").getBoundingClientRect();
+  let ignoreTabstripRects = {
+    filter: rects => rects.filter(r => !(
+      // We expect plenty of changed rects within the tab strip.
+      r.y1 >= tabStripRect.top && r.y2 <= tabStripRect.bottom &&
+      r.x1 >= tabStripRect.left && r.x2 <= tabStripRect.right
+    )),
+    exceptions: [
+      {name: "the urlbar placeolder moves up and down by a few pixels",
+       condition: r =>
+         r.x1 >= textBoxRect.left && r.x2 <= textBoxRect.right &&
+         r.y1 >= textBoxRect.top && r.y2 <= textBoxRect.bottom
+      },
+      {name: "bug 1446449 - spurious tab switch spinner",
+       condition: r =>
+         AppConstants.DEBUG &&
+         // In the content area
+         r.y1 >= document.getElementById("appcontent").getBoundingClientRect().top
+      },
+    ]
+  };
+
+  await withPerfObserver(async function() {
     let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone");
     BrowserOpenTab();
     await BrowserTestUtils.waitForEvent(gBrowser.selectedTab, "transitionend",
         false, e => e.propertyName === "max-width");
     await switchDone;
     await BrowserTestUtils.waitForCondition(() => {
       return gBrowser.tabContainer.arrowScrollbox.hasAttribute("scrolledtoend");
     });
-  }, EXPECTED_OVERFLOW_REFLOWS, window);
+  }, {expectedReflows: EXPECTED_OVERFLOW_REFLOWS, frames: ignoreTabstripRects});
 
   Assert.ok(gBrowser.tabContainer.hasAttribute("overflow"),
             "Tabs should now be overflowed.");
 
   // Now test that opening and closing a tab while overflowed doesn't cause
   // us to reflow.
-  await withReflowObserver(async function(dirtyFrame) {
+  await withPerfObserver(async function() {
     let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone");
     BrowserOpenTab();
     await switchDone;
     await BrowserTestUtils.waitForCondition(() => {
       return gBrowser.tabContainer.arrowScrollbox.hasAttribute("scrolledtoend");
     });
-  }, [], window);
+  }, {expectedReflows: [], frames: ignoreTabstripRects});
 
-  await withReflowObserver(async function(dirtyFrame) {
+  await withPerfObserver(async function() {
     let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone");
     BrowserTestUtils.removeTab(gBrowser.selectedTab, { animate: true });
     await switchDone;
-  }, [], window);
+  }, {expectedReflows: [], frames: ignoreTabstripRects});
 
   // At this point, we have an overflowed tab strip, and we've got the last tab
   // selected. This should mean that the first tab is scrolled out of view.
   // Let's test that we don't reflow when switching to that first tab.
   let lastTab = gBrowser.selectedTab;
   let arrowScrollbox = gBrowser.tabContainer.arrowScrollbox;
 
   // First, we'll check that the first tab is actually scrolled
   // at least partially out of view.
   Assert.ok(arrowScrollbox.scrollPosition > 0,
             "First tab should be partially scrolled out of view.");
 
   // Now switch to the first tab. We shouldn't flush layout at all.
-  await withReflowObserver(async function(dirtyFrame) {
+  await withPerfObserver(async function() {
     let firstTab = gBrowser.tabContainer.firstChild;
     await BrowserTestUtils.switchTab(gBrowser, firstTab);
     await BrowserTestUtils.waitForCondition(() => {
       return gBrowser.tabContainer.arrowScrollbox.hasAttribute("scrolledtostart");
     });
-  }, [], window);
+  }, {expectedReflows: [], frames: ignoreTabstripRects});
 
   // Okay, now close the last tab. The tabstrip should stay overflowed, but removing
   // one more after that should underflow it.
   BrowserTestUtils.removeTab(lastTab);
 
   Assert.ok(gBrowser.tabContainer.hasAttribute("overflow"),
             "Tabs should still be overflowed.");
 
@@ -103,18 +125,19 @@ add_task(async function() {
   while (gBrowser.tabContainer.hasAttribute("overflow")) {
     lastTab = gBrowser.tabContainer.lastElementChild;
     if (gBrowser.selectedTab !== lastTab) {
       await BrowserTestUtils.switchTab(gBrowser, lastTab);
     }
 
     // ... and make sure we don't flush layout when closing it, and exiting
     // the overflowed state.
-    await withReflowObserver(async function() {
+    await withPerfObserver(async function() {
       let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone");
       BrowserTestUtils.removeTab(lastTab, { animate: true });
       await switchDone;
       await BrowserTestUtils.waitForCondition(() => !lastTab.isConnected);
-    }, EXPECTED_UNDERFLOW_REFLOWS, window);
+    }, {expectedReflows: EXPECTED_UNDERFLOW_REFLOWS,
+        frames: ignoreTabstripRects});
   }
 
   await removeAllButFirstTab();
 });
rename from browser/base/content/test/performance/browser_tabswitch_reflows.js
rename to browser/base/content/test/performance/browser_tabswitch.js
--- a/browser/base/content/test/performance/browser_tabswitch_reflows.js
+++ b/browser/base/content/test/performance/browser_tabswitch.js
@@ -32,16 +32,49 @@ add_task(async function() {
   Assert.equal(EXPECTED_REFLOWS.length, 0,
     "We shouldn't have added any new expected reflows.");
 
   let origTab = gBrowser.selectedTab;
   let firstSwitchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone");
   let otherTab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
   await firstSwitchDone;
 
-  await withReflowObserver(async function() {
+  let tabStripRect = gBrowser.tabContainer.arrowScrollbox.getBoundingClientRect();
+  let firstTabRect = origTab.getBoundingClientRect();
+  let inRange = (val, min, max) => min <= val && val <= max;
+
+  await withPerfObserver(async function() {
     let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone");
     gBrowser.selectedTab = origTab;
     await switchDone;
-  }, EXPECTED_REFLOWS);
+  }, {expectedReflows: EXPECTED_REFLOWS,
+      frames: {
+        filter: rects => rects.filter(r => !(
+          // We expect all changes to be within the tab strip.
+          r.y1 >= tabStripRect.top && r.y2 <= tabStripRect.bottom &&
+          r.x1 >= tabStripRect.left && r.x2 <= tabStripRect.right &&
+          // The tab selection changes between 2 adjacent tabs, so we expect
+          // both to change color at once: this should be a single rect of the
+          // width of 2 tabs.
+          inRange(r.w, (origTab.clientWidth - 1) * 2, // -1 for the border on Win7
+                  origTab.clientWidth * 2)
+        )),
+        exceptions: [
+          {name: "bug 1446454 - the border between tabs should be painted at" +
+                 " the same time as the tab switch",
+           condition: r =>
+             // In tab strip
+             r.y1 >= tabStripRect.top && r.y2 <= tabStripRect.bottom &&
+             // 1px border, 1px before the end of the first tab.
+             r.w == 1 && r.x1 == firstTabRect.right - 1
+          },
+          {name: "bug 1446449 - spurious tab switch spinner",
+           condition: r =>
+             AppConstants.DEBUG &&
+             // In the content area
+             r.y1 >= document.getElementById("appcontent").getBoundingClientRect().top
+          },
+        ]
+      }
+     });
 
   BrowserTestUtils.removeTab(otherTab);
 });
rename from browser/base/content/test/performance/browser_urlbar_keyed_search_reflows.js
rename to browser/base/content/test/performance/browser_urlbar_keyed_search.js
--- a/browser/base/content/test/performance/browser_urlbar_keyed_search_reflows.js
+++ b/browser/base/content/test/performance/browser_urlbar_keyed_search.js
@@ -122,42 +122,58 @@ add_task(async function() {
   let win = await prepareSettledWindow();
 
   let URLBar = win.gURLBar;
   let popup = URLBar.popup;
 
   URLBar.focus();
   URLBar.value = "";
 
-  await withReflowObserver(async function(dirtyFrameFn) {
+  let dropmarkerRect = document.getAnonymousElementByAttribute(gURLBar,
+    "anonid", "historydropmarker").getBoundingClientRect();
+  let textBoxRect = document.getAnonymousElementByAttribute(gURLBar,
+    "anonid", "textbox-input-box").getBoundingClientRect();
+
+  await withPerfObserver(async function() {
     let oldInvalidate = popup.invalidate.bind(popup);
     let oldResultsAdded = popup.onResultsAdded.bind(popup);
 
     // We need to invalidate the frame tree outside of the normal
     // mechanism since invalidations and result additions to the
     // URL bar occur without firing JS events (which is how we
     // normally know to dirty the frame tree).
     popup.invalidate = (reason) => {
-      dirtyFrameFn();
+      dirtyFrame(win);
       oldInvalidate(reason);
     };
 
     popup.onResultsAdded = () => {
-      dirtyFrameFn();
+      dirtyFrame(win);
       oldResultsAdded();
     };
 
     // Only keying in 6 characters because the number of reflows triggered
     // is so high that we risk timing out the test if we key in any more.
     const SEARCH_TERM = "ows-10";
     for (let i = 0; i < SEARCH_TERM.length; ++i) {
       let char = SEARCH_TERM[i];
       EventUtils.synthesizeKey(char, {}, win);
       await promiseSearchComplete(win);
     }
 
     let hiddenPromise = BrowserTestUtils.waitForEvent(URLBar.popup, "popuphidden");
     EventUtils.synthesizeKey("VK_ESCAPE", {}, win);
     await hiddenPromise;
-  }, EXPECTED_REFLOWS_FIRST_OPEN, win);
+  }, {expectedReflows: EXPECTED_REFLOWS_FIRST_OPEN,
+      frames: {filter: rects => rects.filter(r => !(
+        // We put text into the urlbar so expect its textbox to change.
+        (r.x1 >= textBoxRect.left && r.x2 <= textBoxRect.right &&
+         r.y1 >= textBoxRect.top && r.y2 <= textBoxRect.bottom) ||
+        // The dropmarker is replaced with the go arrow during the test.
+        // dropmarkerRect.left isn't always an integer, hence the - 1 and + 1
+        (r.x1 >= dropmarkerRect.left - 1 && r.x2 <= dropmarkerRect.right + 1 &&
+         r.y1 >= dropmarkerRect.top && r.y2 <= dropmarkerRect.bottom)
+        // XXX For some reason the awesomebar panel isn't in our screenshots,
+        // but that's where we actually expect many changes.
+      ))}}, win);
 
   await BrowserTestUtils.closeWindow(win);
 });
rename from browser/base/content/test/performance/browser_urlbar_search_reflows.js
rename to browser/base/content/test/performance/browser_urlbar_search.js
--- a/browser/base/content/test/performance/browser_urlbar_search_reflows.js
+++ b/browser/base/content/test/performance/browser_urlbar_search.js
@@ -139,38 +139,38 @@ add_task(async function setup() {
 add_task(async function() {
   let win = await prepareSettledWindow();
 
   let URLBar = win.gURLBar;
   let popup = URLBar.popup;
 
   URLBar.focus();
   URLBar.value = SEARCH_TERM;
-  let testFn = async function(dirtyFrameFn) {
+  let testFn = async function() {
     let oldInvalidate = popup.invalidate.bind(popup);
     let oldResultsAdded = popup.onResultsAdded.bind(popup);
     let oldSetTimeout = win.setTimeout;
 
     // We need to invalidate the frame tree outside of the normal
     // mechanism since invalidations and result additions to the
     // URL bar occur without firing JS events (which is how we
     // normally know to dirty the frame tree).
     popup.invalidate = (reason) => {
-      dirtyFrameFn();
+      dirtyFrame(win);
       oldInvalidate(reason);
     };
 
     popup.onResultsAdded = () => {
-      dirtyFrameFn();
+      dirtyFrame(win);
       oldResultsAdded();
     };
 
     win.setTimeout = (fn, ms) => {
       return oldSetTimeout(() => {
-        dirtyFrameFn();
+        dirtyFrame(win);
         fn();
       }, ms);
     };
 
     URLBar.controller.startSearch(URLBar.value);
     await BrowserTestUtils.waitForEvent(URLBar.popup, "popupshown");
     await BrowserTestUtils.waitForCondition(() => {
       return URLBar.controller.searchStatus >=
@@ -190,16 +190,36 @@ add_task(async function() {
     // especially if it's GC'ing from previous tests.
     await new Promise(resolve => win.requestIdleCallback(resolve, { timeout: 1000 }));
 
     let hiddenPromise = BrowserTestUtils.waitForEvent(URLBar.popup, "popuphidden");
     EventUtils.synthesizeKey("VK_ESCAPE", {}, win);
     await hiddenPromise;
   };
 
+  let dropmarkerRect = document.getAnonymousElementByAttribute(gURLBar,
+    "anonid", "historydropmarker").getBoundingClientRect();
+  let textBoxRect = document.getAnonymousElementByAttribute(gURLBar,
+    "anonid", "textbox-input-box").getBoundingClientRect();
+  let expectedRects = {
+    filter: rects => rects.filter(r => !(
+      // We put text into the urlbar so expect its textbox to change.
+      (r.x1 >= textBoxRect.left && r.x2 <= textBoxRect.right &&
+       r.y1 >= textBoxRect.top && r.y2 <= textBoxRect.bottom) ||
+      // The dropmarker is displayed as active during some of the test.
+      // dropmarkerRect.left isn't always an integer, hence the - 1 and + 1
+      (r.x1 >= dropmarkerRect.left - 1 && r.x2 <= dropmarkerRect.right + 1 &&
+       r.y1 >= dropmarkerRect.top && r.y2 <= dropmarkerRect.bottom)
+      // XXX For some reason the awesomebar panel isn't in our screenshots,
+      // but that's where we actually expect many changes.
+    ))
+  };
+
   info("First opening");
-  await withReflowObserver(testFn, EXPECTED_REFLOWS_FIRST_OPEN, win);
+  await withPerfObserver(testFn, {expectedReflows: EXPECTED_REFLOWS_FIRST_OPEN,
+                                  frames: expectedRects}, win);
 
   info("Second opening");
-  await withReflowObserver(testFn, EXPECTED_REFLOWS_SECOND_OPEN, win);
+  await withPerfObserver(testFn, {expectedReflows: EXPECTED_REFLOWS_SECOND_OPEN,
+                                  frames: expectedRects}, win);
 
   await BrowserTestUtils.closeWindow(win);
 });
rename from browser/base/content/test/performance/browser_window_resize_reflows.js
rename to browser/base/content/test/performance/browser_window_resize.js
--- a/browser/base/content/test/performance/browser_window_resize_reflows.js
+++ b/browser/base/content/test/performance/browser_window_resize.js
@@ -124,15 +124,15 @@ add_task(async function() {
       win.screen.availHeight < STARTING_HEIGHT) {
     Assert.ok(false, "This test is running on too small a display - " +
               `(${STARTING_WIDTH}x${STARTING_HEIGHT} min)`);
     return;
   }
 
   await resizeWindow(win, STARTING_WIDTH, STARTING_HEIGHT);
 
-  await withReflowObserver(async function() {
+  await withPerfObserver(async function() {
     await resizeWindow(win, SMALL_WIDTH, SMALL_HEIGHT);
     await resizeWindow(win, STARTING_WIDTH, STARTING_HEIGHT);
-  }, EXPECTED_REFLOWS, win);
+  }, {expectedReflows: EXPECTED_REFLOWS, frames: {filter: () => []}}, win);
 
   await BrowserTestUtils.closeWindow(win);
 });
rename from browser/base/content/test/performance/browser_windowclose_reflows.js
rename to browser/base/content/test/performance/browser_windowclose.js
--- a/browser/base/content/test/performance/browser_windowclose_reflows.js
+++ b/browser/base/content/test/performance/browser_windowclose.js
@@ -35,16 +35,26 @@ add_task(async function() {
   });
 
   // At the time of writing, there are no reflows on window closing.
   // Mochitest will fail if we have no assertions, so we add one here
   // to make sure nobody adds any new ones.
   Assert.equal(EXPECTED_REFLOWS.length, 0,
     "We shouldn't have added any new expected reflows for window close.");
 
-  await withReflowObserver(async function() {
+  let dropmarkerRect = document.getAnonymousElementByAttribute(gURLBar,
+    "anonid", "historydropmarker").getBoundingClientRect();
+
+  await withPerfObserver(async function() {
     let promiseOrigBrowserFocused = BrowserTestUtils.waitForCondition(() => {
       return Services.focus.activeWindow == window;
     });
     await BrowserTestUtils.closeWindow(win);
     await promiseOrigBrowserFocused;
-  }, EXPECTED_REFLOWS, win);
+  }, {expectedReflows: EXPECTED_REFLOWS, frames: {
+    filter: rects => rects.filter(r => !(
+      // The dropmarker is visible when the window opens and sometimes hasn't
+      // finished its transition to opacity: 0 by the time waitForFocus resolves.
+      (r.x1 >= dropmarkerRect.left - 1 && r.x2 <= dropmarkerRect.right + 1 &&
+       r.y1 >= dropmarkerRect.top && r.y2 <= dropmarkerRect.bottom)
+    ))
+  }}, win);
 });
rename from browser/base/content/test/performance/browser_windowopen_reflows.js
rename to browser/base/content/test/performance/browser_windowopen.js
--- a/browser/base/content/test/performance/browser_windowopen_reflows.js
+++ b/browser/base/content/test/performance/browser_windowopen.js
@@ -44,28 +44,91 @@ if (Services.appinfo.OS == "WINNT" || Se
       // These numbers should only ever go down - never up.
       maxCount: Services.appinfo.OS == "WINNT" ? 5 : 4,
     },
   );
 }
 
 /*
  * This test ensures that there are no unexpected
- * uninterruptible reflows when opening new windows.
+ * uninterruptible reflows or flickering areas when opening new windows.
  */
 add_task(async function() {
   // Flushing all caches helps to ensure that we get consistent
   // behaviour when opening a new window, even if windows have been
   // opened in previous tests.
   Services.obs.notifyObservers(null, "startupcache-invalidate");
   Services.obs.notifyObservers(null, "chrome-flush-skin-caches");
   Services.obs.notifyObservers(null, "chrome-flush-caches");
 
-  let win = OpenBrowserWindow();
+  let win = window.openDialog("chrome://browser/content/", "_blank",
+                              "chrome,all,dialog=no,remote,suppressanimation",
+                              "about:home");
+
+  let alreadyFocused = false;
+  let inRange = (val, min, max) => min <= val && val <= max;
+  let expectations = {
+    expectedReflows: EXPECTED_REFLOWS,
+    frames: {
+      filter(rects, frame, previousFrame) {
+        // The first screenshot we get in OSX / Windows shows an unfocused browser
+        // window for some reason. See bug 1445161.
+        //
+        // We'll assume the changes we are seeing are due to this focus change if
+        // there are at least 5 areas that changed near the top of the screen, but
+        // will only ignore this once (hence the alreadyFocused variable).
+        if (!alreadyFocused && rects.length > 5 && rects.every(r => r.y2 < 100)) {
+          alreadyFocused = true;
+          todo(false,
+               "bug 1445161 - the window should be focused at first paint, " +
+               rects.toSource());
+          return [];
+        }
 
-  await withReflowObserver(async function() {
+        return rects;
+      },
+      exceptions: [
+        {name: "bug 1421463 - reload toolbar icon shouldn't flicker",
+         condition: r => r.h == 13 && inRange(r.w, 14, 16) && // icon size
+                         inRange(r.y1, 40, 80) && // in the toolbar
+                         // near the left side of the screen
+                         // The reload icon is shifted on devedition builds
+                         // where there's an additional devtools toolbar icon.
+                         AppConstants.MOZ_DEV_EDITION ? inRange(r.x1, 100, 120) :
+                                                        inRange(r.x1, 65, 100)
+        },
+      ]
+    }
+  };
+
+  await withPerfObserver(async function() {
+    // Avoid showing the remotecontrol UI.
+    await new Promise(resolve => {
+      win.addEventListener("DOMContentLoaded", () => {
+        delete win.Marionette;
+        win.Marionette = {running: false};
+        resolve();
+      }, {once: true});
+    });
+
     await TestUtils.topicObserved("browser-delayed-startup-finished",
                                   subject => subject == win);
-  }, EXPECTED_REFLOWS, win);
+
+    await BrowserTestUtils.firstBrowserLoaded(win, false);
+    await BrowserTestUtils.browserStopped(win.gBrowser.selectedBrowser, "about:home");
+
+    await new Promise(resolve => {
+      // 10 is an arbitrary value here, it needs to be at least 2 to avoid
+      // races with code initializing itself using idle callbacks.
+      (function waitForIdle(count = 10) {
+        if (!count) {
+          resolve();
+          return;
+        }
+        Services.tm.idleDispatchToMainThread(() => {
+          waitForIdle(count - 1);
+        });
+      })();
+    });
+  }, expectations, win);
 
   await BrowserTestUtils.closeWindow(win);
 });
-
--- a/browser/base/content/test/performance/head.js
+++ b/browser/base/content/test/performance/head.js
@@ -1,26 +1,97 @@
 "use strict";
 
 ChromeUtils.defineModuleGetter(this, "PlacesUtils",
   "resource://gre/modules/PlacesUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "PlacesTestUtils",
   "resource://testing-common/PlacesTestUtils.jsm");
 
+
 /**
- * Async utility function for ensuring that no unexpected uninterruptible
- * reflows occur during some period of time in a window.
+ * This function can be called if the test needs to trigger frame dirtying
+ * outside of the normal mechanism.
+ *
+ * @param win (dom window)
+ *        The window in which the frame tree needs to be marked as dirty.
+ */
+function dirtyFrame(win) {
+  let dwu = win.QueryInterface(Ci.nsIInterfaceRequestor)
+               .getInterface(Ci.nsIDOMWindowUtils);
+  try {
+    dwu.ensureDirtyRootFrame();
+  } catch (e) {
+    // If this fails, we should probably make note of it, but it's not fatal.
+    info("Note: ensureDirtyRootFrame threw an exception:" + e);
+  }
+}
+
+/**
+ * Async utility function to collect the stacks of uninterruptible reflows
+ * occuring during some period of time in a window.
+ *
+ * @param testPromise (Promise)
+ *        A promise that is resolved when the data collection should stop.
+ *
+ * @param win (browser window, optional)
+ *        The browser window to monitor. Defaults to the current window.
  *
- * @param testFn (async function)
- *        The async function that will exercise the browser activity that is
- *        being tested for reflows.
+ * @return An array of reflow stacks
+ */
+async function recordReflows(testPromise, win = window) {
+  // Collect all reflow stacks, we'll process them later.
+  let reflows = [];
+
+  let observer = {
+    reflow(start, end) {
+      // Gather information about the current code path.
+      reflows.push(new Error().stack);
+
+      // Just in case, dirty the frame now that we've reflowed.
+      dirtyFrame(win);
+    },
+
+    reflowInterruptible(start, end) {
+      // Interruptible reflows are the reflows caused by the refresh
+      // driver ticking. These are fine.
+    },
+
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver,
+                                           Ci.nsISupportsWeakReference])
+  };
+
+  let docShell = win.QueryInterface(Ci.nsIInterfaceRequestor)
+                    .getInterface(Ci.nsIWebNavigation)
+                    .QueryInterface(Ci.nsIDocShell);
+  docShell.addWeakReflowObserver(observer);
+
+  let dirtyFrameFn = event => {
+    if (event.type != "MozAfterPaint") {
+      dirtyFrame(win);
+    }
+  };
+  Services.els.addListenerForAllEvents(win, dirtyFrameFn, true);
+
+  try {
+    dirtyFrame(win);
+    await testPromise;
+  } finally {
+    Services.els.removeListenerForAllEvents(win, dirtyFrameFn, true);
+    docShell.removeWeakReflowObserver(observer);
+  }
+
+  return reflows;
+}
+
+/**
+ * Utility function to report unexpected reflows.
  *
- *        The testFn will be passed a single argument, which is a frame dirtying
- *        function that can be called if the test needs to trigger frame
- *        dirtying outside of the normal mechanism.
+ * @param reflows (Array)
+ *        An array of reflow stacks returned by recordReflows.
+ *
  * @param expectedReflows (Array, optional)
  *        An Array of Objects representing reflows.
  *
  *        Example:
  *
  *        [
  *          {
  *            // This reflow is caused by lorem ipsum.
@@ -49,135 +120,85 @@ ChromeUtils.defineModuleGetter(this, "Pl
  *          }
  *        ]
  *
  *        Note that line numbers are not included in the stacks.
  *
  *        Order of the reflows doesn't matter. Expected reflows that aren't seen
  *        will cause an assertion failure. When this argument is not passed,
  *        it defaults to the empty Array, meaning no reflows are expected.
- * @param window (browser window, optional)
- *        The browser window to monitor. Defaults to the current window.
  */
-async function withReflowObserver(testFn, expectedReflows = [], win = window) {
-  let dwu = win.QueryInterface(Ci.nsIInterfaceRequestor)
-               .getInterface(Ci.nsIDOMWindowUtils);
-  let dirtyFrameFn = () => {
-    try {
-      dwu.ensureDirtyRootFrame();
-    } catch (e) {
-      // If this fails, we should probably make note of it, but it's not fatal.
-      info("Note: ensureDirtyRootFrame threw an exception.");
-    }
-  };
-
-  // Collect all reflow stacks, we'll process them later.
-  let reflows = [];
+function reportUnexpectedReflows(reflows, expectedReflows = []) {
+  let knownReflows = expectedReflows.map(r => {
+    return {stack: r.stack, path: r.stack.join("|"),
+            count: 0, maxCount: r.maxCount || 1,
+            actualStacks: new Map()};
+  });
+  let unexpectedReflows = new Map();
+  for (let stack of reflows) {
+    let path =
+      stack.split("\n").slice(1) // the first frame which is our test code.
+           .map(line => line.replace(/:\d+:\d+$/, "")) // strip line numbers.
+           .join("|");
 
-  let observer = {
-    reflow(start, end) {
-      // Gather information about the current code path.
-      reflows.push(new Error().stack);
-
-      // Just in case, dirty the frame now that we've reflowed.
-      dirtyFrameFn();
-    },
+    // Stack trace is empty. Reflow was triggered by native code, which
+    // we ignore.
+    if (path === "") {
+      continue;
+    }
 
-    reflowInterruptible(start, end) {
-      // Interruptible reflows are the reflows caused by the refresh
-      // driver ticking. These are fine.
-    },
-
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver,
-                                           Ci.nsISupportsWeakReference])
-  };
+    // synthesizeKey from EventUtils.js causes us to reflow. That's the test
+    // harness and we don't care about that, so we'll filter that out.
+    if (path.startsWith("synthesizeKey@chrome://mochikit/content/tests/SimpleTest/EventUtils.js")) {
+      continue;
+    }
 
-  let docShell = win.QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIWebNavigation)
-                    .QueryInterface(Ci.nsIDocShell);
-  docShell.addWeakReflowObserver(observer);
-
-  Services.els.addListenerForAllEvents(win, dirtyFrameFn, true);
+    let index = knownReflows.findIndex(reflow => path.startsWith(reflow.path));
+    if (index != -1) {
+      let reflow = knownReflows[index];
+      ++reflow.count;
+      reflow.actualStacks.set(stack, (reflow.actualStacks.get(stack) || 0) + 1);
+    } else {
+      unexpectedReflows.set(stack, (unexpectedReflows.get(stack) || 0) + 1);
+    }
+  }
 
-  try {
-    dirtyFrameFn();
-    await testFn(dirtyFrameFn);
-  } finally {
-    let knownReflows = expectedReflows.map(r => {
-      return {stack: r.stack, path: r.stack.join("|"),
-              count: 0, maxCount: r.maxCount || 1,
-              actualStacks: new Map()};
-    });
-    let unexpectedReflows = new Map();
-    for (let stack of reflows) {
-      let path =
-        stack.split("\n").slice(1) // the first frame which is our test code.
-             .map(line => line.replace(/:\d+:\d+$/, "")) // strip line numbers.
-             .join("|");
-
-      // Stack trace is empty. Reflow was triggered by native code, which
-      // we ignore.
-      if (path === "") {
-        continue;
+  let formatStack = stack =>
+    stack.split("\n").slice(1).map(frame => "  " + frame).join("\n");
+  for (let reflow of knownReflows) {
+    let firstFrame = reflow.stack[0];
+    if (!reflow.count) {
+      Assert.ok(false,
+                `Unused expected reflow at ${firstFrame}:\nStack:\n` +
+                reflow.stack.map(frame => "  " + frame).join("\n") + "\n" +
+                "This is probably a good thing - just remove it from the whitelist.");
+    } else {
+      if (reflow.count > reflow.maxCount) {
+        Assert.ok(false,
+                  `reflow at ${firstFrame} was encountered ${reflow.count} times,\n` +
+                  `it was expected to happen up to ${reflow.maxCount} times.`);
+      } else {
+        todo(false, `known reflow at ${firstFrame} was encountered ${reflow.count} times`);
       }
-
-      // synthesizeKey from EventUtils.js causes us to reflow. That's the test
-      // harness and we don't care about that, so we'll filter that out.
-      if (path.startsWith("synthesizeKey@chrome://mochikit/content/tests/SimpleTest/EventUtils.js")) {
-        continue;
-      }
-
-      let index = knownReflows.findIndex(reflow => path.startsWith(reflow.path));
-      if (index != -1) {
-        let reflow = knownReflows[index];
-        ++reflow.count;
-        reflow.actualStacks.set(stack, (reflow.actualStacks.get(stack) || 0) + 1);
-      } else {
-        unexpectedReflows.set(stack, (unexpectedReflows.get(stack) || 0) + 1);
+      for (let [stack, count] of reflow.actualStacks) {
+        info("Full stack" + (count > 1 ? ` (hit ${count} times)` : "") + ":\n" +
+             formatStack(stack));
       }
     }
-
-    let formatStack = stack =>
-      stack.split("\n").slice(1).map(frame => "  " + frame).join("\n");
-    for (let reflow of knownReflows) {
-      let firstFrame = reflow.stack[0];
-      if (!reflow.count) {
-        Assert.ok(false,
-                  `Unused expected reflow at ${firstFrame}:\nStack:\n` +
-                  reflow.stack.map(frame => "  " + frame).join("\n") + "\n" +
-                  "This is probably a good thing - just remove it from the whitelist.");
-      } else {
-        if (reflow.count > reflow.maxCount) {
-          Assert.ok(false,
-                    `reflow at ${firstFrame} was encountered ${reflow.count} times,\n` +
-                    `it was expected to happen up to ${reflow.maxCount} times.`);
+  }
 
-        } else {
-          todo(false, `known reflow at ${firstFrame} was encountered ${reflow.count} times`);
-        }
-        for (let [stack, count] of reflow.actualStacks) {
-          info("Full stack" + (count > 1 ? ` (hit ${count} times)` : "") + ":\n" +
-               formatStack(stack));
-        }
-      }
-    }
-
-    for (let [stack, count] of unexpectedReflows) {
-      let location = stack.split("\n")[1].replace(/:\d+:\d+$/, "");
-      Assert.ok(false,
-                `unexpected reflow at ${location} hit ${count} times\n` +
-                "Stack:\n" +
-                formatStack(stack));
-    }
-    Assert.ok(!unexpectedReflows.size,
-              unexpectedReflows.size + " unexpected reflows");
-
-    Services.els.removeListenerForAllEvents(win, dirtyFrameFn, true);
-    docShell.removeWeakReflowObserver(observer);
+  for (let [stack, count] of unexpectedReflows) {
+    let location = stack.split("\n")[1].replace(/:\d+:\d+$/, "");
+    Assert.ok(false,
+              `unexpected reflow at ${location} hit ${count} times\n` +
+              "Stack:\n" +
+              formatStack(stack));
   }
+  Assert.ok(!unexpectedReflows.size,
+            unexpectedReflows.size + " unexpected reflows");
 }
 
 async function ensureNoPreloadedBrowser(win = window) {
   // If we've got a preloaded browser, get rid of it so that it
   // doesn't interfere with the test if it's loading. We have to
   // do this before we disable preloading or changing the new tab
   // URL, otherwise _getPreloadedBrowser will return null, despite
   // the preloaded browser existing.
@@ -224,16 +245,33 @@ function forceImmediateToolbarOverflowHa
 async function prepareSettledWindow() {
   let win = await BrowserTestUtils.openNewBrowserWindow();
 
   await ensureNoPreloadedBrowser(win);
   forceImmediateToolbarOverflowHandling(win);
   return win;
 }
 
+// Use this function to avoid catching a reflow related to calling focus on the
+// urlbar and changed rects for its dropmarker when opening new tabs.
+async function ensureFocusedUrlbar() {
+  // The switchingtabs attribute prevents the historydropmarker opacity
+  // transition, so if we expect a transitionend event when this attribute
+  // is set, we wait forever. (it's removed off a MozAfterPaint event listener)
+  await BrowserTestUtils.waitForCondition(() =>
+    !gURLBar.hasAttribute("switchingtabs"));
+
+  let dropmarker = document.getAnonymousElementByAttribute(gURLBar, "anonid",
+                                                           "historydropmarker");
+  let opacityPromise = BrowserTestUtils.waitForEvent(dropmarker, "transitionend",
+                                                     false, e => e.propertyName === "opacity");
+  gURLBar.focus();
+  await opacityPromise;
+}
+
 /**
  * Calculate and return how many additional tabs can be fit into the
  * tabstrip without causing it to overflow.
  *
  * @return int
  *         The maximum additional tabs that can be fit into the
  *         tabstrip without causing it to overflow.
  */
@@ -311,16 +349,83 @@ async function addDummyHistoryEntries(se
 
   await PlacesTestUtils.addVisits(visits);
 
   registerCleanupFunction(async function() {
     await PlacesUtils.history.clear();
   });
 }
 
+
+/**
+ * Async utility function to capture a screenshot of each painted frame.
+ *
+ * @param testPromise (Promise)
+ *        A promise that is resolved when the data collection should stop.
+ *
+ * @param win (browser window, optional)
+ *        The browser window to monitor. Defaults to the current window.
+ *
+ * @return An array of screenshots
+ */
+async function recordFrames(testPromise, win = window) {
+  let canvas = win.document.createElementNS("http://www.w3.org/1999/xhtml",
+                                            "canvas");
+  canvas.mozOpaque = true;
+  let ctx = canvas.getContext("2d", {alpha: false, willReadFrequently: true});
+
+  let frames = [];
+
+  let afterPaintListener = event => {
+    let width, height;
+    canvas.width = width = win.innerWidth;
+    canvas.height = height = win.innerHeight;
+    ctx.drawWindow(win, 0, 0, width, height, "white",
+                   ctx.DRAWWINDOW_DO_NOT_FLUSH | ctx.DRAWWINDOW_DRAW_VIEW |
+                   ctx.DRAWWINDOW_ASYNC_DECODE_IMAGES |
+                   ctx.DRAWWINDOW_USE_WIDGET_LAYERS);
+    let data = Cu.cloneInto(ctx.getImageData(0, 0, width, height).data, {});
+    if (frames.length) {
+      // Compare this frame with the previous one to avoid storing duplicate
+      // frames and running out of memory.
+      let previous = frames[frames.length - 1];
+      if (previous.width == width && previous.height == height) {
+        let equals = true;
+        for (let i = 0; i < data.length; ++i) {
+          if (data[i] != previous.data[i]) {
+            equals = false;
+            break;
+          }
+        }
+        if (equals) {
+          return;
+        }
+      }
+    }
+    frames.push({data, width, height});
+  };
+  win.addEventListener("MozAfterPaint", afterPaintListener);
+
+  // If the test is using an existing window, capture a frame immediately.
+  if (win.document.readyState == "complete") {
+    afterPaintListener();
+  }
+
+  try {
+    await testPromise;
+  } finally {
+    win.removeEventListener("MozAfterPaint", afterPaintListener);
+  }
+
+  return frames;
+}
+
+// How many identical pixels to accept between 2 rects when deciding to merge
+// them.
+const kMaxEmptyPixels = 3;
 function compareFrames(frame, previousFrame) {
   // Accessing the Math global is expensive as the test executes in a
   // non-syntactic scope. Accessing it as a lexical variable is enough
   // to make the code JIT well.
   const M = Math;
 
   function expandRect(x, y, rect) {
     if (rect.x2 < x)
@@ -366,23 +471,22 @@ function compareFrames(frame, previousFr
         different.push(i);
         break;
       }
     }
   }
   rects.reverse();
 
   // The following code block merges rects that are close to each other
-  // (less than maxEmptyPixels away).
+  // (less than kMaxEmptyPixels away).
   // This is needed to avoid having a rect for each letter when a label moves.
-  const maxEmptyPixels = 3;
   let areRectsContiguous = function(r1, r2) {
-    return r1.y2 >= r2.y1 - 1 - maxEmptyPixels &&
-           r2.x1 - 1 - maxEmptyPixels <= r1.x2 &&
-           r2.x2 >= r1.x1 - 1 - maxEmptyPixels;
+    return r1.y2 >= r2.y1 - 1 - kMaxEmptyPixels &&
+           r2.x1 - 1 - kMaxEmptyPixels <= r1.x2 &&
+           r2.x2 >= r1.x1 - 1 - kMaxEmptyPixels;
   };
   let hasMergedRects;
   do {
     hasMergedRects = false;
     for (let r = rects.length - 1; r > 0; --r) {
       let rr = rects[r];
       for (let s = r - 1; s >= 0; --s) {
         let rs = rects[s];
@@ -396,26 +500,135 @@ function compareFrames(frame, previousFr
           break;
         }
       }
     }
   } while (hasMergedRects);
 
   // For convenience, pre-compute the width and height of each rect.
   rects.forEach(r => {
-    r.w = r.x2 - r.x1;
-    r.h = r.y2 - r.y1;
+    r.w = r.x2 - r.x1 + 1;
+    r.h = r.y2 - r.y1 + 1;
   });
 
   return rects;
 }
 
 function dumpFrame({data, width, height}) {
   let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
   canvas.mozOpaque = true;
   canvas.width = width;
   canvas.height = height;
 
   canvas.getContext("2d", {alpha: false, willReadFrequently: true})
         .putImageData(new ImageData(data, width, height), 0, 0);
 
   info(canvas.toDataURL());
 }
+
+/**
+ * Utility function to report unexpected changed areas on screen.
+ *
+ * @param frames (Array)
+ *        An array of frames captured by recordFrames.
+ *
+ * @param expectations (Object)
+ *        An Object indicating which changes on screen are expected.
+ *        If can contain the following optional fields:
+ *         - filter: a function used to exclude changed rects that are expected.
+ *            It takes the following parameters:
+ *             - rects: an array of changed rects
+ *             - frame: the current frame
+ *             - previousFrame: the previous frame
+ *            It returns an array of rects. This array is typically a copy of
+ *            the rects parameter, from which identified expected changes have
+ *            been excluded.
+ *         - exceptions: an array of objects describing known flicker bugs.
+ *           Example:
+ *             exceptions: [
+ *               {name: "bug 1nnnnnn - the foo icon shouldn't flicker",
+ *                condition: r => r.w == 14 && r.y1 == 0 && ... }
+ *               },
+ *               {name: "bug ...
+ *             ]
+ */
+function reportUnexpectedFlicker(frames, expectations) {
+  info("comparing " + frames.length + " frames");
+
+  let unexpectedRects = 0;
+  for (let i = 1; i < frames.length; ++i) {
+    let frame = frames[i], previousFrame = frames[i - 1];
+    let rects = compareFrames(frame, previousFrame);
+
+    if (expectations.filter) {
+      rects = expectations.filter(rects, frame, previousFrame);
+    }
+
+    rects = rects.filter(rect => {
+      let rectText = `${rect.toSource()}, window width: ${frame.width}`;
+      for (let e of (expectations.exceptions || [])) {
+        if (e.condition(rect)) {
+          todo(false, e.name + ", " + rectText);
+          return false;
+        }
+      }
+
+      ok(false, "unexpected changed rect: " + rectText);
+      return true;
+    });
+
+    if (!rects.length)
+      continue;
+
+    // Before dumping a frame with unexpected differences for the first time,
+    // ensure at least one previous frame has been logged so that it's possible
+    // to see the differences when examining the log.
+    if (!unexpectedRects) {
+      dumpFrame(previousFrame);
+    }
+    unexpectedRects += rects.length;
+    dumpFrame(frame);
+  }
+  is(unexpectedRects, 0, "should have 0 unknown flickering areas");
+}
+
+/**
+ * This is the main function that performance tests in this folder will call.
+ *
+ * The general idea is that individual tests provide a test function (testFn)
+ * that will perform some user interactions we care about (eg. open a tab), and
+ * this withPerfObserver function takes care of setting up and removing the
+ * observers and listener we need to detect common performance issues.
+ *
+ * Once testFn is done, withPerfObserver will analyse the collected data and
+ * report anything unexpected.
+ *
+ * @param testFn (async function)
+ *        An async function that exercises some part of the browser UI.
+ *
+ * @param exceptions (object, optional)
+ *        An Array of Objects representing expectations and known issues.
+ *        It can contain the following fields:
+ *         - expectedReflows: an array of expected reflow stacks.
+ *           (see the comment above reportUnexpectedReflows for an example)
+ *         - frames: an object setting expectations for what will change
+ *           on screen during the test, and the known flicker bugs.
+ *           (see the comment above reportUnexpectedFlicker for an example)
+ */
+async function withPerfObserver(testFn, exceptions = {}, win = window) {
+  let resolveFn, rejectFn;
+  let promiseTestDone = new Promise((resolve, reject) => {
+    resolveFn = resolve;
+    rejectFn = reject;
+  });
+
+  let promiseReflows = recordReflows(promiseTestDone, win);
+  let promiseFrames = recordFrames(promiseTestDone, win);
+
+  testFn().then(resolveFn, rejectFn);
+  await promiseTestDone;
+
+  let reflows = await promiseReflows;
+  reportUnexpectedReflows(reflows, exceptions.expectedReflows);
+
+  let frames = await promiseFrames;
+  reportUnexpectedFlicker(frames, exceptions.frames);
+}
--- a/build.gradle
+++ b/build.gradle
@@ -46,16 +46,21 @@ buildscript {
         }
         // For in tree plugins.
         maven {
             url "file://${gradle.mozconfig.topsrcdir}/mobile/android/gradle/m2repo"
         }
     }
 
     ext.kotlin_version = '1.1.51'
+    ext.support_library_version = '23.4.0'
+
+    if (gradle.mozconfig.substs.MOZ_ANDROID_GOOGLE_PLAY_SERVICES) {
+        ext.google_play_services_version = '8.4.0'
+    }
 
     dependencies {
         classpath 'com.android.tools.build:gradle:3.0.1'
         classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.8.2'
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
     }
 }
 
--- a/devtools/client/debugger/new/README.mozilla
+++ b/devtools/client/debugger/new/README.mozilla
@@ -1,13 +1,13 @@
 This is the debugger.html project output.
 See https://github.com/devtools-html/debugger.html
 
-Version 25.0
+Version 26.0
 
-Comparison: https://github.com/devtools-html/debugger.html/compare/release-24...release-25
+Comparison: https://github.com/devtools-html/debugger.html/compare/release-25...release-26
 
 Packages:
 - babel-plugin-transform-es2015-modules-commonjs @6.26.0
 - babel-preset-react @6.24.1
 - react @16.2.0
 - react-dom @16.2.0
 - webpack @3.11.0
--- a/devtools/client/debugger/new/debugger.css
+++ b/devtools/client/debugger/new/debugger.css
@@ -666,18 +666,30 @@ img.arrow {
 html[dir="ltr"] img.arrow {
   transform: rotate(-90deg);
 }
 
 html[dir="rtl"] img.arrow {
   transform: rotate(90deg);
 }
 
-/* TODO (Amit): html is just for specificity. keep it like this? */
-html .arrow.expanded svg {
+.arrow svg {
+  transition: transform 0.125s ease;
+  width: 10px;
+  margin-inline-end: 5px;
+  transform: rotate(-90deg);
+}
+
+html[dir="rtl"] .arrow svg,
+.arrow svg:dir(rtl),
+.arrow svg:-moz-locale-dir(rtl) {
+  transform: rotate(90deg);
+}
+
+.arrow.expanded.expanded svg {
   transform: rotate(0deg);
 }
 
 .arrow.hidden {
   visibility: hidden;
 }
 
 .webpack svg {
@@ -785,20 +797,16 @@ html[dir="rtl"] .managed-tree .tree .nod
 .tree.noselect {
   -webkit-user-select: none;
   -moz-user-select: none;
   -ms-user-select: none;
   -o-user-select: none;
   user-select: none;
 }
 
-.tree button {
-  display: block;
-}
-
 .tree .tree-node {
   display: flex;
 }
 
 .tree .tree-node:not(.focused):hover {
   background-color: var(--theme-selection-background-hover);
 }
 
@@ -812,53 +820,52 @@ html[dir="rtl"] .managed-tree .tree .nod
 
 /* Align with expandables siblings (where we have the arrow) */
 .tree-node[data-expandable="false"] .tree-indent:last-of-type {
   margin-inline-end: 15px;
 }
 
 /* For non expandable root nodes, we don't have .tree-indent elements, so we declare
    the margin on the start of the node */
-.tree-node[data-expandable="false"][aria-level="0"] {
+.tree-node[data-expandable="false"][aria-level="1"] {
   padding-inline-start: 15px
 }
 
 .tree .tree-node[data-expandable="true"] {
   cursor: default;
 }
 
+.tree-node img.arrow {
+  mask: url("chrome://devtools/skin/images/devtools-components/arrow.svg") no-repeat;
+  mask-size: 100%;
+  width: 9px;
+  height: 9px;
+  margin-inline-start: 1px;
+  margin-inline-end: 4px;
+  background-color: var(--theme-splitter-color, #9B9B9B);
+  transform: rotate(-90deg);
+  transition: transform 0.125s ease;
+  align-self: center;
+}
+
+html[dir="rtl"] .tree-node img.arrow {
+  transform: rotate(90deg);
+}
+
+.tree-node img.arrow.expanded.expanded {
+  transform: rotate(0deg);
+ }
+
 .tree .tree-node.focused {
   color: white;
   background-color: var(--theme-selection-background, #0a84ff);
 }
 
-.tree-node.focused .arrow svg {
-  fill: currentColor;
-}
-
-.tree-node:hover img {
-  background-color: var(--theme-content-color3);
-}
-
-.arrow svg {
-  fill: var(--theme-splitter-color, #9B9B9B);
-  transition: transform 0.125s ease;
-  width: 10px;
-  margin-inline-end: 5px;
-  transform: rotate(-90deg);
-}
-
-html[dir="rtl"] .arrow svg,
-.arrow svg:dir(rtl),
-.arrow svg:-moz-locale-dir(rtl) {
-  transform: rotate(90deg);
-}
-
-.arrow.expanded.expanded svg {
-  transform: rotate(0deg);
+.tree-node.focused img.arrow {
+  background-color: currentColor;
 }
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 .close-btn {
   width: 14px;
   height: 14px;
@@ -1327,19 +1334,17 @@ html[dir="rtl"] .arrow svg,
 .theme-dark .sources-list .managed-tree .tree .node img.blackBox {
   background-color: var(--theme-body-color);
 }
 
 .theme-dark .sources-list .managed-tree .tree .node.focused img.blackBox {
   background-color: white;
 }
 
-.tree:not(.object-inspector)
-  .tree-node[data-expandable="false"]
-  .tree-indent:last-of-type {
+.tree:not(.object-inspector) .tree-node[data-expandable="false"] .tree-indent:last-of-type {
   margin-inline-end: 4px;
 }
 
 /*
   Custom root styles
 */
 .sources-pane.sources-list-custom-root {
   display: block;
@@ -1888,16 +1893,17 @@ html .toggle-button.end.vertical svg {
   --null-color: var(--theme-comment);
   --object-color: var(--theme-highlight-blue);
   --caption-color: var(--theme-highlight-blue);
   --location-color: var(--theme-comment);
   --source-link-color: var(--theme-highlight-blue);
   --node-color: var(--theme-highlight-purple);
   --reference-color: var(--theme-highlight-blue);
   --comment-node-color: var(--theme-comment);
+  --stack-function-color: var(--theme-highlight-red);
 }
 
 .theme-firebug {
   --number-color: #000088;
   --string-color: #FF0000;
   --null-color: #787878;
   --object-color: DarkGreen;
   --caption-color: #444444;
@@ -1941,28 +1947,47 @@ html .toggle-button.end.vertical svg {
 .objectBox-symbol {
   color: var(--string-color);
 }
 
 .objectBox-string a, .objectBox-string a:visited {
   color: currentColor;
   text-decoration: none;
   font-style: italic;
+  cursor: pointer;
 }
 
 .objectBox-string a:hover {
   text-decoration: underline;
 }
 
 .objectBox-function,
 .objectBox-stackTrace,
 .objectBox-profile {
   color: var(--object-color);
 }
 
+.objectBox-stackTrace-grid {
+  display: inline-grid;
+  grid-template-columns: auto auto;
+  margin-top: 3px;
+}
+
+.objectBox-stackTrace-fn::before {
+  content: "\3BB"; /* The "lambda" symbol */
+  color: var(--theme-body-color);
+  display: inline-block;
+  margin: 0 0.3em;
+}
+
+.objectBox-stackTrace-fn {
+  color: var(--stack-function-color);
+  padding-inline-start: 17px;
+}
+
 .objectBox-Location,
 .location {
   color: var(--location-color);
 }
 
 .objectBox-null,
 .objectBox-undefined,
 .objectBox-hint,
@@ -2083,45 +2108,45 @@ html .toggle-button.end.vertical svg {
 .theme-dark .caption,
 .theme-light .caption {
   font-weight: normal;
 }
 
 /******************************************************************************/
 /* Open DOMNode in inspector button */
 
-.open-inspector svg {
-  fill: var(--comment-node-color);
+button.open-inspector {
+  mask: url("chrome://devtools/skin/images/devtools-reps/open-inspector.svg") no-repeat;
+  display: inline-block;
+  background-color: var(--comment-node-color);
   height: 16px;
-  width: 16px;
   margin-left: .25em;
-  cursor: pointer;
   vertical-align: middle;
 }
 
-.objectBox-node:hover .open-inspector svg,
-.objectBox-textNode:hover .open-inspector svg,
-.open-inspector svg:hover {
-  fill: var(--theme-highlight-blue);
+.objectBox-node:hover .open-inspector,
+.objectBox-textNode:hover .open-inspector,
+.open-inspector:hover {
+  background-color: var(--theme-highlight-blue);
 }
 
 /******************************************************************************/
 /* Jump to definition button */
 
-.jump-definition svg {
-  stroke: var(--comment-node-color);
+button.jump-definition {
+  mask: url("chrome://devtools/skin/images/devtools-reps/jump-definition.svg") no-repeat;
+  display: inline-block;
+  background-color: var(--comment-node-color);
   height: 16px;
-  width: 16px;
   margin-left: .25em;
-  cursor: pointer;
   vertical-align: middle;
 }
 
-.jump-definition svg:hover {
-  stroke: var(--theme-highlight-blue);
+.jump-definition:hover {
+  background-color: var(--theme-highlight-blue);
 }
 
 /******************************************************************************/
 /* "more…" ellipsis */
 .more-ellipsis {
   color: var(--comment-node-color);
 }
 /* This Source Code Form is subject to the terms of the Mozilla Public
@@ -2143,19 +2168,34 @@ html .toggle-button.end.vertical svg {
 
 .tree.object-inspector .lessen,
 .tree.object-inspector .lessen *,
 .tree.object-inspector .lessen .object-label,
 .tree.object-inspector .lessen .object-label * {
   color: var(--theme-comment);
 }
 
+.tree.object-inspector .block .object-label,
+.tree.object-inspector .block .object-label * {
+  color: var(--theme-body-color);
+}
+
+.tree.object-inspector .block .object-label:before {
+  content: "\2632   ";
+  font-size: 1.1em;
+}
+
 .object-inspector .object-delimiter {
   color: var(--theme-comment);
 }
+
+.object-inspector .tree-node img.arrow {
+  display: inline-block;
+  vertical-align: middle;
+}
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 .bracket-arrow {
   position: absolute;
 }
 
@@ -3596,16 +3636,27 @@ img.ignore-exceptions {
 
 .scopes-list .tree:focus {
   outline: none;
 }
 
 .scopes-list .function-signature {
   display: inline-block;
 }
+
+.scopes-list .scope-type-toggle {
+  text-align: center;
+  padding-top: 10px;
+  padding-bottom: 10px;
+}
+
+.scopes-list .scope-type-toggle a {
+  /* Override color so that the link doesn't turn purple */
+  color: var(--theme-body-color);
+}
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 .secondary-panes {
   overflow: auto;
   display: flex;
   flex-direction: column;
--- a/devtools/client/debugger/new/debugger.js
+++ b/devtools/client/debugger/new/debugger.js
@@ -728,23 +728,16 @@ function baseAssignValue(object, key, va
   }
 }
 
 module.exports = baseAssignValue;
 
 
 /***/ }),
 
-/***/ 1153:
-/***/ (function(module, exports) {
-
-module.exports = "<!-- This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. --><svg viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M8,3L12,3L12,7L14,7L14,8L12,8L12,12L8,12L8,14L7,14L7,12L3,12L3,8L1,8L1,7L3,7L3,3L7,3L7,1L8,1L8,3ZM10,10L10,5L5,5L5,10L10,10Z\"></path></svg>"
-
-/***/ }),
-
 /***/ 116:
 /***/ (function(module, exports, __webpack_require__) {
 
 var getNative = __webpack_require__(81);
 
 var defineProperty = (function() {
   try {
     var func = getNative(Object, 'defineProperty');
@@ -1754,17 +1747,17 @@ module.exports = "<!-- This Source Code 
 "use strict";
 
 
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Dependencies
-const validProtocols = /^(http|https|ftp|data|javascript|resource|chrome):/i;
+const validProtocols = /^(http|https|ftp|data|resource|chrome):/i;
 const tokenSplitRegex = /(\s|\'|\"|\\)+/;
 const ELLIPSIS = "\u2026";
 const dom = __webpack_require__(1758);
 const { span } = dom;
 
 /**
  * Returns true if the given object is a grip (see RDP protocol)
  */
@@ -2129,23 +2122,40 @@ function isURL(token) {
     }
     new URL(token);
     return true;
   } catch (e) {
     return false;
   }
 }
 
+/**
+ * Returns a new array in which `char` are interleaved between the original items.
+ *
+ * @param {Array} items
+ * @param {String} char
+ * @returns Array
+ */
+function interleave(items, char) {
+  return items.reduce((res, item, index) => {
+    if (index !== items.length - 1) {
+      return res.concat(item, char);
+    }
+    return res.concat(item);
+  }, []);
+}
+
 const ellipsisElement = span({
   key: "more",
   className: "more-ellipsis",
   title: `more${ELLIPSIS}`
 }, ELLIPSIS);
 
 module.exports = {
+  interleave,
   isGrip,
   isURL,
   cropString,
   containsURL,
   rawCropString,
   sanitizeString,
   escapeString,
   wrapRender,
@@ -3162,17 +3172,17 @@ function createPendingBreakpoint(bp) {
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
-exports.replaceOriginalVariableName = exports.getPausePoints = exports.getFramework = exports.hasSyntaxError = exports.clearSources = exports.setSource = exports.hasSource = exports.isInvalidPauseLocation = exports.getNextStep = exports.clearASTs = exports.clearScopes = exports.clearSymbols = exports.findOutOfScopeLocations = exports.getScopes = exports.getSymbols = exports.getClosestExpression = exports.stopParserWorker = exports.startParserWorker = undefined;
+exports.replaceOriginalVariableName = exports.getPausePoints = exports.getFramework = exports.mapOriginalExpression = exports.hasSyntaxError = exports.clearSources = exports.setSource = exports.hasSource = exports.isInvalidPauseLocation = exports.getNextStep = exports.clearASTs = exports.clearScopes = exports.clearSymbols = exports.findOutOfScopeLocations = exports.getScopes = exports.getSymbols = exports.getClosestExpression = exports.stopParserWorker = exports.startParserWorker = undefined;
 
 var _devtoolsUtils = __webpack_require__(1363);
 
 const { WorkerDispatcher } = _devtoolsUtils.workerUtils; /* This Source Code Form is subject to the terms of the Mozilla Public
                                                           * License, v. 2.0. If a copy of the MPL was not distributed with this
                                                           * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 const dispatcher = new WorkerDispatcher();
@@ -3187,16 +3197,17 @@ const clearSymbols = exports.clearSymbol
 const clearScopes = exports.clearScopes = dispatcher.task("clearScopes");
 const clearASTs = exports.clearASTs = dispatcher.task("clearASTs");
 const getNextStep = exports.getNextStep = dispatcher.task("getNextStep");
 const isInvalidPauseLocation = exports.isInvalidPauseLocation = dispatcher.task("isInvalidPauseLocation");
 const hasSource = exports.hasSource = dispatcher.task("hasSource");
 const setSource = exports.setSource = dispatcher.task("setSource");
 const clearSources = exports.clearSources = dispatcher.task("clearSources");
 const hasSyntaxError = exports.hasSyntaxError = dispatcher.task("hasSyntaxError");
+const mapOriginalExpression = exports.mapOriginalExpression = dispatcher.task("mapOriginalExpression");
 const getFramework = exports.getFramework = dispatcher.task("getFramework");
 const getPausePoints = exports.getPausePoints = dispatcher.task("getPausePoints");
 const replaceOriginalVariableName = exports.replaceOriginalVariableName = dispatcher.task("replaceOriginalVariableName");
 
 /***/ }),
 
 /***/ 1366:
 /***/ (function(module, exports, __webpack_require__) {
@@ -3955,16 +3966,17 @@ const SymbolRep = __webpack_require__(15
 const InfinityRep = __webpack_require__(1566);
 const NaNRep = __webpack_require__(1567);
 const Accessor = __webpack_require__(1568);
 
 // DOM types (grips)
 const Attribute = __webpack_require__(1569);
 const DateTime = __webpack_require__(1570);
 const Document = __webpack_require__(1571);
+const DocumentType = __webpack_require__(3614);
 const Event = __webpack_require__(1572);
 const Func = __webpack_require__(1573);
 const PromiseRep = __webpack_require__(1574);
 const RegExp = __webpack_require__(1575);
 const StyleSheet = __webpack_require__(1576);
 const CommentNode = __webpack_require__(1577);
 const ElementNode = __webpack_require__(1578);
 const TextNode = __webpack_require__(1579);
@@ -3975,17 +3987,17 @@ const ObjectWithURL = __webpack_require_
 const GripArray = __webpack_require__(1450);
 const GripMap = __webpack_require__(1584);
 const GripMapEntry = __webpack_require__(1451);
 const Grip = __webpack_require__(1409);
 
 // List of all registered template.
 // XXX there should be a way for extensions to register a new
 // or modify an existing rep.
-let reps = [RegExp, StyleSheet, Event, DateTime, CommentNode, ElementNode, TextNode, Attribute, Func, PromiseRep, ArrayRep, Document, Window, ObjectWithText, ObjectWithURL, ErrorRep, GripArray, GripMap, GripMapEntry, Grip, Undefined, Null, StringRep, Number, SymbolRep, InfinityRep, NaNRep, Accessor];
+let reps = [RegExp, StyleSheet, Event, DateTime, CommentNode, ElementNode, TextNode, Attribute, Func, PromiseRep, ArrayRep, Document, DocumentType, Window, ObjectWithText, ObjectWithURL, ErrorRep, GripArray, GripMap, GripMapEntry, Grip, Undefined, Null, StringRep, Number, SymbolRep, InfinityRep, NaNRep, Accessor];
 
 /**
  * Generic rep that is using for rendering native JS types or an object.
  * The right template used for rendering is picked automatically according
  * to the current value type. The value must be passed is as 'object'
  * property.
  */
 const Rep = function (props) {
@@ -4034,16 +4046,17 @@ module.exports = {
   Rep,
   REPS: {
     Accessor,
     ArrayRep,
     Attribute,
     CommentNode,
     DateTime,
     Document,
+    DocumentType,
     ElementNode,
     ErrorRep,
     Event,
     Func,
     Grip,
     GripArray,
     GripMap,
     GripMapEntry,
@@ -4552,18 +4565,17 @@ exports.default = SearchInput;
 // Dependencies
 const PropTypes = __webpack_require__(20);
 const {
   maybeEscapePropertyName,
   wrapRender
 } = __webpack_require__(1353);
 const { MODE } = __webpack_require__(1357);
 
-const dom = __webpack_require__(1758);
-const { span } = dom;
+const { span } = __webpack_require__(1758);
 
 /**
  * Property for Obj (local JS objects), Grip (remote JS objects)
  * and GripMap (remote JS maps and weakmaps) reps.
  * It's used to render object properties.
  */
 PropRep.propTypes = {
   // Property name.
@@ -4603,27 +4615,28 @@ function PropRep(props) {
   // The key can be a simple string, for plain objects,
   // or another object for maps and weakmaps.
   if (typeof name === "string") {
     if (!suppressQuotes) {
       name = maybeEscapePropertyName(name);
     }
     key = span({ "className": "nodeName" }, name);
   } else {
-    key = Rep(Object.assign({}, props, {
+    key = Rep({
+      ...props,
       className: "nodeName",
       object: name,
       mode: mode || MODE.TINY,
       defaultRep: Grip
-    }));
+    });
   }
 
   return [key, span({
     "className": "objectEqual"
-  }, equal), Rep(Object.assign({}, props))];
+  }, equal), Rep({ ...props })];
 }
 
 // Exports from this module
 module.exports = wrapRender(PropRep);
 
 /***/ }),
 
 /***/ 1382:
@@ -5401,19 +5414,21 @@ exports.getPreviousPauseFrameLocation = 
 exports.isEvaluatingExpression = isEvaluatingExpression;
 exports.getPopupObjectProperties = getPopupObjectProperties;
 exports.getIsWaitingOnBreak = getIsWaitingOnBreak;
 exports.getShouldPauseOnExceptions = getShouldPauseOnExceptions;
 exports.getShouldIgnoreCaughtExceptions = getShouldIgnoreCaughtExceptions;
 exports.getCanRewind = getCanRewind;
 exports.getFrames = getFrames;
 exports.getGeneratedFrameScope = getGeneratedFrameScope;
+exports.getOriginalFrameScope = getOriginalFrameScope;
 exports.getFrameScopes = getFrameScopes;
 exports.getFrameScope = getFrameScope;
 exports.getSelectedScope = getSelectedScope;
+exports.getSelectedScopeMappings = getSelectedScopeMappings;
 exports.getSelectedFrameId = getSelectedFrameId;
 exports.getTopFrame = getTopFrame;
 exports.getDebuggeeUrl = getDebuggeeUrl;
 exports.getChromeScopes = getChromeScopes;
 
 var _reselect = __webpack_require__(993);
 
 var _devtoolsSourceMap = __webpack_require__(1360);
@@ -5424,33 +5439,35 @@ var _sources = __webpack_require__(1369)
 
 const createPauseState = exports.createPauseState = () => ({
   why: null,
   isWaitingOnBreak: false,
   frames: undefined,
   selectedFrameId: undefined,
   frameScopes: {
     generated: {},
-    original: {}
+    original: {},
+    mappings: {}
   },
   loadedObjects: {},
   shouldPauseOnExceptions: _prefs.prefs.pauseOnExceptions,
   shouldIgnoreCaughtExceptions: _prefs.prefs.ignoreCaughtExceptions,
   canRewind: false,
   debuggeeUrl: "",
   command: "",
   previousLocation: null
 });
 
 const emptyPauseState = {
   pause: null,
   frames: null,
   frameScopes: {
     generated: {},
-    original: {}
+    original: {},
+    mappings: {}
   },
   selectedFrameId: null,
   loadedObjects: {},
   previousLocation: null
 };
 
 function update(state = createPauseState(), action) {
   switch (action.type) {
@@ -5503,22 +5520,27 @@ function update(state = createPauseState
     case "MAP_SCOPES":
       {
         const { frame, status, value } = action;
         const selectedFrameId = frame.id;
 
         const original = _extends({}, state.frameScopes.original, {
           [selectedFrameId]: {
             pending: status !== "done",
-            scope: value
+            scope: value && value.scope
           }
         });
+
+        const mappings = _extends({}, state.frameScopes.mappings, {
+          [selectedFrameId]: value && value.mappings
+        });
         return _extends({}, state, {
           frameScopes: _extends({}, state.frameScopes, {
-            original
+            original,
+            mappings
           })
         });
       }
 
     case "BREAK_ON_NEXT":
       return _extends({}, state, { isWaitingOnBreak: true });
 
     case "SELECT_FRAME":
@@ -5659,42 +5681,55 @@ function getFrames(state) {
 function getGeneratedFrameScope(state, frameId) {
   if (!frameId) {
     return null;
   }
 
   return getFrameScopes(state).generated[frameId];
 }
 
-function getFrameScopes(state) {
-  return state.pause.frameScopes;
-}
-
-function getFrameScope(state, sourceId, frameId) {
+function getOriginalFrameScope(state, sourceId, frameId) {
   if (!frameId || !sourceId) {
     return null;
   }
 
   const isGenerated = (0, _devtoolsSourceMap.isGeneratedId)(sourceId);
   const original = getFrameScopes(state).original[frameId];
 
   if (!isGenerated && original && (original.pending || original.scope)) {
     return original;
   }
 
-  return getFrameScopes(state).generated[frameId];
+  return null;
+}
+
+function getFrameScopes(state) {
+  return state.pause.frameScopes;
+}
+
+function getFrameScope(state, sourceId, frameId) {
+  return getOriginalFrameScope(state, sourceId, frameId) || getGeneratedFrameScope(state, frameId);
 }
 
 function getSelectedScope(state) {
   const sourceRecord = (0, _sources.getSelectedSource)(state);
   const frameId = getSelectedFrameId(state);
   const { scope } = getFrameScope(state, sourceRecord && sourceRecord.get("id"), frameId) || {};
   return scope || null;
 }
 
+function getSelectedScopeMappings(state) {
+  const frameId = getSelectedFrameId(state);
+  if (!frameId) {
+    return null;
+  }
+
+  return getFrameScopes(state).mappings[frameId];
+}
+
 function getSelectedFrameId(state) {
   return state.pause.selectedFrameId;
 }
 
 function getTopFrame(state) {
   const frames = getFrames(state);
   return frames && frames[0];
 }
@@ -6217,22 +6252,23 @@ function _interopRequireWildcard(obj) { 
  * @static
  */
 function addExpression(input) {
   return async ({ dispatch, getState }) => {
     if (!input) {
       return;
     }
 
+    const expressionError = await parser.hasSyntaxError(input);
+
     const expression = (0, _selectors.getExpression)(getState(), input);
     if (expression) {
       return dispatch(evaluateExpression(expression));
     }
 
-    const expressionError = await parser.hasSyntaxError(input);
     dispatch({ type: "ADD_EXPRESSION", input, expressionError });
 
     const newExpression = (0, _selectors.getExpression)(getState(), input);
     if (newExpression) {
       return dispatch(evaluateExpression(newExpression));
     }
   };
 } /* This Source Code Form is subject to the terms of the Mozilla Public
@@ -6302,18 +6338,20 @@ function evaluateExpression(expression) 
     let input = expression.input;
     const frame = (0, _selectors.getSelectedFrame)(getState());
 
     if (frame) {
       const { location, generatedLocation } = frame;
       const source = (0, _selectors.getSource)(getState(), location.sourceId);
       const sourceId = source.get("id");
 
-      if (!(0, _devtoolsSourceMap.isGeneratedId)(sourceId)) {
-        input = await getMappedExpression({ sourceMaps }, generatedLocation, input);
+      const selectedSource = (0, _selectors.getSelectedSource)(getState());
+
+      if (selectedSource && !(0, _devtoolsSourceMap.isGeneratedId)(sourceId) && !(0, _devtoolsSourceMap.isGeneratedId)(selectedSource.get("id"))) {
+        input = await getMappedExpression({ getState, sourceMaps }, generatedLocation, input);
       }
     }
 
     const frameId = (0, _selectors.getSelectedFrameId)(getState());
 
     return dispatch({
       type: "EVALUATE_EXPRESSION",
       input: expression.input,
@@ -6321,18 +6359,23 @@ function evaluateExpression(expression) 
     });
   };
 }
 
 /**
  * Gets information about original variable names from the source map
  * and replaces all posible generated names.
  */
-async function getMappedExpression({ sourceMaps }, generatedLocation, expression) {
-  return expression;
+async function getMappedExpression({ getState, sourceMaps }, generatedLocation, expression) {
+  const mappings = (0, _selectors.getSelectedScopeMappings)(getState());
+  if (!mappings) {
+    return expression;
+  }
+
+  return await parser.mapOriginalExpression(expression, mappings);
 }
 
 /***/ }),
 
 /***/ 1399:
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -7228,16 +7271,17 @@ module.exports = {
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // ReactJS
 const PropTypes = __webpack_require__(20);
 
 // Dependencies
 const {
+  interleave,
   isGrip,
   wrapRender
 } = __webpack_require__(1353);
 const PropRep = __webpack_require__(1381);
 const { MODE } = __webpack_require__(1357);
 
 const dom = __webpack_require__(1758);
 const { span } = dom;
@@ -7292,17 +7336,17 @@ function GripRep(props) {
 
     return span(config, ...tinyModeItems);
   }
 
   let propsArray = safePropIterator(props, object, maxLengthMap.get(mode));
 
   return span(config, getTitleElement(props, object), span({
     className: "objectLeftBrace"
-  }, " { "), ...propsArray, span({
+  }, " { "), ...interleave(propsArray, ", "), span({
     className: "objectRightBrace"
   }, " }"));
 }
 
 function getTitleElement(props, object) {
   return span({
     className: "objectTitle"
   }, getTitle(props, object));
@@ -7347,21 +7391,22 @@ function propIterator(props, object, max
     })];
   }
 
   // Property filter. Show only interesting properties to the user.
   let isInterestingProp = props.isInterestingProp || ((type, value) => {
     return type == "boolean" || type == "number" || type == "string" && value.length != 0;
   });
 
-  let properties = object.preview ? object.preview.ownProperties : {};
+  let properties = object.preview ? object.preview.ownProperties || {} : {};
+
   let propertiesLength = getPropertiesLength(object);
 
   if (object.preview && object.preview.safeGetterValues) {
-    properties = Object.assign({}, properties, object.preview.safeGetterValues);
+    properties = { ...properties, ...object.preview.safeGetterValues };
   }
 
   let indexes = getPropIndexes(properties, max, isInterestingProp);
   if (indexes.length < max && indexes.length < propertiesLength) {
     // There are not enough props yet. Then add uninteresting props to display them.
     indexes = indexes.concat(getPropIndexes(properties, max - indexes.length, (t, value, name) => {
       return !isInterestingProp(t, value, name);
     }));
@@ -7375,25 +7420,26 @@ function propIterator(props, object, max
   let propsArray = getProps(props, properties, indexes, suppressQuotes);
 
   // Show symbols.
   if (object.preview && object.preview.ownSymbols) {
     const { ownSymbols } = object.preview;
     const length = max - indexes.length;
 
     const symbolsProps = ownSymbols.slice(0, length).map(symbolItem => {
-      return PropRep(Object.assign({}, props, {
+      return PropRep({
+        ...props,
         mode: MODE.TINY,
         name: symbolItem,
         object: symbolItem.descriptor.value,
         equal: ": ",
         defaultRep: Grip,
         title: null,
         suppressQuotes
-      }));
+      });
     });
 
     propsArray.push(...symbolsProps);
   }
 
   if (Object.keys(properties).length > max || propertiesLength > max
   // When the object has non-enumerable properties, we don't have them in the packet,
   // but we might want to show there's something in the object.
@@ -7401,33 +7447,17 @@ function propIterator(props, object, max
     // There are some undisplayed props. Then display "more...".
     propsArray.push(span({
       key: "more",
       className: "more-ellipsis",
       title: "more…"
     }, "…"));
   }
 
-  return unfoldProps(propsArray);
-}
-
-function unfoldProps(items) {
-  return items.reduce((res, item, index) => {
-    if (Array.isArray(item)) {
-      res = res.concat(item);
-    } else {
-      res.push(item);
-    }
-
-    // Interleave commas between elements
-    if (index !== items.length - 1) {
-      res.push(", ");
-    }
-    return res;
-  }, []);
+  return propsArray;
 }
 
 /**
  * Get props ordered by index.
  *
  * @param {Object} componentProps Grip Component props.
  * @param {Object} properties Properties of the object the Grip describes.
  * @param {Array} indexes Indexes of properties.
@@ -7441,25 +7471,26 @@ function getProps(componentProps, proper
     return a - b;
   });
 
   const propertiesKeys = Object.keys(properties);
   return indexes.map(i => {
     let name = propertiesKeys[i];
     let value = getPropValue(properties[name]);
 
-    return PropRep(Object.assign({}, componentProps, {
+    return PropRep({
+      ...componentProps,
       mode: MODE.TINY,
       name,
       object: value,
       equal: ": ",
       defaultRep: Grip,
       title: null,
       suppressQuotes
-    }));
+    });
   });
 }
 
 /**
  * Get the indexes of props in the object.
  *
  * @param {Object} properties Props object.
  * @param {Number} max The maximum length of indexes array.
@@ -7536,64 +7567,16 @@ let Grip = {
   maxLengthMap
 };
 
 // Exports from this module
 module.exports = Grip;
 
 /***/ }),
 
-/***/ 1410:
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-var _svgInlineReact = __webpack_require__(1763);
-
-var _svgInlineReact2 = _interopRequireDefault(_svgInlineReact);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const React = __webpack_require__(0);
-const PropTypes = __webpack_require__(20);
-
-
-const svg = {
-  "open-inspector": __webpack_require__(1153),
-  "jump-definition": __webpack_require__(2012)
-};
-
-Svg.propTypes = {
-  className: PropTypes.string
-};
-
-function Svg(name, props) {
-  if (!svg[name]) {
-    throw new Error("Unknown SVG: " + name);
-  }
-  let className = name;
-  if (props && props.className) {
-    className = `${name} ${props.className}`;
-  }
-  if (name === "subSettings") {
-    className = "";
-  }
-  props = Object.assign({}, props, { className, src: svg[name] });
-  return React.createElement(_svgInlineReact2.default, props);
-}
-
-module.exports = Svg;
-
-/***/ }),
-
 /***/ 1413:
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -10288,31 +10271,29 @@ const { a, span } = dom;
 StringRep.propTypes = {
   useQuotes: PropTypes.bool,
   escapeWhitespace: PropTypes.bool,
   style: PropTypes.object,
   cropLimit: PropTypes.number.isRequired,
   member: PropTypes.string,
   object: PropTypes.object.isRequired,
   openLink: PropTypes.func,
-  className: PropTypes.string,
-  omitLinkHref: PropTypes.bool
+  className: PropTypes.string
 };
 
 function StringRep(props) {
   let {
     className,
     style,
     cropLimit,
     object,
     useQuotes = true,
     escapeWhitespace = true,
     member,
-    openLink,
-    omitLinkHref = true
+    openLink
   } = props;
 
   let text = object;
 
   const isLong = isLongString(object);
   const shouldCrop = (!member || !member.open) && cropLimit && text.length > cropLimit;
 
   if (isLong) {
@@ -10330,17 +10311,17 @@ function StringRep(props) {
   const config = getElementConfig({
     className,
     style,
     actor: object.actor
   });
 
   if (!isLong) {
     if (containsURL(text)) {
-      return span(config, ...getLinkifiedElements(text, shouldCrop && cropLimit, omitLinkHref, openLink));
+      return span(config, ...getLinkifiedElements(text, shouldCrop && cropLimit, openLink));
     }
 
     // Cropping of longString has been handled before formatting.
     text = maybeCropString({
       isLong,
       shouldCrop,
       cropLimit
     }, text);
@@ -10415,21 +10396,20 @@ function maybeCropString(opts, text) {
 }
 
 /**
  * Get an array of the elements representing the string, cropped if needed,
  * with actual links.
  *
  * @param {String} text: The actual string to linkify.
  * @param {Integer | null} cropLimit
- * @param {Boolean} omitLinkHref: Do not create an href attribute if true.
  * @param {Function} openLink: Function handling the link opening.
  * @returns {Array<String|ReactElement>}
  */
-function getLinkifiedElements(text, cropLimit, omitLinkHref, openLink) {
+function getLinkifiedElements(text, cropLimit, openLink) {
   const halfLimit = Math.ceil((cropLimit - ELLIPSIS.length) / 2);
   const startCropIndex = cropLimit ? halfLimit : null;
   const endCropIndex = cropLimit ? text.length - halfLimit : null;
 
   // As we walk through the tokens of the source string, we make sure to preserve
   // the original whitespace that separated the tokens.
   let currentIndex = 0;
   const items = [];
@@ -10446,17 +10426,16 @@ function getLinkifiedElements(text, crop
       // Update the index to match the beginning of the token.
       currentIndex = tokenStart;
 
       let linkText = getCroppedString(token, currentIndex, startCropIndex, endCropIndex);
       if (linkText) {
         items.push(a({
           className: "url",
           title: token,
-          href: omitLinkHref === true ? null : token,
           draggable: false,
           onClick: openLink ? e => {
             e.preventDefault();
             openLink(token);
           } : null
         }, linkText));
       }
 
@@ -10601,39 +10580,41 @@ function ArrayRep(props) {
     brackets = needSpace(items.length > 0);
   }
 
   return span({
     className: "objectBox objectBox-array" }, span({
     className: "arrayLeftBracket"
   }, brackets.left), ...items, span({
     className: "arrayRightBracket"
-  }, brackets.right), span({
-    className: "arrayProperties",
-    role: "group" }));
+  }, brackets.right));
 }
 
 function arrayIterator(props, array, max) {
   let items = [];
 
   for (let i = 0; i < array.length && i < max; i++) {
     let config = {
       mode: MODE.TINY,
       delim: i == array.length - 1 ? "" : ", "
     };
     let item;
 
     try {
-      item = ItemRep(Object.assign({}, props, config, {
+      item = ItemRep({
+        ...props,
+        ...config,
         object: array[i]
-      }));
+      });
     } catch (exc) {
-      item = ItemRep(Object.assign({}, props, config, {
+      item = ItemRep({
+        ...props,
+        ...config,
         object: exc
-      }));
+      });
     }
     items.push(item);
   }
 
   if (array.length > max) {
     items.push(span({
       className: "more-ellipsis",
       title: "more…"
@@ -10655,20 +10636,21 @@ ItemRep.propTypes = {
 function ItemRep(props) {
   const { Rep } = __webpack_require__(1372);
 
   let {
     object,
     delim,
     mode
   } = props;
-  return span({}, Rep(Object.assign({}, props, {
+  return span({}, Rep({
+    ...props,
     object: object,
     mode: mode
-  })), delim);
+  }), delim);
 }
 
 function getLength(object) {
   return object.length;
 }
 
 function supportsObject(object) {
   return Array.isArray(object) || Object.prototype.toString.call(object) === "[object Arguments]";
@@ -10734,26 +10716,28 @@ module.exports = {
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Dependencies
 const PropTypes = __webpack_require__(20);
 
 const { lengthBubble } = __webpack_require__(2249);
 const {
+  interleave,
   getGripType,
   isGrip,
   wrapRender,
   ellipsisElement
 } = __webpack_require__(1353);
 const { MODE } = __webpack_require__(1357);
 
 const dom = __webpack_require__(1758);
 const { span } = dom;
 const { ModePropType } = __webpack_require__(1448);
+const DEFAULT_TITLE = "Array";
 
 /**
  * Renders an array. The array is enclosed by left and right bracket
  * and the max number of rendered items depends on the current mode.
  */
 GripArray.propTypes = {
   object: PropTypes.object.isRequired,
   // @TODO Change this to Object.values once it's supported in Node's version of V8
@@ -10802,71 +10786,63 @@ function GripArray(props) {
   let max = maxLengthMap.get(mode);
   items = arrayIterator(props, object, max);
   brackets = needSpace(items.length > 0);
 
   return span({
     "data-link-actor-id": object.actor,
     className: "objectBox objectBox-array" }, title, span({
     className: "arrayLeftBracket"
-  }, brackets.left), ...interleaveCommas(items), span({
+  }, brackets.left), ...interleave(items, ", "), span({
     className: "arrayRightBracket"
   }, brackets.right), span({
     className: "arrayProperties",
     role: "group" }));
 }
 
-function interleaveCommas(items) {
-  return items.reduce((res, item, index) => {
-    if (index !== items.length - 1) {
-      return res.concat(item, ", ");
-    }
-    return res.concat(item);
-  }, []);
-}
-
 function getLength(grip) {
   if (!grip.preview) {
     return 0;
   }
 
   return grip.preview.length || grip.preview.childNodesLength || 0;
 }
 
 function getTitle(props, object) {
   let objectLength = getLength(object);
   let isEmpty = objectLength === 0;
 
-  let title = props.title || object.class || "Array";
+  let title = props.title || object.class || DEFAULT_TITLE;
 
   const length = lengthBubble({
     object,
     mode: props.mode,
     maxLengthMap,
     getLength
   });
 
   if (props.mode === MODE.TINY) {
     if (isEmpty) {
-      return object.class === "Array" ? "" : span({
-        className: "objectTitle" }, title, " ");
+      if (object.class === DEFAULT_TITLE) {
+        return null;
+      }
+
+      return span({ className: "objectTitle" }, `${title} `);
     }
 
     let trailingSpace;
-    if (object.class === "Array") {
-      title = "";
+    if (object.class === DEFAULT_TITLE) {
+      title = null;
       trailingSpace = " ";
     }
 
-    return span({
-      className: "objectTitle" }, title, length, trailingSpace);
-  }
-
-  return span({
-    className: "objectTitle" }, title, length, " ");
+    return span({ className: "objectTitle" }, title, length, trailingSpace);
+  }
+
+  return span({ className: "objectTitle" }, title, length, " ");
 }
 
 function getPreviewItems(grip) {
   if (!grip.preview) {
     return null;
   }
 
   return grip.preview.items || grip.preview.childNodes || [];
@@ -10906,22 +10882,23 @@ function arrayIterator(props, grip, max)
 
     if (emptySlots > 0) {
       res.push(getEmptySlotsElement(emptySlots));
       foldedEmptySlots = foldedEmptySlots + emptySlots - 1;
       emptySlots = 0;
     }
 
     if (res.length < max) {
-      res.push(Rep(Object.assign({}, props, {
+      res.push(Rep({
+        ...props,
         object,
         mode: MODE.TINY,
         // Do not propagate title to array items reps
         title: undefined
-      })));
+      }));
     }
 
     return res;
   }, []);
 
   // Handle trailing empty slots if there are some.
   if (items.length < max && emptySlots > 0) {
     items.push(getEmptySlotsElement(emptySlots));
@@ -11002,23 +10979,24 @@ function GripMapEntry(props) {
 
   const {
     key,
     value
   } = object.preview;
 
   return span({
     className: "objectBox objectBox-map-entry"
-  }, ...PropRep(Object.assign({}, props, {
+  }, PropRep({
+    ...props,
     name: key,
     object: value,
     equal: " \u2192 ",
     title: null,
     suppressQuotes: false
-  })));
+  }));
 }
 
 function supportsObject(grip, noGrip = false) {
   if (noGrip === true) {
     return false;
   }
   return grip && grip.type === "mapEntry" && grip.preview;
 }
@@ -15391,29 +15369,21 @@ var _react2 = _interopRequireDefault(_re
 var _reactDomFactories = __webpack_require__(1758);
 
 var _reactDomFactories2 = _interopRequireDefault(_reactDomFactories);
 
 var _propTypes = __webpack_require__(20);
 
 var _propTypes2 = _interopRequireDefault(_propTypes);
 
-var _svgInlineReact = __webpack_require__(1763);
-
-var _svgInlineReact2 = _interopRequireDefault(_svgInlineReact);
-
-var _arrow = __webpack_require__(2247);
-
-var _arrow2 = _interopRequireDefault(_arrow);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-const { Component, createFactory, createElement } = _react2.default; /* This Source Code Form is subject to the terms of the Mozilla Public
-                                                                      * License, v. 2.0. If a copy of the MPL was not distributed with this
-                                                                      * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+const { Component, createFactory } = _react2.default; /* This Source Code Form is subject to the terms of the Mozilla Public
+                                                       * License, v. 2.0. If a copy of the MPL was not distributed with this
+                                                       * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 __webpack_require__(2248);
 
 const AUTO_EXPAND_DEPTH = 0; // depth
 
 /**
  * An arrow that displays whether its node is expanded (▼) or collapsed
  * (▶). When its node has no children, it is hidden.
@@ -15433,19 +15403,18 @@ class ArrowExpander extends Component {
     const {
       expanded
     } = this.props;
 
     const classNames = ["arrow"];
     if (expanded) {
       classNames.push("expanded");
     }
-    return createElement(_svgInlineReact2.default, {
-      className: classNames.join(" "),
-      src: _arrow2.default
+    return _reactDomFactories2.default.img({
+      className: classNames.join(" ")
     });
   }
 }
 
 const treeIndent = _reactDomFactories2.default.span({ className: "tree-indent" }, "\u200B");
 
 class TreeNode extends Component {
   static get propTypes() {
@@ -15493,17 +15462,17 @@ class TreeNode extends Component {
     const indents = Array.from({ length: depth }).fill(treeIndent);
     let items = indents.concat(renderItem(item, depth, focused, arrow, expanded));
 
     return _reactDomFactories2.default.div({
       id,
       className: "tree-node" + (focused ? " focused" : ""),
       onClick: this.props.onClick,
       role: "treeitem",
-      "aria-level": depth,
+      "aria-level": depth + 1,
       "aria-expanded": ariaExpanded,
       "data-expandable": this.props.isExpandable
     }, ...items);
   }
 }
 
 const ArrowExpanderFactory = createFactory(ArrowExpander);
 const TreeNodeFactory = createFactory(TreeNode);
@@ -16893,16 +16862,26 @@ function _interopRequireDefault(obj) { r
 
 
 // Selectors
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 // Dependencies
+const sourceTypes = {
+  coffee: "coffeescript",
+  js: "javascript",
+  jsx: "react",
+  ts: "typescript"
+};
+
+// Actions
+
+
 class SourcesTree extends _react.Component {
 
   constructor(props) {
     super(props);
 
     _initialiseProps.call(this);
 
     const { debuggeeUrl, sources, projectRoot } = this.props;
@@ -17059,18 +17038,16 @@ class SourcesTree extends _react.Compone
         "div",
         { className: "sources-list", onKeyDown: onKeyDown },
         tree
       )
     );
   }
 }
 
-// Actions
-
 var _initialiseProps = function () {
   this.focusItem = item => {
     this.setState({ focusedItem: item });
   };
 
   this.selectItem = item => {
     if (!(0, _sourcesTree.nodeHasChildren)(item)) {
       this.props.selectLocation({ sourceId: item.contents.get("id") });
@@ -17109,23 +17086,19 @@ var _initialiseProps = function () {
     }
 
     if (!(0, _sourcesTree.nodeHasChildren)(item)) {
       const obj = item.contents.get("id");
       const source = sources.get(obj);
       if (source && source.get("isBlackBoxed")) {
         return _react2.default.createElement("img", { className: "blackBox" });
       }
-      const sourceType = {
-        coffee: "coffeescript",
-        js: "javascript",
-        jsx: "react",
-        ts: "typescript"
-      }[(0, _sourcesTree.getExtension)(source)];
-      return sourceType ? _react2.default.createElement(_Svg2.default, { className: "source-icon", name: sourceType }) : _react2.default.createElement("img", { className: "file" });
+
+      const sourceType = sourceTypes[(0, _sourcesTree.getExtension)(source)];
+      return _react2.default.createElement("img", { className: sourceType || "file" });
     }
 
     return _react2.default.createElement("img", { className: "folder" });
   };
 
   this.onContextMenu = (event, item) => {
     const copySourceUri2Label = L10N.getStr("copySourceUri2");
     const copySourceUri2Key = L10N.getStr("copySourceUri2.accesskey");
@@ -19163,23 +19136,24 @@ function propIterator(props, object, max
   }
 
   const elements = [];
   const unimportantProperties = [];
   let propertiesNumber = 0;
   const propertiesNames = Object.keys(object);
 
   const pushPropRep = (name, value) => {
-    elements.push(PropRep(Object.assign({}, props, {
+    elements.push(PropRep({
+      ...props,
       key: name,
       mode: MODE.TINY,
       name,
       object: value,
       equal: ": "
-    })));
+    }));
     propertiesNumber++;
 
     if (propertiesNumber < propertiesNames.length) {
       elements.push(", ");
     }
   };
 
   try {
@@ -19426,19 +19400,17 @@ function Accessor(props) {
   if (hasGetter(object)) {
     accessors.push("Getter");
   }
   if (hasSetter(object)) {
     accessors.push("Setter");
   }
   const title = accessors.join(" & ");
 
-  return span({ className: "objectBox objectBox-accessor" }, span({
-    className: "objectTitle"
-  }, title));
+  return span({ className: "objectBox objectBox-accessor objectTitle" }, title);
 }
 
 function hasGetter(object) {
   return object && object.get && object.get.type !== "undefined";
 }
 
 function hasSetter(object) {
   return object && object.set && object.set.type !== "undefined";
@@ -19622,17 +19594,17 @@ Document.propTypes = {
 };
 
 function Document(props) {
   let grip = props.object;
   const location = getLocation(grip);
   return span({
     "data-link-actor-id": grip.actor,
     className: "objectBox objectBox-document"
-  }, getTitle(grip), location ? " " : null, location ? span({ className: "location" }, location) : null);
+  }, getTitle(grip), location ? span({ className: "location" }, ` ${location}`) : null);
 }
 
 function getLocation(grip) {
   let location = grip.preview.location;
   return location ? getURLDisplayString(location) : null;
 }
 
 function getTitle(grip) {
@@ -19689,26 +19661,28 @@ Event.propTypes = {
   // @TODO Change this to Object.values once it's supported in Node's version of V8
   mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
   onDOMNodeMouseOver: PropTypes.func,
   onDOMNodeMouseOut: PropTypes.func,
   onInspectIconClick: PropTypes.func
 };
 
 function Event(props) {
-  // Use `Object.assign` to keep `props` without changes because:
-  // 1. JSON.stringify/JSON.parse is slow.
-  // 2. Immutable.js is planned for the future.
-  let gripProps = Object.assign({}, props, {
-    title: getTitle(props)
-  });
-  gripProps.object = Object.assign({}, props.object);
-  gripProps.object.preview = Object.assign({}, props.object.preview);
-
-  gripProps.object.preview.ownProperties = {};
+  let gripProps = {
+    ...props,
+    title: getTitle(props),
+    object: {
+      ...props.object,
+      preview: {
+        ...props.object.preview,
+        ownProperties: {}
+      }
+    }
+  };
+
   if (gripProps.object.preview.target) {
     Object.assign(gripProps.object.preview.ownProperties, {
       target: gripProps.object.preview.target
     });
   }
   Object.assign(gripProps.object.preview.ownProperties, gripProps.object.preview.properties);
 
   delete gripProps.object.preview.properties;
@@ -19783,17 +19757,16 @@ const PropTypes = __webpack_require__(20
 // Reps
 const {
   getGripType,
   isGrip,
   cropString,
   wrapRender
 } = __webpack_require__(1353);
 const { MODE } = __webpack_require__(1357);
-const Svg = __webpack_require__(1410);
 
 const dom = __webpack_require__(1758);
 const { span } = dom;
 
 const IGNORED_SOURCE_URLS = ["debugger eval code"];
 
 /**
  * This component represents a template for Function objects.
@@ -19807,18 +19780,18 @@ FunctionRep.propTypes = {
 function FunctionRep(props) {
   let {
     object: grip,
     onViewSourceInDebugger
   } = props;
 
   let jumpToDefinitionButton;
   if (onViewSourceInDebugger && grip.location && grip.location.url && !IGNORED_SOURCE_URLS.includes(grip.location.url)) {
-    jumpToDefinitionButton = Svg("jump-definition", {
-      element: "a",
+    jumpToDefinitionButton = dom.button({
+      className: "jump-definition",
       draggable: false,
       title: "Jump to definition",
       onClick: e => {
         // Stop the event propagation so we don't trigger ObjectInspector expand/collapse.
         e.stopPropagation();
         onViewSourceInDebugger(grip.location);
       }
     });
@@ -19852,53 +19825,64 @@ function getTitle(grip, props) {
     title = "async" + " " + title;
   }
 
   return span({
     className: "objectTitle"
   }, title);
 }
 
-// Decodes an anonymous naming scheme that
-// spider monkey implements based on "Naming Anonymous JavaScript Functions"
-// http://johnjbarton.github.io/nonymous/index.html
-const objectProperty = /([\w\d]+)$/;
-const arrayProperty = /\[(.*?)\]$/;
-const functionProperty = /([\w\d]+)[\/\.<]*?$/;
-const annonymousProperty = /([\w\d]+)\(\^\)$/;
-
+/**
+ * Returns a ReactElement representing the function name.
+ *
+ * @param {Object} grip : Function grip
+ * @param {Object} props: Function rep props
+ */
 function getFunctionName(grip, props = {}) {
   let { functionName } = props;
   let name;
 
   if (functionName) {
     let end = functionName.length - 1;
     functionName = functionName.startsWith('"') && functionName.endsWith('"') ? functionName.substring(1, end) : functionName;
   }
 
   if (grip.displayName != undefined && functionName != undefined && grip.displayName != functionName) {
     name = functionName + ":" + grip.displayName;
   } else {
-    name = grip.userDisplayName || grip.displayName || grip.name || props.functionName || "";
-
-    const scenarios = [objectProperty, arrayProperty, functionProperty, annonymousProperty];
-
-    scenarios.some(reg => {
-      const match = reg.exec(name);
-      if (match) {
-        name = match[1];
-        return true;
-      }
-      return false;
-    });
+    name = cleanFunctionName(grip.userDisplayName || grip.displayName || grip.name || props.functionName || "");
   }
 
   return cropString(name, 100);
 }
 
+const objectProperty = /([\w\d]+)$/;
+const arrayProperty = /\[(.*?)\]$/;
+const functionProperty = /([\w\d]+)[\/\.<]*?$/;
+const annonymousProperty = /([\w\d]+)\(\^\)$/;
+
+/**
+ * Decodes an anonymous naming scheme that
+ * spider monkey implements based on "Naming Anonymous JavaScript Functions"
+ * http://johnjbarton.github.io/nonymous/index.html
+ *
+ * @param {String} name : Function name to clean up
+ * @returns String
+ */
+function cleanFunctionName(name) {
+  for (const reg of [objectProperty, arrayProperty, functionProperty, annonymousProperty]) {
+    const match = reg.exec(name);
+    if (match) {
+      return match[1];
+    }
+  }
+
+  return name;
+}
+
 function renderParams(props) {
   const {
     parameterNames = []
   } = props;
 
   return parameterNames.filter(param => param).reduce((res, param, index, arr) => {
     res.push(span({ className: "param" }, param));
     if (index < arr.length - 1) {
@@ -19918,16 +19902,17 @@ function supportsObject(grip, noGrip = f
   return type == "Function";
 }
 
 // Exports from this module
 
 module.exports = {
   rep: wrapRender(FunctionRep),
   supportsObject,
+  cleanFunctionName,
   // exported for testing purpose.
   getFunctionName
 };
 
 /***/ }),
 
 /***/ 1574:
 /***/ (function(module, exports, __webpack_require__) {
@@ -20002,23 +19987,24 @@ function getTitle(object) {
 function getProps(props, promiseState) {
   const keys = ["state"];
   if (Object.keys(promiseState).includes("value")) {
     keys.push("value");
   }
 
   return keys.reduce((res, key, i) => {
     let object = promiseState[key];
-    res = res.concat(PropRep(Object.assign({}, props, {
+    res = res.concat(PropRep({
+      ...props,
       mode: MODE.TINY,
       name: `<${key}>`,
       object,
       equal: ": ",
       suppressQuotes: true
-    })));
+    }));
 
     // Interleave commas between elements
     if (i !== keys.length - 1) {
       res.push(", ");
     }
 
     return res;
   }, []);
@@ -20252,17 +20238,16 @@ const PropTypes = __webpack_require__(20
 // Utils
 const {
   isGrip,
   wrapRender
 } = __webpack_require__(1353);
 const { rep: StringRep } = __webpack_require__(1447);
 const { MODE } = __webpack_require__(1357);
 const nodeConstants = __webpack_require__(1449);
-const Svg = __webpack_require__(1410);
 
 const dom = __webpack_require__(1758);
 const { span } = dom;
 
 /**
  * Renders DOM element node.
  */
 ElementNode.propTypes = {
@@ -20300,19 +20285,18 @@ function ElementNode(props) {
 
     if (onDOMNodeMouseOut) {
       Object.assign(baseConfig, {
         onMouseOut: onDOMNodeMouseOut
       });
     }
 
     if (onInspectIconClick) {
-      inspectIcon = Svg("open-inspector", {
-        element: "a",
-        draggable: false,
+      inspectIcon = dom.button({
+        className: "open-inspector",
         // TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands
         title: "Click to select the node in the inspector",
         onClick: e => onInspectIconClick(object, e)
       });
     }
   }
 
   return span(baseConfig, ...elements, inspectIcon);
@@ -20384,17 +20368,16 @@ const PropTypes = __webpack_require__(20
 
 // Reps
 const {
   isGrip,
   cropString,
   wrapRender
 } = __webpack_require__(1353);
 const { MODE } = __webpack_require__(1357);
-const Svg = __webpack_require__(1410);
 
 const dom = __webpack_require__(1758);
 const { span } = dom;
 
 /**
  * Renders DOM #text node.
  */
 TextNode.propTypes = {
@@ -20431,18 +20414,18 @@ function TextNode(props) {
 
     if (onDOMNodeMouseOut) {
       Object.assign(baseConfig, {
         onMouseOut: onDOMNodeMouseOut
       });
     }
 
     if (onInspectIconClick) {
-      inspectIcon = Svg("open-inspector", {
-        element: "a",
+      inspectIcon = dom.button({
+        className: "open-inspector",
         draggable: false,
         // TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands
         title: "Click to select the node in the inspector",
         onClick: e => onInspectIconClick(grip, e)
       });
     }
   }
 
@@ -20492,16 +20475,17 @@ module.exports = {
 // ReactJS
 const PropTypes = __webpack_require__(20);
 // Utils
 const {
   getGripType,
   isGrip,
   wrapRender
 } = __webpack_require__(1353);
+const { cleanFunctionName } = __webpack_require__(1573);
 const { MODE } = __webpack_require__(1357);
 
 const dom = __webpack_require__(1758);
 const { span } = dom;
 
 /**
  * Renders Error objects.
  */
@@ -20526,33 +20510,93 @@ function ErrorRep(props) {
         break;
       default:
         throw new Error("Unknown preview kind for the Error rep.");
     }
   } else {
     name = "Error";
   }
 
-  let content = props.mode === MODE.TINY ? name : `${name}: ${preview.message}`;
+  const content = [];
+
+  if (props.mode === MODE.TINY) {
+    content.push(name);
+  } else {
+    content.push(`${name}: "${preview.message}"`);
+  }
 
   if (preview.stack && props.mode !== MODE.TINY) {
-    /*
-      * Since Reps are used in the JSON Viewer, we can't localize
-      * the "Stack trace" label (defined in debugger.properties as
-      * "variablesViewErrorStacktrace" property), until Bug 1317038 lands.
-      */
-    content = `${content}\nStack trace:\n${preview.stack}`;
+    content.push("\n", getStacktraceElements(preview));
   }
 
   return span({
     "data-link-actor-id": object.actor,
     className: "objectBox-stackTrace"
   }, content);
 }
 
+/**
+ * Returns a React element reprensenting the Error stacktrace, i.e. transform error.stack
+ * from:
+ *
+ * semicolon@debugger eval code:1:109
+ * jkl@debugger eval code:1:63
+ * asdf@debugger eval code:1:28
+ * @debugger eval code:1:227
+ *
+ * Into a column layout:
+ *
+ * semicolon  (<anonymous>:8:10)
+ * jkl        (<anonymous>:5:10)
+ * asdf       (<anonymous>:2:10)
+ *            (<anonymous>:11:1)
+ */
+function getStacktraceElements(preview) {
+  const stack = [];
+  preview.stack.split("\n").forEach((line, index) => {
+    if (!line) {
+      // Skip any blank lines
+      return;
+    }
+
+    let functionName;
+    let location;
+
+    // Given the input: "functionName@scriptLocation:2:100"
+    // Result:
+    // ["functionName@scriptLocation:2:100", "functionName", "scriptLocation:2:100"]
+    const result = line.match(/^(.*)@(.*)$/);
+    if (result && result.length === 3) {
+      functionName = result[1];
+
+      // If the resource was loaded by base-loader.js, the location looks like:
+      // resource://devtools/shared/base-loader.js -> resource://path/to/file.js .
+      // What's needed is only the last part after " -> ".
+      location = result[2].split(" -> ").pop();
+    }
+
+    if (!functionName) {
+      functionName = "<anonymous>";
+    }
+
+    stack.push(span({
+      key: "fn" + index,
+      className: "objectBox-stackTrace-fn"
+    }, cleanFunctionName(functionName)), span({
+      key: "location" + index,
+      className: "objectBox-stackTrace-location"
+    }, ` (${location})`));
+  });
+
+  return span({
+    key: "stack",
+    className: "objectBox-stackTrace-grid"
+  }, stack);
+}
+
 // Registration
 function supportsObject(object, noGrip = false) {
   if (noGrip === true || !isGrip(object)) {
     return false;
   }
   return object.preview && getGripType(object, noGrip) === "Error" || object.class === "DOMException";
 }
 
@@ -20609,21 +20653,24 @@ function WindowRep(props) {
     "data-link-actor-id": object.actor,
     className: "objectBox objectBox-Window"
   };
 
   if (mode === MODE.TINY) {
     return span(config, getTitle(object));
   }
 
-  return span(config, getTitle(object), " ", span({ className: "location" }, getLocation(object)));
-}
-
-function getTitle(object) {
+  return span(config, getTitle(object, true), span({ className: "location" }, getLocation(object)));
+}
+
+function getTitle(object, trailingSpace) {
   let title = object.displayClass || object.class || "Window";
+  if (trailingSpace === true) {
+    title = `${title} `;
+  }
   return span({ className: "objectTitle" }, title);
 }
 
 function getLocation(object) {
   return getURLDisplayString(object.preview.url);
 }
 
 // Registration
@@ -20674,17 +20721,17 @@ ObjectWithText.propTypes = {
   object: PropTypes.object.isRequired
 };
 
 function ObjectWithText(props) {
   let grip = props.object;
   return span({
     "data-link-actor-id": grip.actor,
     className: "objectTitle objectBox objectBox-" + getType(grip)
-  }, getType(grip), " ", getDescription(grip));
+  }, `${getType(grip)} `, getDescription(grip));
 }
 
 function getType(grip) {
   return grip.class;
 }
 
 function getDescription(grip) {
   return String({
@@ -20786,26 +20833,26 @@ module.exports = {
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Dependencies
 
 const { lengthBubble } = __webpack_require__(2249);
 const PropTypes = __webpack_require__(20);
 const {
+  interleave,
   isGrip,
   wrapRender,
   ellipsisElement
 } = __webpack_require__(1353);
 const PropRep = __webpack_require__(1381);
 const { MODE } = __webpack_require__(1357);
 const { ModePropType } = __webpack_require__(1448);
 
-const dom = __webpack_require__(1758);
-const { span } = dom;
+const { span } = __webpack_require__(1758);
 
 /**
  * Renders an map. A map is represented by a list of its
  * entries enclosed in curly brackets.
  */
 GripMap.propTypes = {
   object: PropTypes.object,
   // @TODO Change this to Object.values once it's supported in Node's version of V8
@@ -20834,17 +20881,17 @@ function GripMap(props) {
   if (isEmpty || mode === MODE.TINY) {
     return span(config, title);
   }
 
   const propsArray = safeEntriesIterator(props, object, maxLengthMap.get(mode));
 
   return span(config, title, span({
     className: "objectLeftBrace"
-  }, " { "), ...propsArray, span({
+  }, " { "), ...interleave(propsArray, ", "), span({
     className: "objectRightBrace"
   }, " }"));
 }
 
 function getTitle(props, object) {
   const title = props.title || (object && object.class ? object.class : "Map");
   return span({
     className: "objectTitle" }, title, lengthBubble({
@@ -20883,33 +20930,17 @@ function entriesIterator(props, object, 
   }
 
   let entries = getEntries(props, mapEntries, indexes);
   if (entries.length < getLength(object)) {
     // There are some undisplayed entries. Then display "…".
     entries.push(ellipsisElement);
   }
 
-  return unfoldEntries(entries);
-}
-
-function unfoldEntries(items) {
-  return items.reduce((res, item, index) => {
-    if (Array.isArray(item)) {
-      res = res.concat(item);
-    } else {
-      res.push(item);
-    }
-
-    // Interleave commas between elements
-    if (index !== items.length - 1) {
-      res.push(", ");
-    }
-    return res;
-  }, []);
+  return entries;
 }
 
 /**
  * Get entries ordered by index.
  *
  * @param {Object} props Component props.
  * @param {Array} entries Entries array.
  * @param {Array} indexes Indexes of entries.
@@ -20994,407 +21025,42 @@ module.exports = {
 /***/ }),
 
 /***/ 1585:
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-var _devtoolsComponents = __webpack_require__(1441);
-
-var _devtoolsComponents2 = _interopRequireDefault(_devtoolsComponents);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const { Component, createFactory } = __webpack_require__(0);
-const PropTypes = __webpack_require__(20);
-const dom = __webpack_require__(1758);
-
-const Tree = createFactory(_devtoolsComponents2.default.Tree);
-__webpack_require__(1325);
-
-const classnames = __webpack_require__(175);
-
-const {
-  REPS: {
-    Rep,
-    Grip
-  }
-} = __webpack_require__(1372);
-const {
-  MODE
-} = __webpack_require__(1357);
-
-const Utils = __webpack_require__(1938);
-
-const {
-  getChildren,
-  getClosestGripNode,
-  getParent,
-  getValue,
-  nodeHasAccessors,
-  nodeHasProperties,
-  nodeIsDefaultProperties,
-  nodeIsFunction,
-  nodeIsGetter,
-  nodeIsMapEntry,
-  nodeIsMissingArguments,
-  nodeIsOptimizedOut,
-  nodeIsPrimitive,
-  nodeIsPrototype,
-  nodeIsSetter,
-  nodeIsUninitializedBinding,
-  nodeIsUnmappedBinding,
-  nodeIsUnscopedBinding,
-  nodeIsWindow
-} = Utils.node;
-
-const {
-  loadItemProperties
-} = Utils.loadProperties;
-
-// This implements a component that renders an interactive inspector
-// for looking at JavaScript objects. It expects descriptions of
-// objects from the protocol, and will dynamically fetch child
-// properties as objects are expanded.
-//
-// If you want to inspect a single object, pass the name and the
-// protocol descriptor of it:
-//
-//  ObjectInspector({
-//    name: "foo",
-//    desc: { writable: true, ..., { value: { actor: "1", ... }}},
-//    ...
-//  })
-//
-// If you want multiple top-level objects (like scopes), you can pass
-// an array of manually constructed nodes as `roots`:
-//
-//  ObjectInspector({
-//    roots: [{ name: ... }, ...],
-//    ...
-//  });
-
-// There are 3 types of nodes: a simple node with a children array, an
-// object that has properties that should be children when they are
-// fetched, and a primitive value that should be displayed with no
-// children.
-
-class ObjectInspector extends Component {
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const { createElement, createFactory, PureComponent } = __webpack_require__(0);
+const { Provider } = __webpack_require__(3592);
+const ObjectInspector = createFactory(__webpack_require__(3615));
+const createStore = __webpack_require__(3618);
+
+class OI extends PureComponent {
+
   constructor(props) {
-    super();
-    this.cachedNodes = new Map();
-
-    this.state = {
-      actors: new Set(),
-      expandedPaths: new Set(),
-      focusedItem: null,
-      loadedProperties: props.loadedProperties || new Map(),
-      loading: new Map()
-    };
-
-    const self = this;
-
-    self.getChildren = this.getChildren.bind(this);
-    self.renderTreeItem = this.renderTreeItem.bind(this);
-    self.setExpanded = this.setExpanded.bind(this);
-    self.focusItem = this.focusItem.bind(this);
-    self.getRoots = this.getRoots.bind(this);
-  }
-
-  shouldComponentUpdate(nextProps, nextState) {
-    const {
-      expandedPaths,
-      loadedProperties
-    } = this.state;
-
-    if (this.props.roots !== nextProps.roots) {
-      // Since the roots changed, we assume the properties did as well. Thus we can clear
-      // the cachedNodes to avoid bugs and memory leaks.
-      this.cachedNodes.clear();
-      return true;
-    }
-
-    return expandedPaths.size !== nextState.expandedPaths.size || loadedProperties.size !== nextState.loadedProperties.size || [...expandedPaths].some(key => !nextState.expandedPaths.has(key));
-  }
-
-  componentWillUnmount() {
-    const { releaseActor } = this.props;
-    if (typeof releaseActor !== "function") {
-      return;
-    }
-
-    const { actors } = this.state;
-    for (let actor of actors) {
-      releaseActor(actor);
-    }
-  }
-
-  getChildren(item) {
-    const {
-      loadedProperties
-    } = this.state;
-    const { cachedNodes } = this;
-
-    return getChildren({
-      loadedProperties,
-      cachedNodes,
-      item
-    });
-  }
-
-  getRoots() {
-    return this.props.roots;
-  }
-
-  getKey(item) {
-    return item.path;
-  }
-
-  /**
-   * This function is responsible for expanding/collapsing a given node,
-   * which also means that it will check if we need to fetch properties,
-   * entries, prototype and symbols for the said node. If we do, it will call
-   * the appropriate ObjectClient functions, and change the state of the component
-   * with the results it gets from those functions.
-   */
-  async setExpanded(item, expand) {
-    if (nodeIsPrimitive(item)) {
-      return;
-    }
-
-    const {
-      loadedProperties
-    } = this.state;
-
-    const key = this.getKey(item);
-
-    this.setState((prevState, props) => {
-      const newPaths = new Set(prevState.expandedPaths);
-      if (expand === true) {
-        newPaths.add(key);
-      } else {
-        newPaths.delete(key);
-      }
-      return {
-        expandedPaths: newPaths
-      };
-    });
-
-    if (expand === true) {
-      const gripItem = getClosestGripNode(item);
-      const value = getValue(gripItem);
-      const path = item.path;
-
-      const onItemPropertiesLoaded = loadItemProperties(item, this.props.createObjectClient, loadedProperties);
-      if (onItemPropertiesLoaded !== null) {
-        this.setState((prevState, props) => {
-          const nextLoading = new Map(prevState.loading);
-          nextLoading.set(path, onItemPropertiesLoaded);
-          return {
-            loading: nextLoading
-          };
-        });
-
-        const properties = await onItemPropertiesLoaded;
-
-        this.setState((prevState, props) => {
-          const nextLoading = new Map(prevState.loading);
-          nextLoading.delete(path);
-
-          const isRoot = this.props.roots.some(root => {
-            const rootValue = getValue(root);
-            return rootValue && rootValue.actor === value.actor;
-          });
-
-          return {
-            actors: isRoot ? prevState.actors : new Set(prevState.actors).add(value.actor),
-            loadedProperties: new Map(prevState.loadedProperties).set(path, properties),
-            loading: nextLoading
-          };
-        });
-      }
-    }
-  }
-
-  focusItem(item) {
-    if (!this.props.disabledFocus && this.state.focusedItem !== item) {
-      this.setState({
-        focusedItem: item
-      });
-
-      if (this.props.onFocus) {
-        this.props.onFocus(item);
-      }
-    }
-  }
-
-  renderTreeItem(item, depth, focused, arrow, expanded) {
-    let objectValue;
-    let label = item.name;
-    let itemValue = getValue(item);
-
-    const isPrimitive = nodeIsPrimitive(item);
-
-    const unavailable = isPrimitive && itemValue && itemValue.hasOwnProperty && itemValue.hasOwnProperty("unavailable");
-
-    if (nodeIsUninitializedBinding(item)) {
-      objectValue = dom.span({ className: "unavailable" }, "(uninitialized)");
-    } else if (nodeIsUnmappedBinding(item)) {
-      objectValue = dom.span({ className: "unavailable" }, "(unmapped)");
-    } else if (nodeIsUnscopedBinding(item)) {
-      objectValue = dom.span({ className: "unavailable" }, "(unscoped)");
-    } else if (nodeIsOptimizedOut(item)) {
-      objectValue = dom.span({ className: "unavailable" }, "(optimized away)");
-    } else if (nodeIsMissingArguments(item) || unavailable) {
-      objectValue = dom.span({ className: "unavailable" }, "(unavailable)");
-    } else if (nodeIsFunction(item) && !nodeIsGetter(item) && !nodeIsSetter(item) && (this.props.mode === MODE.TINY || !this.props.mode)) {
-      objectValue = undefined;
-      label = this.renderGrip(item, Object.assign({}, this.props, {
-        functionName: label
-      }));
-    } else if (nodeHasProperties(item) || nodeHasAccessors(item) || nodeIsMapEntry(item) || isPrimitive) {
-      let repsProp = Object.assign({}, this.props);
-      if (depth > 0) {
-        repsProp.mode = this.props.mode === MODE.LONG ? MODE.SHORT : MODE.TINY;
-      }
-      if (expanded) {
-        repsProp.mode = MODE.TINY;
-      }
-
-      objectValue = this.renderGrip(item, repsProp);
-    }
-
-    const hasLabel = label !== null && typeof label !== "undefined";
-    const hasValue = typeof objectValue !== "undefined";
-
-    const {
-      onDoubleClick,
-      onLabelClick,
-      dimTopLevelWindow
-    } = this.props;
-
-    return dom.div({
-      className: classnames("node object-node", {
-        focused,
-        lessen: !expanded && (nodeIsDefaultProperties(item) || nodeIsPrototype(item) || dimTopLevelWindow === true && nodeIsWindow(item) && depth === 0)
-      }),
-      onClick: e => {
-        e.stopPropagation();
-        if (isPrimitive === false) {
-          this.setExpanded(item, !expanded);
-        }
-      },
-      onDoubleClick: onDoubleClick ? e => {
-        e.stopPropagation();
-        onDoubleClick(item, {
-          depth,
-          focused,
-          expanded
-        });
-      } : null
-    }, arrow, hasLabel ? dom.span({
-      className: "object-label",
-      onClick: onLabelClick ? event => {
-        event.stopPropagation();
-        onLabelClick(item, {
-          depth,
-          focused,
-          expanded,
-          setExpanded: this.setExpanded
-        });
-      } : null
-    }, label) : null, hasLabel && hasValue ? dom.span({ className: "object-delimiter" }, ": ") : null, hasValue ? objectValue : null);
-  }
-
-  renderGrip(item, props) {
-    const object = getValue(item);
-    return Rep(Object.assign({}, props, {
-      object,
-      mode: props.mode || MODE.TINY,
-      defaultRep: Grip
-    }));
-  }
-
-  render() {
-    const {
-      autoExpandDepth = 1,
-      autoExpandAll = true,
-      disabledFocus,
-      inline,
-      itemHeight = 20,
-      disableWrap = false
-    } = this.props;
-
-    const {
-      expandedPaths,
-      focusedItem
-    } = this.state;
-
-    let roots = this.getRoots();
-    if (roots.length === 1) {
-      const root = roots[0];
-      const name = root && root.name;
-      if (nodeIsPrimitive(root) && (name === null || typeof name === "undefined")) {
-        return this.renderGrip(root, this.props);
-      }
-    }
-
-    return Tree({
-      className: classnames({
-        inline,
-        nowrap: disableWrap,
-        "object-inspector": true
-      }),
-      autoExpandAll,
-      autoExpandDepth,
-      disabledFocus,
-      itemHeight,
-
-      isExpanded: item => expandedPaths.has(this.getKey(item)),
-      isExpandable: item => nodeIsPrimitive(item) === false,
-      focused: focusedItem,
-
-      getRoots: this.getRoots,
-      getParent,
-      getChildren: this.getChildren,
-      getKey: this.getKey,
-
-      onExpand: item => this.setExpanded(item, true),
-      onCollapse: item => this.setExpanded(item, false),
-      onFocus: this.focusItem,
-
-      renderItem: this.renderTreeItem
-    });
-  }
-}
-
-ObjectInspector.displayName = "ObjectInspector";
-
-ObjectInspector.propTypes = {
-  autoExpandAll: PropTypes.bool,
-  autoExpandDepth: PropTypes.number,
-  disabledFocus: PropTypes.bool,
-  disableWrap: PropTypes.bool,
-  inline: PropTypes.bool,
-  roots: PropTypes.array,
-  itemHeight: PropTypes.number,
-  mode: PropTypes.oneOf(Object.values(MODE)),
-  createObjectClient: PropTypes.func.isRequired,
-  onFocus: PropTypes.func,
-  onDoubleClick: PropTypes.func,
-  onLabelClick: PropTypes.func
-};
-
-module.exports = ObjectInspector;
+    super(props);
+    this.store = createStore(props);
+  }
+
+  getStore() {
+    return this.store;
+  }
+
+  render() {
+    return createElement(Provider, { store: this.store }, ObjectInspector(this.props));
+  }
+}
+
+module.exports = OI;
 
 /***/ }),
 
 /***/ 1586:
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
@@ -22629,27 +22295,38 @@ function getMenuItems(event, {
   const blackboxKey = L10N.getStr("sourceFooter.blackbox.accesskey");
   const blackboxLabel = L10N.getStr("sourceFooter.blackbox");
   const unblackboxLabel = L10N.getStr("sourceFooter.unblackbox");
   const toggleBlackBoxLabel = selectedSource.get("isBlackBoxed") ? unblackboxLabel : blackboxLabel;
   const copyFunctionKey = L10N.getStr("copyFunction.accesskey");
   const copyFunctionLabel = L10N.getStr("copyFunction.label");
   const copySourceKey = L10N.getStr("copySource.accesskey");
   const copySourceLabel = L10N.getStr("copySource");
+  const copyToClipboardKey = L10N.getStr("copyToClipboard.accesskey");
+  const copyToClipboardLabel = L10N.getStr("copyToClipboard.label");
   const copySourceUri2Key = L10N.getStr("copySourceUri2.accesskey");
   const copySourceUri2Label = L10N.getStr("copySourceUri2");
   const evaluateInConsoleLabel = L10N.getStr("evaluateInConsole.label");
   const jumpToMappedLocKey = L10N.getStr("editor.jumpToMappedLocation1.accesskey");
   const jumpToMappedLocLabel = L10N.getFormatStr("editor.jumpToMappedLocation1", isOriginal ? L10N.getStr("generated") : L10N.getStr("original"));
   const revealInTreeKey = L10N.getStr("sourceTabs.revealInTree.accesskey");
   const revealInTreeLabel = L10N.getStr("sourceTabs.revealInTree");
   const watchExpressionKey = L10N.getStr("expressions.accesskey");
   const watchExpressionLabel = L10N.getStr("expressions.label");
 
   // menu items
+
+  const copyToClipboardItem = {
+    id: "node-menu-copy-to-clipboard",
+    label: copyToClipboardLabel,
+    accesskey: copyToClipboardKey,
+    disabled: false,
+    click: () => (0, _clipboard.copyToTheClipboard)(selectedSource.get("text"))
+  };
+
   const copySourceItem = {
     id: "node-menu-copy-source",
     label: copySourceLabel,
     accesskey: copySourceKey,
     disabled: selectionText.length === 0,
     click: () => (0, _clipboard.copyToTheClipboard)(selectionText)
   };
 
@@ -22714,17 +22391,17 @@ function getMenuItems(event, {
 
   const evaluateInConsoleItem = {
     id: "node-menu-evaluate-in-console",
     label: evaluateInConsoleLabel,
     click: () => evaluateInConsole(selectionText)
   };
 
   // construct menu
-  const menuItems = [copySourceItem, copySourceUri2Item, copyFunctionItem, { type: "separator" }, jumpToMappedLocationItem, showSourceMenuItem, blackBoxMenuItem];
+  const menuItems = [copyToClipboardItem, copySourceItem, copySourceUri2Item, copyFunctionItem, { type: "separator" }, jumpToMappedLocationItem, showSourceMenuItem, blackBoxMenuItem];
 
   // conditionally added items
   // TODO: Find a new way to only add this for mapped sources?
   if (isTextSelected) {
     menuItems.push(watchExpressionItem, evaluateInConsoleItem);
   }
 
   return menuItems;
@@ -23647,24 +23324,32 @@ class Expressions extends _react.Compone
       if (e.key === "Escape") {
         this.clear();
       }
     };
 
     this.handleExistingSubmit = async (e, expression) => {
       e.preventDefault();
       e.stopPropagation();
+
       this.props.updateExpression(this.state.inputValue, expression);
     };
 
     this.handleNewSubmit = async e => {
+      const { inputValue } = this.state;
       e.preventDefault();
       e.stopPropagation();
-      this.props.addExpression(this.state.inputValue);
-      this.setState({ editing: false, editIndex: -1, inputValue: "" });
+
+      this.props.clearExpressionError();
+      await this.props.addExpression(this.state.inputValue);
+      this.setState({
+        editing: false,
+        editIndex: -1,
+        inputValue: this.props.expressionError ? inputValue : ""
+      });
     };
 
     this.renderExpression = (expression, index) => {
       const { expressionError, openLink } = this.props;
       const { editing, editIndex } = this.state;
       const { input, updating } = expression;
       const isEditingExpr = editing && editIndex === index;
       if (isEditingExpr || isEditingExpr && expressionError) {
@@ -25316,55 +25001,86 @@ var _scopes = __webpack_require__(1792);
 var _devtoolsReps = __webpack_require__(1408);
 
 __webpack_require__(1296);
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 class Scopes extends _react.PureComponent {
   constructor(props, ...args) {
-    const { why, selectedFrame, frameScopes } = props;
+    const {
+      why,
+      selectedFrame,
+      originalFrameScopes,
+      generatedFrameScopes
+    } = props;
 
     super(props, ...args);
 
     this.state = {
-      scopes: (0, _scopes.getScopes)(why, selectedFrame, frameScopes)
+      originalScopes: (0, _scopes.getScopes)(why, selectedFrame, originalFrameScopes),
+      generatedScopes: (0, _scopes.getScopes)(why, selectedFrame, generatedFrameScopes),
+      showOriginal: true
     };
   }
 
   componentWillReceiveProps(nextProps) {
-    const { isPaused, selectedFrame, frameScopes } = this.props;
+    const {
+      isPaused,
+      selectedFrame,
+      originalFrameScopes,
+      generatedFrameScopes
+    } = this.props;
     const isPausedChanged = isPaused !== nextProps.isPaused;
     const selectedFrameChanged = selectedFrame !== nextProps.selectedFrame;
-    const frameScopesChanged = frameScopes !== nextProps.frameScopes;
-
-    if (isPausedChanged || selectedFrameChanged || frameScopesChanged) {
+    const originalFrameScopesChanged = originalFrameScopes !== nextProps.originalFrameScopes;
+    const generatedFrameScopesChanged = generatedFrameScopes !== nextProps.generatedFrameScopes;
+
+    if (isPausedChanged || selectedFrameChanged || originalFrameScopesChanged || generatedFrameScopesChanged) {
       this.setState({
-        scopes: (0, _scopes.getScopes)(nextProps.why, nextProps.selectedFrame, nextProps.frameScopes)
+        originalScopes: (0, _scopes.getScopes)(nextProps.why, nextProps.selectedFrame, nextProps.originalFrameScopes),
+        generatedScopes: (0, _scopes.getScopes)(nextProps.why, nextProps.selectedFrame, nextProps.generatedFrameScopes)
       });
     }
   }
 
   render() {
     const { isPaused, isLoading } = this.props;
-    const { scopes } = this.state;
-
-    if (scopes) {
+    const { originalScopes, generatedScopes, showOriginal } = this.state;
+
+    const scopes = showOriginal && originalScopes || generatedScopes;
+
+    if (scopes && !isLoading) {
       return _react2.default.createElement(
         "div",
         { className: "pane scopes-list" },
         _react2.default.createElement(_devtoolsReps.ObjectInspector, {
           roots: scopes,
           autoExpandAll: false,
           autoExpandDepth: 1,
           disableWrap: true,
           disabledFocus: true,
           dimTopLevelWindow: true,
           createObjectClient: grip => (0, _firefox.createObjectClient)(grip)
-        })
+        }),
+        originalScopes ? _react2.default.createElement(
+          "div",
+          { className: "scope-type-toggle" },
+          _react2.default.createElement(
+            "a",
+            {
+              href: "",
+              onClick: e => {
+                e.preventDefault();
+                this.setState({ showOriginal: !showOriginal });
+              }
+            },
+            showOriginal ? L10N.getStr("scopes.toggleToGenerated") : L10N.getStr("scopes.toggleToOriginal")
+          )
+        ) : null
       );
     }
 
     let stateText = L10N.getStr("scopes.notPaused");
     if (isPaused) {
       if (isLoading) {
         stateText = L10N.getStr("loadingText");
       } else {
@@ -25385,24 +25101,36 @@ class Scopes extends _react.PureComponen
 } /* This Source Code Form is subject to the terms of the Mozilla Public
    * License, v. 2.0. If a copy of the MPL was not distributed with this
    * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 exports.default = (0, _reactRedux.connect)(state => {
   const selectedFrame = (0, _selectors.getSelectedFrame)(state);
   const selectedSource = (0, _selectors.getSelectedSource)(state);
 
-  const { scope: frameScopes, pending } = (0, _selectors.getFrameScope)(state, selectedSource && selectedSource.get("id"), selectedFrame && selectedFrame.id) || { scope: null, pending: false };
+  const {
+    scope: originalFrameScopes,
+    pending: originalPending
+  } = (0, _selectors.getOriginalFrameScope)(state, selectedSource && selectedSource.get("id"), selectedFrame && selectedFrame.id) || { scope: null, pending: false };
+
+  const {
+    scope: generatedFrameScopes,
+    pending: generatedPending
+  } = (0, _selectors.getGeneratedFrameScope)(state, selectedFrame && selectedFrame.id) || {
+    scope: null,
+    pending: false
+  };
 
   return {
     selectedFrame,
     isPaused: (0, _selectors.isPaused)(state),
-    isLoading: pending,
+    isLoading: generatedPending || originalPending,
     why: (0, _selectors.getPauseReason)(state),
-    frameScopes: frameScopes
+    originalFrameScopes,
+    generatedFrameScopes
   };
 }, dispatch => (0, _redux.bindActionCreators)(_actions2.default, dispatch))(Scopes);
 
 /***/ }),
 
 /***/ 1613:
 /***/ (function(module, exports, __webpack_require__) {
 
@@ -26237,17 +25965,17 @@ function _objectWithoutProperties(obj, k
 function mapScopes(scopes, frame) {
   return async function ({ dispatch, getState, client, sourceMaps }) {
     const generatedSourceRecord = (0, _selectors.getSource)(getState(), frame.generatedLocation.sourceId);
 
     const sourceRecord = (0, _selectors.getSource)(getState(), frame.location.sourceId);
 
     const shouldMapScopes = _prefs.features.mapScopes && !generatedSourceRecord.get("isWasm") && !sourceRecord.get("isPrettyPrinted") && !(0, _devtoolsSourceMap.isGeneratedId)(frame.location.sourceId);
 
-    dispatch({
+    await dispatch({
       type: "MAP_SCOPES",
       frame,
       [_promise.PROMISE]: async function () {
         if (!shouldMapScopes) {
           return null;
         }
 
         await dispatch((0, _loadSourceText.loadSourceText)(sourceRecord));
@@ -26268,37 +25996,47 @@ async function buildMappedScopes(source,
   const generatedAstScopes = await (0, _parser.getScopes)(frame.generatedLocation);
 
   if (!originalAstScopes || !generatedAstScopes) {
     return null;
   }
 
   const generatedAstBindings = buildGeneratedBindingList(scopes, generatedAstScopes, frame.this);
 
-  const mappedOriginalScopes = await Promise.all(Array.from(originalAstScopes, async item => {
+  const expressionLookup = {};
+  const mappedOriginalScopes = [];
+
+  for (const item of originalAstScopes) {
     const generatedBindings = {};
 
-    await Promise.all(Object.keys(item.bindings).map(async name => {
+    for (const name of Object.keys(item.bindings)) {
       const binding = item.bindings[name];
 
       const result = await findGeneratedBinding(sourceMaps, client, source, name, binding, generatedAstBindings);
 
       if (result) {
-        generatedBindings[name] = result;
-      }
+        generatedBindings[name] = result.grip;
+
+        if (binding.refs.length !== 0 &&
+        // These are assigned depth-first, so we don't want shadowed
+        // bindings in parent scopes overwriting the expression.
+        !Object.prototype.hasOwnProperty.call(expressionLookup, name)) {
+          expressionLookup[name] = result.expression;
+        }
+      }
+    }
+
+    mappedOriginalScopes.push(_extends({}, item, {
+      generatedBindings
     }));
-
-    return _extends({}, item, {
-      generatedBindings
-    });
-  }));
+  }
 
   const mappedGeneratedScopes = generateClientScope(scopes, mappedOriginalScopes);
 
-  return isReliableScope(mappedGeneratedScopes) ? mappedGeneratedScopes : null;
+  return isReliableScope(mappedGeneratedScopes) ? { mappings: expressionLookup, scope: mappedGeneratedScopes } : null;
 }
 
 /**
  * Consider a scope and its parents reliable if the vast majority of its
  * bindings were successfully mapped to generated scope bindings.
  */
 function isReliableScope(scope) {
   let totalBindings = 0;
@@ -26392,58 +26130,67 @@ async function findGeneratedBinding(sour
     if (result) {
       return result;
     }
 
     return await (0, _findGeneratedBindingFromPosition.findGeneratedBindingFromPosition)(sourceMaps, client, source, pos, name, originalBinding.type, generatedAstBindings);
   }, null);
 
   if (genContent && genContent.desc) {
-    return genContent.desc;
+    return {
+      grip: genContent.desc,
+      expression: genContent.expression
+    };
   } else if (genContent) {
     // If there is no descriptor for 'this', then this is not the top-level
     // 'this' that the server gave us a binding for, and we can just ignore it.
     if (name === "this") {
       return null;
     }
 
     // If the location is found but the descriptor is not, then it
     // means that the server scope information didn't match the scope
     // information from the DevTools parsed scopes.
     return {
-      configurable: false,
-      enumerable: true,
-      writable: false,
-      value: {
-        type: "unscoped",
-        unscoped: true,
-
-        // HACK: Until support for "unscoped" lands in devtools-reps,
-        // this will make these show as (unavailable).
-        missingArguments: true
-      }
+      grip: {
+        configurable: false,
+        enumerable: true,
+        writable: false,
+        value: {
+          type: "unscoped",
+          unscoped: true,
+
+          // HACK: Until support for "unscoped" lands in devtools-reps,
+          // this will make these show as (unavailable).
+          missingArguments: true
+        }
+      },
+      expression: null
     };
   }
 
   // If no location mapping is found, then the map is bad, or
   // the map is okay but it original location is inside
   // of some scope, but the generated location is outside, leading
   // us to search for bindings that don't technically exist.
   return {
-    configurable: false,
-    enumerable: true,
-    writable: false,
-    value: {
-      type: "unmapped",
-      unmapped: true,
-
-      // HACK: Until support for "unmapped" lands in devtools-reps,
-      // this will make these show as (unavailable).
-      missingArguments: true
-    }
+    grip: {
+      configurable: false,
+      enumerable: true,
+      writable: false,
+      value: {
+        type: "unmapped",
+        unmapped: true,
+
+        // HACK: Until support for "unmapped" lands in devtools-reps,
+        // this will make these show as (unavailable).
+        missingArguments: true
+      }
+    },
+    expression: null
   };
 }
 
 function buildGeneratedBindingList(scopes, generatedAstScopes, thisBinding) {
   const clientScopes = [];
   for (let s = scopes; s; s = s.parent) {
     clientScopes.push(s);
   }
@@ -27294,31 +27041,33 @@ function paused(pauseInfo) {
       loadedObjects: loadedObjects || []
     });
 
     const hiddenBreakpointLocation = (0, _selectors.getHiddenBreakpointLocation)(getState());
     if (hiddenBreakpointLocation) {
       dispatch((0, _breakpoints.removeBreakpoint)(hiddenBreakpointLocation));
     }
 
-    if (!(0, _selectors.isEvaluatingExpression)(getState())) {
-      dispatch((0, _expressions.evaluateExpressions)());
-    }
-
     await dispatch((0, _.mapFrames)());
     const selectedFrame = (0, _selectors.getSelectedFrame)(getState());
 
     if (selectedFrame) {
       const visibleFrame = (0, _selectors.getVisibleSelectedFrame)(getState());
       const location = (0, _devtoolsSourceMap.isGeneratedId)(visibleFrame.location.sourceId) ? selectedFrame.generatedLocation : selectedFrame.location;
       await dispatch((0, _sources.selectLocation)(location));
     }
 
     dispatch((0, _ui.togglePaneCollapse)("end", false));
-    dispatch((0, _fetchScopes.fetchScopes)());
+    await dispatch((0, _fetchScopes.fetchScopes)());
+
+    // Run after fetching scoping data so that it may make use of the sourcemap
+    // expression mappings for local variables.
+    if (!(0, _selectors.isEvaluatingExpression)(getState())) {
+      dispatch((0, _expressions.evaluateExpressions)());
+    }
   };
 }
 
 /***/ }),
 
 /***/ 1641:
 /***/ (function(module, exports, __webpack_require__) {
 
@@ -28003,16 +27752,17 @@ class QuickOpenModal extends _react.Comp
     const newResults = results && results.slice(0, 100);
     const items = this.highlightMatching(query, newResults || []);
     const expanded = !!items && items.length > 0;
     return _react2.default.createElement(
       _Modal2.default,
       { "in": enabled, handleClose: this.closeModal },
       _react2.default.createElement(_SearchInput2.default, {
         query: query,
+        hasPrefix: true,
         count: this.getResultCount(),
         placeholder: L10N.getStr("sourceSearch.search"),
         summaryMsg: "",
         showErrorEmoji: this.shouldShowErrorEmoji(),
         onChange: this.onChange,
         onKeyDown: this.onKeyDown,
         handleClose: this.closeModal,
         expanded: expanded,
@@ -28151,17 +27901,17 @@ function fetchScopes() {
     }
 
     const scopes = dispatch({
       type: "ADD_SCOPES",
       frame,
       [_promise.PROMISE]: client.getFrameScopes(frame)
     });
 
-    dispatch((0, _mapScopes.mapScopes)(scopes, frame));
+    await dispatch((0, _mapScopes.mapScopes)(scopes, frame));
   };
 } /* This Source Code Form is subject to the terms of the Mozilla Public
    * License, v. 2.0. If a copy of the MPL was not distributed with this
    * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 /***/ }),
 
 /***/ 1657:
@@ -30732,17 +30482,17 @@ var _getExpression = __webpack_require__
 
 var _selectors = __webpack_require__(3590);
 
 var _expressions = __webpack_require__(1398);
 
 var _lodash = __webpack_require__(2);
 
 async function getReactProps(evaluate) {
-  const reactDisplayName = await evaluate("this._reactInternalInstance.getName()");
+  const reactDisplayName = await evaluate("this.hasOwnProperty('_reactInternalFiber') ? " + "this._reactInternalFiber.type.name : " + "this._reactInternalInstance.getName()");
 
   return {
     displayName: reactDisplayName.result
   };
 }
 
 async function getImmutableProps(expression, evaluate) {
   const immutableEntries = await evaluate((exp => `${exp}.toJS()`)(expression));
@@ -30844,17 +30594,17 @@ function setPreview(expression, location
       type: "SET_PREVIEW",
       [_promise.PROMISE]: async function () {
         const source = (0, _selectors.getSelectedSource)(getState());
 
         const sourceId = source.get("id");
         if (location && !(0, _devtoolsSourceMap.isGeneratedId)(sourceId)) {
           const generatedLocation = await sourceMaps.getGeneratedLocation(_extends({}, location.start, { sourceId }), source.toJS());
 
-          expression = await (0, _expressions.getMappedExpression)({ sourceMaps }, generatedLocation, expression);
+          expression = await (0, _expressions.getMappedExpression)({ sourceMaps, getState }, generatedLocation, expression);
         }
 
         const selectedFrame = (0, _selectors.getSelectedFrame)(getState());
         if (!selectedFrame) {
           return;
         }
 
         const { result } = await client.evaluateInFrame(selectedFrame.id, expression);
@@ -31124,16 +30874,18 @@ Object.defineProperty(exports, "__esModu
 });
 
 var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; /* This Source Code Form is subject to the terms of the Mozilla Public
                                                                                                                                                                                                                                                                    * License, v. 2.0. If a copy of the MPL was not distributed with this
                                                                                                                                                                                                                                                                    * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 exports.getScope = getScope;
 
+var _devtoolsReps = __webpack_require__(1408);
+
 var _getVariables = __webpack_require__(1765);
 
 var _utils = __webpack_require__(1766);
 
 var _frames = __webpack_require__(3605);
 
 function getScopeTitle(type, scope) {
   if (type === "block" && scope.block && scope.block.displayName) {
@@ -31178,17 +30930,18 @@ function getScope(scope, selectedFrame, 
     }
 
     if (vars && vars.length) {
       const title = getScopeTitle(type, scope);
       vars.sort((a, b) => a.name.localeCompare(b.name));
       return {
         name: title,
         path: key,
-        contents: vars
+        contents: vars,
+        type: _devtoolsReps.ObjectInspectorUtils.node.NODE_TYPES.BLOCK
       };
     }
   } else if (type === "object" && scope.object) {
     let value = scope.object;
     // If this is the global window scope, mark it as such so that it will
     // preview Window: Global instead of Window: Window
     if (value.class === "Window") {
       value = _extends({}, scope.object, { displayClass: "Global" });
@@ -32450,17 +32203,17 @@ function isReactComponent(result) {
     return;
   }
 
   const ownProperties = result.preview.ownProperties;
   if (!ownProperties) {
     return;
   }
 
-  return Object.keys(ownProperties).includes("_reactInternalInstance");
+  return Object.keys(ownProperties).includes("_reactInternalInstance") || Object.keys(ownProperties).includes("_reactInternalFiber");
 }
 
 /***/ }),
 
 /***/ 1808:
 /***/ (function(module, exports) {
 
 module.exports = "<!-- This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. --><svg viewBox=\"0 0 256 247\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" preserveAspectRatio=\"xMidYMid\"><defs><radialGradient cx=\"78.7636112%\" cy=\"37.8476394%\" fx=\"78.7636112%\" fy=\"37.8476394%\" r=\"89.8725577%\" id=\"radialGradient-1\"><stop stop-color=\"#F80090\" offset=\"0%\"></stop><stop stop-color=\"#4D008E\" offset=\"100%\"></stop></radialGradient><radialGradient cx=\"68.7389016%\" cy=\"4.39833672%\" fx=\"68.7389016%\" fy=\"4.39833672%\" r=\"81.7284786%\" id=\"radialGradient-2\"><stop stop-color=\"#57008E\" offset=\"0%\"></stop><stop stop-color=\"#5C008E\" offset=\"29.1746283%\"></stop><stop stop-color=\"#F80090\" offset=\"100%\"></stop></radialGradient><linearGradient x1=\"18.2386532%\" y1=\"0%\" x2=\"81.1591125%\" y2=\"84.3374763%\" id=\"linearGradient-3\"><stop stop-color=\"#F70090\" offset=\"0%\"></stop><stop stop-color=\"#E50090\" offset=\"66.9712865%\"></stop><stop stop-color=\"#D6008F\" stop-opacity=\"0.2\" offset=\"82.7147533%\"></stop><stop stop-color=\"#C10090\" stop-opacity=\"0\" offset=\"100%\"></stop></linearGradient><linearGradient x1=\"64.9060589%\" y1=\"71.5585538%\" x2=\"44.2897699%\" y2=\"50%\" id=\"linearGradient-4\"><stop stop-color=\"#B2008F\" stop-opacity=\"0.151340138\" offset=\"0%\"></stop><stop stop-color=\"#F70090\" stop-opacity=\"0.4\" offset=\"40.0350765%\"></stop><stop stop-color=\"#F60090\" stop-opacity=\"0.891668\" offset=\"64.8995536%\"></stop><stop stop-color=\"#FF0090\" offset=\"100%\"></stop></linearGradient></defs><g><path d=\"M16.6852208,157.125328 C3.56690702,87.3798324 38.2363025,20.1145078 117.808706,11.1662199 C106.835616,-0.558801732 91.8452087,-0.646905628 84.9481697,0.779380087 C72.770288,4.66044372 73.1525932,12.540855 59.3390152,22.7199675 C45.6064437,30.5634307 38.7094156,24.5568182 28.7057455,32.6879515 C18.7234849,40.7583874 25.6888528,59.2851732 21.5022823,62.8870857 C17.3464381,70.0905489 4.45500952,76.5077264 2.10834286,85.6062545 C0.168948918,97.2420641 7.37241212,105.553752 7.09535584,115.527778 C7.92652468,123.839467 -1.17920693,128.539449 0.129052814,135.275796 C4.0477368,146.281025 11.600845,152.904887 15.1615723,155.958047 C15.9781085,156.533531 16.8404881,157.95083 16.6852208,157.125328 L16.6852208,157.125328 Z\" fill=\"#FF0090\"></path><path d=\"M158.275491,60.578542 C155.368486,60.578542 153.011422,58.2214776 153.011422,55.3144727 C153.011422,52.4074679 155.368486,50.0504035 158.275491,50.0504035 C161.182496,50.0504035 163.53956,52.4074679 163.53956,55.3144727 C163.53956,58.2214776 161.182496,60.578542 158.275491,60.578542 L158.275491,60.578542 Z M19.7566405,164.732808 C7.1500258,104.116773 46.1602355,53.4676156 121.704062,78.4026805 C166.031404,104.334594 221.793282,102.646102 224.307422,85.8832 C230.514061,65.7878769 196.047681,24.3767065 144.515214,13.5715117 C42.2814476,-6.37654026 -12.8335943,104.116774 19.7566405,164.732808 L19.7566405,164.732808 Z\" fill=\"url(#radialGradient-1)\"></path><path d=\"M187.458604,171.493257 C202.639072,173.137863 217.048769,169.494573 230.402327,158.61014 C210.228197,181.112651 185.002777,192.426521 156.059262,195.505171 C169.878829,207.254019 183.20579,212.546348 195.955366,210.281136 C160.528734,220.05679 130.847947,209.296529 94.7424273,173.340673 C92.8517347,183.020022 103.074741,198.100667 113.611745,207.727264 C52.4742909,181.221845 47.1143627,98.6544556 121.66531,78.3442237 C44.3844415,41.214641 0.686373501,113.357693 22.1558444,172.485931 C43.1623368,218.026693 99.1402667,253.085223 160.492163,245.3753 C190.292928,241.7251 234.79401,221.178935 252.973664,172.485931 C240.160919,183.983766 217.257941,193.997836 207.037617,194.765984 C241.628648,177.478781 260.301586,148.103896 255.060336,107.955387 C247.895106,125.013742 238.441392,138.114625 226.616076,147.112305 C251.735653,107.955387 247.425219,87.716426 228.832526,65.4732398 C242.131228,102.044668 224.928249,142.633967 187.458604,171.493257 L187.458604,171.493257 Z\" fill=\"url(#radialGradient-2)\"></path><path d=\"M169.707072,213.625541 C167.082407,213.13513 175.656929,217.098842 159.079366,212.710316 C142.501804,208.32179 125.622502,204.092744 94.7424273,173.340673 C92.8517347,183.020022 103.074741,198.100667 113.611745,207.727264 C142.056275,227.564927 122.711866,218.286797 166.051946,233.269481 C169.52976,226.346862 169.707072,220.195346 169.707072,213.625541 L169.707072,213.625541 Z\" fill=\"url(#linearGradient-3)\"></path><path d=\"M114.601372,57.8510108 C114.601372,57.8510108 118.369452,52.2893628 119.836219,49.7810251 C121.633641,46.7072319 124.393939,41.104618 124.393939,41.104618 C124.393939,41.104618 95.389611,31.6417749 88.2716448,30.4871665 C66.1450215,36.2308801 66.0645022,45.5009559 78.435065,59.690116 C79.8114806,61.2693368 114.601372,57.8510108 114.601372,57.8510108 L114.601372,57.8510108 Z\" fill=\"url(#linearGradient-4)\"></path></g></svg>"
@@ -32495,21 +32248,23 @@ module.exports = ReactPropTypesSecret;
 
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const client = __webpack_require__(1939);
 const loadProperties = __webpack_require__(2017);
 const node = __webpack_require__(1940);
+const selection = __webpack_require__(3616);
 
 module.exports = {
   client,
   loadProperties,
-  node
+  node,
+  selection
 };
 
 /***/ }),
 
 /***/ 1939:
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -32601,29 +32356,30 @@ const ArrayRep = __webpack_require__(144
 const GripArrayRep = __webpack_require__(1450);
 const GripMap = __webpack_require__(1584);
 const GripMapEntryRep = __webpack_require__(1451);
 
 const MAX_NUMERICAL_PROPERTIES = 100;
 
 const NODE_TYPES = {
   BUCKET: Symbol("[n…n]"),
-  DEFAULT_PROPERTIES: Symbol("[default properties]"),
+  DEFAULT_PROPERTIES: Symbol("<default properties>"),
   ENTRIES: Symbol("<entries>"),
   GET: Symbol("<get>"),
   GRIP: Symbol("GRIP"),
   MAP_ENTRY_KEY: Symbol("<key>"),
   MAP_ENTRY_VALUE: Symbol("<value>"),
   PROMISE_REASON: Symbol("<reason>"),
   PROMISE_STATE: Symbol("<state>"),
   PROMISE_VALUE: Symbol("<value>"),
   PROXY_HANDLER: Symbol("<handler>"),
   PROXY_TARGET: Symbol("<target>"),
   SET: Symbol("<set>"),
-  PROTOTYPE: Symbol("__proto__")
+  PROTOTYPE: Symbol("<prototype>"),
+  BLOCK: Symbol("☲")
 };
 
 let WINDOW_PROPERTIES = {};
 
 if (typeof window === "object") {
   WINDOW_PROPERTIES = Object.getOwnPropertyNames(window);
 }
 
@@ -32761,16 +32517,20 @@ function nodeIsWindow(item) {
 function nodeIsGetter(item) {
   return getType(item) === NODE_TYPES.GET;
 }
 
 function nodeIsSetter(item) {
   return getType(item) === NODE_TYPES.SET;
 }
 
+function nodeIsBlock(item) {
+  return getType(item) === NODE_TYPES.BLOCK;
+}
+
 function nodeHasAccessors(item) {
   return !!getNodeGetter(item) || !!getNodeSetter(item);
 }
 
 function nodeSupportsNumericalBucketing(item) {
   // We exclude elements with entries since it's the <entries> node
   // itself that can have buckets.
   return nodeIsArrayLike(item) && !nodeHasEntries(item) || nodeIsEntries(item) || nodeIsBucket(item);
@@ -32950,17 +32710,17 @@ function makeDefaultPropsBucket(properti
     } else {
       userPropertiesNames.push(name);
     }
   });
 
   let nodes = makeNodesForOwnProps(userPropertiesNames, parent, ownProperties);
 
   if (defaultProperties.length > 0) {
-    const defaultPropertiesNode = createNode(parent, "[default properties]", `${parentPath}/${SAFE_PATH_PREFIX}default`, null, NODE_TYPES.DEFAULT_PROPERTIES);
+    const defaultPropertiesNode = createNode(parent, "<default properties>", `${parentPath}/${SAFE_PATH_PREFIX}default`, null, NODE_TYPES.DEFAULT_PROPERTIES);
 
     const defaultNodes = defaultProperties.map((name, index) => createNode(defaultPropertiesNode, maybeEscapePropertyName(name), `${parentPath}/${SAFE_PATH_PREFIX}bucket${index}/${name}`, ownProperties[name]));
     nodes.push(setNodeChildren(defaultPropertiesNode, defaultNodes));
   }
   return nodes;
 }
 
 function makeNodesForOwnProps(propertiesNames, parent, ownProperties) {
@@ -32974,17 +32734,17 @@ function makeNodesForProperties(objProps
     ownSymbols,
     prototype,
     safeGetterValues
   } = objProps;
 
   const parentPath = parent.path;
   const parentValue = getValue(parent);
 
-  let allProperties = Object.assign({}, ownProperties, safeGetterValues);
+  let allProperties = { ...ownProperties, ...safeGetterValues };
 
   // Ignore properties that are neither non-concrete nor getters/setters.
   const propertiesNames = sortProperties(Object.keys(allProperties)).filter(name => {
     if (!allProperties[name]) {
       return false;
     }
 
     const properties = Object.getOwnPropertyNames(allProperties[name]);
@@ -33022,17 +32782,17 @@ function makeNodesForProperties(objProps
 
 function makeNodeForPrototype(objProps, parent) {
   const {
     prototype
   } = objProps || {};
 
   // Add the prototype if it exists and is not null
   if (prototype && prototype.type !== "null") {
-    return createNode(parent, "__proto__", `${parent.path}/__proto__`, { value: prototype }, NODE_TYPES.PROTOTYPE);
+    return createNode(parent, "<prototype>", `${parent.path}/<prototype>`, { value: prototype }, NODE_TYPES.PROTOTYPE);
   }
 
   return null;
 }
 
 function createNode(parent, name, path, contents, type = NODE_TYPES.GRIP, meta) {
   if (contents === undefined) {
     return null;
@@ -33211,16 +32971,17 @@ module.exports = {
   makeNodesForPromiseProperties,
   makeNodesForProperties,
   makeNumericalBuckets,
   nodeHasAccessors,
   nodeHasAllEntriesInPreview,
   nodeHasChildren,
   nodeHasEntries,
   nodeHasProperties,
+  nodeIsBlock,
   nodeIsBucket,
   nodeIsDefaultProperties,
   nodeIsEntries,
   nodeIsFunction,
   nodeIsGetter,
   nodeIsMapEntry,
   nodeIsMissingArguments,
   nodeIsObject,
@@ -33342,16 +33103,22 @@ function getTabMenuItems() {
       disabled: false
     },
     showSource: {
       id: "node-menu-show-source",
       label: L10N.getStr("sourceTabs.revealInTree"),
       accesskey: L10N.getStr("sourceTabs.revealInTree.accesskey"),
       disabled: false
     },
+    copyToClipboard: {
+      id: "node-menu-copy-to-clipboard",
+      label: L10N.getStr("copyToClipboard.label"),
+      accesskey: L10N.getStr("copyToClipboard.accesskey"),
+      disabled: false
+    },
     copySourceUri2: {
       id: "node-menu-copy-source-url",
       label: L10N.getStr("copySourceUri2"),
       accesskey: L10N.getStr("copySourceUri2.accesskey"),
       disabled: false
     },
     prettyPrint: {
       id: "node-menu-pretty-print",
@@ -33801,23 +33568,16 @@ function highlightMatches(lineMatch) {
 
 /***/ 2011:
 /***/ (function(module, exports) {
 
 // removed by extract-text-webpack-plugin
 
 /***/ }),
 
-/***/ 2012:
-/***/ (function(module, exports) {
-
-module.exports = "<!-- This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. --><svg viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/svg\"><g stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\" stroke-linecap=\"round\"><g id=\"arrow\" transform=\"translate(1.000000, 3.000000)\"><path d=\"M4.5,0.5 L6.5,2.5\"></path><path d=\"M4.5,2.5 L6.5,4.5\" transform=\"translate(5.500000, 3.500000) scale(1, -1) translate(-5.500000, -3.500000) \"></path><path d=\"M6.00090144,2.5 C4.67806937,2.5 3.67938478,2.5 3.00484766,2.5 C1.99304199,2.5 1.01049805,3.5168457 0.993840144,4.52403846 C0.988750751,4.54723808 0.988750751,5.87097168 0.993840144,8.49523926\" id=\"Path-2\" stroke-linejoin=\"round\"></path></g><g id=\"content-lines\" transform=\"translate(9.000000, 2.000000)\"><path d=\"M1.5,3.5 L5.5,3.5\"></path><path d=\"M0.5,1.5 L5.5,1.5\"></path><path d=\"M0.5,5.5 L5.5,5.5\"></path></g></g></svg>"
-
-/***/ }),
-
 /***/ 2017:
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -33843,69 +33603,66 @@ const {
   nodeIsEntries,
   nodeIsMapEntry,
   nodeIsPrimitive,
   nodeIsProxy,
   nodeNeedsNumericalBuckets
 } = __webpack_require__(1940);
 
 function loadItemProperties(item, createObjectClient, loadedProperties) {
+  const gripItem = getClosestGripNode(item);
+  const value = getValue(gripItem);
+
   const [start, end] = item.meta ? [item.meta.startIndex, item.meta.endIndex] : [];
 
+  let promises = [];
   let objectClient;
-  const getObjectClient = () => {
-    if (objectClient) {
-      return objectClient;
-    }
-
-    const gripItem = getClosestGripNode(item);
-    const value = getValue(gripItem);
-    return createObjectClient(value);
-  };
-
-  let loadingPromises = [];
+  const getObjectClient = () => objectClient || createObjectClient(value);
+
   if (shouldLoadItemIndexedProperties(item, loadedProperties)) {
-    loadingPromises.push(enumIndexedProperties(getObjectClient(), start, end));
+    promises.push(enumIndexedProperties(getObjectClient(), start, end));
   }
 
   if (shouldLoadItemNonIndexedProperties(item, loadedProperties)) {
-    loadingPromises.push(enumNonIndexedProperties(getObjectClient(), start, end));
+    promises.push(enumNonIndexedProperties(getObjectClient(), start, end));
   }
 
   if (shouldLoadItemEntries(item, loadedProperties)) {
-    loadingPromises.push(enumEntries(getObjectClient(), start, end));
+    promises.push(enumEntries(getObjectClient(), start, end));
   }
 
   if (shouldLoadItemPrototype(item, loadedProperties)) {
-    loadingPromises.push(getPrototype(getObjectClient()));
+    promises.push(getPrototype(getObjectClient()));
   }
 
   if (shouldLoadItemSymbols(item, loadedProperties)) {
-    loadingPromises.push(enumSymbols(getObjectClient(), start, end));
-  }
-
-  if (loadingPromises.length === 0) {
-    return null;
-  }
-
-  return Promise.all(loadingPromises).then(responses => responses.reduce((accumulator, res) => {
-    // Let's loop through the responses to build a single response object.
-    Object.entries(res).forEach(([k, v]) => {
-      if (accumulator.hasOwnProperty(k)) {
-        if (Array.isArray(accumulator[k])) {
-          accumulator[k].push(...v);
-        } else if (typeof accumulator[k] === "object") {
-          accumulator[k] = Object.assign({}, accumulator[k], v);
-        }
-      } else {
-        accumulator[k] = v;
-      }
-    });
-    return accumulator;
-  }, {}));
+    promises.push(enumSymbols(getObjectClient(), start, end));
+  }
+
+  return Promise.all(promises).then(mergeResponses);
+}
+
+function mergeResponses(responses) {
+  const data = {};
+
+  for (const response of responses) {
+    if (response.hasOwnProperty("ownProperties")) {
+      data.ownProperties = { ...data.ownProperties, ...response.ownProperties };
+    }
+
+    if (response.ownSymbols && response.ownSymbols.length > 0) {
+      data.ownSymbols = response.ownSymbols;
+    }
+
+    if (response.prototype) {
+      data.prototype = response.prototype;
+    }
+  }
+
+  return data;
 }
 
 function shouldLoadItemIndexedProperties(item, loadedProperties = new Map()) {
   const gripItem = getClosestGripNode(item);
   const value = getValue(gripItem);
 
   return value && nodeHasProperties(gripItem) && !loadedProperties.has(item.path) && !nodeIsProxy(item) && !nodeNeedsNumericalBuckets(item) && !nodeIsEntries(getClosestNonBucketNode(item))
   // The data is loaded when expanding the window node.
@@ -33937,16 +33694,17 @@ function shouldLoadItemPrototype(item, l
 function shouldLoadItemSymbols(item, loadedProperties = new Map()) {
   const value = getValue(item);
 
   return value && !loadedProperties.has(item.path) && !nodeIsBucket(item) && !nodeIsMapEntry(item) && !nodeIsEntries(item) && !nodeIsDefaultProperties(item) && !nodeHasAccessors(item) && !nodeIsPrimitive(item) && !nodeIsProxy(item);
 }
 
 module.exports = {
   loadItemProperties,
+  mergeResponses,
   shouldLoadItemEntries,
   shouldLoadItemIndexedProperties,
   shouldLoadItemNonIndexedProperties,
   shouldLoadItemPrototype,
   shouldLoadItemSymbols
 };
 
 /***/ }),
@@ -34008,17 +33766,18 @@ class Tab extends _react.PureComponent {
   }
 
   showContextMenu(e, tab) {
     const {
       closeTab,
       closeTabs,
       tabSources,
       showSource,
-      togglePrettyPrint
+      togglePrettyPrint,
+      selectedSource
     } = this.props;
 
     const otherTabs = tabSources.filter(t => t.get("id") !== tab);
     const sourceTab = tabSources.find(t => t.get("id") == tab);
     const tabURLs = tabSources.map(t => t.get("url"));
     const otherTabURLs = otherTabs.map(t => t.get("url"));
 
     if (!sourceTab) {
@@ -34042,16 +33801,21 @@ class Tab extends _react.PureComponent {
           const tabIndex = tabSources.findIndex(t => t.get("id") == tab);
           closeTabs(tabURLs.filter((t, i) => i > tabIndex));
         }
       }),
       hidden: () => tabSources.size === 1 || tabSources.some((t, i) => t === tab && tabSources.size - 1 === i)
     }, {
       item: _extends({}, tabMenuItems.closeAllTabs, { click: () => closeTabs(tabURLs) })
     }, { item: { type: "separator" } }, {
+      item: _extends({}, tabMenuItems.copyToClipboard, {
+        disabled: selectedSource.get("id") !== tab,
+        click: () => (0, _clipboard.copyToTheClipboard)(sourceTab.get("text"))
+      })
+    }, {
       item: _extends({}, tabMenuItems.copySourceUri2, {
         click: () => (0, _clipboard.copyToTheClipboard)((0, _source.getRawSourceURL)(sourceTab.get("url")))
       })
     }];
 
     items.push({
       item: _extends({}, tabMenuItems.showSource, { click: () => showSource(tab) })
     });
@@ -34317,23 +34081,16 @@ function setupHelper(obj) {
     console.log("Debugging Tips", localDevelopmentUrl);
     console.log("dbg", window.dbg);
     console.groupEnd();
   }
 }
 
 /***/ }),
 
-/***/ 2247:
-/***/ (function(module, exports) {
-
-module.exports = "<!-- This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. --><svg viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M8 13.4c-.5 0-.9-.2-1.2-.6L.4 5.2C0 4.7-.1 4.3.2 3.7S1 3 1.6 3h12.8c.6 0 1.2.1 1.4.7.3.6.2 1.1-.2 1.6l-6.4 7.6c-.3.4-.7.5-1.2.5z\"></path></svg>"
-
-/***/ }),
-
 /***/ 2248:
 /***/ (function(module, exports) {
 
 // removed by extract-text-webpack-plugin
 
 /***/ }),
 
 /***/ 2249:
@@ -34892,17 +34649,18 @@ async function mapBindingReferenceToDesc
   // Allow the mapping to point anywhere within the generated binding
   // location to allow for less than perfect sourcemaps. Since you also
   // need at least one character between identifiers, we also give one
   // characters of space at the front the generated binding in order
   // to increase the probability of finding the right mapping.
   if (mapped.start.line === binding.loc.start.line && (0, _locColumn.locColumn)(mapped.start) >= (0, _locColumn.locColumn)(binding.loc.start) - 1 && (0, _locColumn.locColumn)(mapped.start) <= (0, _locColumn.locColumn)(binding.loc.end)) {
     return {
       name: binding.name,
-      desc: binding.desc
+      desc: binding.desc,
+      expression: binding.name
     };
   }
 
   return null;
 }
 
 /**
  * Given an generated binding, and a range over the generated code, statically
@@ -34913,44 +34671,33 @@ async function mapBindingReferenceToDesc
  */
 async function mapImportDeclarationToDescriptor(binding, mapped) {
   // When trying to map an actual import declaration binding, we can try
   // to map it back to the namespace object in the original code.
   if (!mappingContains(mapped, binding.loc)) {
     return null;
   }
 
-  let desc = binding.desc;
-  if (desc && typeof desc.value === "object") {
-    if (desc.value.optimizedOut) {
-      // If the value was optimized out, we skip it entirely because there is
-      // a good chance that this means that this isn't the right binding. This
-      // allows us to catch cases like
-      //
-      //   var _mod = require(...);
-      //   var _mod2 = _interopRequire(_mod);
-      //
-      // where "_mod" is optimized out because it is only referenced once, and
-      // we want to continue searching to try to find "_mod2".
-      return null;
-    }
-
-    if (desc.value.type !== "object") {
-      // If we got a non-primitive descriptor but it isn't an object, then
-      // it's definitely not the namespace.
-      return null;
-    }
-
-    const objectClient = (0, _firefox.createObjectClient)(desc.value);
-    desc = (await objectClient.getProperty(mapped.importName)).descriptor;
-  }
+  const desc = await readDescriptorProperty(binding.desc, mapped.importName,
+  // If the value was optimized out or otherwise unavailable, we skip it
+  // entirely because there is a good chance that this means that this
+  // isn't the right binding. This allows us to catch cases like
+  //
+  //   var _mod = require(...);
+  //   var _mod2 = _interopRequire(_mod);
+  //
+  // where "_mod" is optimized out because it is only referenced once, and
+  // we want to continue searching to try to find "_mod2".
+  true);
+  const expression = `${binding.name}.${mapped.importName}`;
 
   return desc ? {
     name: binding.name,
-    desc
+    desc,
+    expression
   } : null;
 }
 
 /**
  * Given an generated binding, and a range over the generated code, statically
  * evaluate accessed properties within the mapped range to resolve the actual
  * imported value.
  */
@@ -34985,16 +34732,17 @@ async function mapImportReferenceToDescr
   //   Object(foo.bar)()
   //   ^^^^^^^^^^^^^^^^^
   //   ^                 // wrapped to column 0 of next line
 
   if (!mappingContains(mapped, binding.loc)) {
     return null;
   }
 
+  let expression = binding.name;
   let desc = binding.desc;
 
   if (binding.loc.type === "ref") {
     const { meta } = binding.loc;
 
     // Limit to 2 simple property or inherits operartions, since it would
     // just be more work to search more and it is very unlikely that
     // bindings would be mapped to more than a single member + inherits
@@ -35005,27 +34753,63 @@ async function mapImportReferenceToDescr
       if (op.type === "call") {
         return null;
       }
 
       if (op.type === "inherit") {
         continue;
       }
 
-      const objectClient = (0, _firefox.createObjectClient)(desc.value);
-      desc = (await objectClient.getProperty(op.property)).descriptor;
+      desc = await readDescriptorProperty(desc, op.property);
+      expression += `.${op.property}`;
     }
   }
 
   return desc ? {
     name: binding.name,
-    desc
+    desc,
+    expression
   } : null;
 }
 
+async function readDescriptorProperty(desc, property, requireValidObject = false) {
+  if (!desc) {
+    return null;
+  }
+
+  if (typeof desc.value !== "object" || !desc.value) {
+    if (requireValidObject) {
+      return null;
+    }
+
+    // If accessing a property on a primitive type, just return 'undefined'
+    // as the value.
+    return {
+      value: {
+        type: "undefined"
+      }
+    };
+  }
+
+  // Note: The check for `.type` might already cover the optimizedOut case
+  // but not 100% sure, so just being cautious.
+  if (desc.value.type !== "object" || desc.value.optimizedOut) {
+    if (requireValidObject) {
+      return null;
+    }
+
+    // If we got a non-primitive descriptor but it isn't an object, then
+    // it's definitely not the namespace and it is probably an error.
+    return desc;
+  }
+
+  const objectClient = (0, _firefox.createObjectClient)(desc.value);
+  return (await objectClient.getProperty(property)).descriptor;
+}
+
 function mappingContains(mapped, item) {
   return (item.start.line > mapped.start.line || item.start.line === mapped.start.line && (0, _locColumn.locColumn)(item.start) >= (0, _locColumn.locColumn)(mapped.start)) && (item.end.line < mapped.end.line || item.end.line === mapped.end.line && (0, _locColumn.locColumn)(item.end) <= (0, _locColumn.locColumn)(mapped.end));
 }
 
 async function getGeneratedLocationRange(pos, source, sourceMaps) {
   const start = await sourceMaps.getGeneratedLocation(pos.start, source);
   const end = await sourceMaps.getGeneratedLocation(pos.end, source);
 
@@ -37973,23 +37757,797 @@ class VisibilityHandler extends _react.C
     return this.isVisible ? this.props.children : null;
   }
 }
 
 module.exports = VisibilityHandler;
 
 /***/ }),
 
+/***/ 3614:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// ReactJS
+const PropTypes = __webpack_require__(20);
+
+// Reps
+const {
+  getGripType,
+  isGrip,
+  wrapRender
+} = __webpack_require__(1353);
+const dom = __webpack_require__(1758);
+const { span } = dom;
+
+/**
+ * Renders DOM documentType object.
+ */
+DocumentType.propTypes = {
+  object: PropTypes.object.isRequired
+};
+
+function DocumentType(props) {
+  const { object } = props;
+  let name = object && object.preview && object.preview.nodeName ? ` ${object.preview.nodeName}` : "";
+  return span({
+    "data-link-actor-id": props.object.actor,
+    className: "objectBox objectBox-document"
+  }, `<!DOCTYPE${name}>`);
+}
+
+// Registration
+function supportsObject(object, noGrip = false) {
+  if (noGrip === true || !isGrip(object)) {
+    return false;
+  }
+
+  const type = getGripType(object, noGrip);
+  return object.preview && type === "DocumentType";
+}
+
+// Exports from this module
+module.exports = {
+  rep: wrapRender(DocumentType),
+  supportsObject
+};
+
+/***/ }),
+
+/***/ 3615:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+var _devtoolsComponents = __webpack_require__(1441);
+
+var _devtoolsComponents2 = _interopRequireDefault(_devtoolsComponents);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const {
+  Component,
+  createFactory
+} = __webpack_require__(0);
+const dom = __webpack_require__(1758);
+const { connect } = __webpack_require__(3592);
+const { bindActionCreators } = __webpack_require__(3593);
+
+const Tree = createFactory(_devtoolsComponents2.default.Tree);
+__webpack_require__(1325);
+
+const classnames = __webpack_require__(175);
+
+const {
+  REPS: {
+    Rep,
+    Grip
+  }
+} = __webpack_require__(1372);
+const {
+  MODE
+} = __webpack_require__(1357);
+
+const Utils = __webpack_require__(1938);
+
+const {
+  getChildren,
+  getClosestGripNode,
+  getParent,
+  getValue,
+  nodeHasAccessors,
+  nodeHasProperties,
+  nodeIsBlock,
+  nodeIsDefaultProperties,
+  nodeIsFunction,
+  nodeIsGetter,
+  nodeIsMapEntry,
+  nodeIsMissingArguments,
+  nodeIsOptimizedOut,
+  nodeIsPrimitive,
+  nodeIsPrototype,
+  nodeIsSetter,
+  nodeIsUninitializedBinding,
+  nodeIsUnmappedBinding,
+  nodeIsUnscopedBinding,
+  nodeIsWindow
+} = Utils.node;
+
+// This implements a component that renders an interactive inspector
+// for looking at JavaScript objects. It expects descriptions of
+// objects from the protocol, and will dynamically fetch children
+// properties as objects are expanded.
+//
+// If you want to inspect a single object, pass the name and the
+// protocol descriptor of it:
+//
+//  ObjectInspector({
+//    name: "foo",
+//    desc: { writable: true, ..., { value: { actor: "1", ... }}},
+//    ...
+//  })
+//
+// If you want multiple top-level objects (like scopes), you can pass
+// an array of manually constructed nodes as `roots`:
+//
+//  ObjectInspector({
+//    roots: [{ name: ... }, ...],
+//    ...
+//  });
+
+// There are 3 types of nodes: a simple node with a children array, an
+// object that has properties that should be children when they are
+// fetched, and a primitive value that should be displayed with no
+// children.
+
+class ObjectInspector extends Component {
+  constructor(props) {
+    super();
+    this.cachedNodes = new Map();
+
+    const self = this;
+
+    self.getItemChildren = this.getItemChildren.bind(this);
+    self.renderTreeItem = this.renderTreeItem.bind(this);
+    self.setExpanded = this.setExpanded.bind(this);
+    self.focusItem = this.focusItem.bind(this);
+    self.getRoots = this.getRoots.bind(this);
+  }
+
+  shouldComponentUpdate(nextProps) {
+    const {
+      expandedPaths,
+      loadedProperties,
+      roots
+    } = this.props;
+
+    if (roots !== nextProps.roots) {
+      // Since the roots changed, we assume the properties did as well. Thus we can clear
+      // the cachedNodes to avoid bugs and memory leaks.
+      this.cachedNodes.clear();
+      return true;
+    }
+
+    return expandedPaths.size !== nextProps.expandedPaths.size || loadedProperties.size !== nextProps.loadedProperties.size || [...expandedPaths].some(key => !nextProps.expandedPaths.has(key));
+  }
+
+  componentWillUnmount() {
+    const { releaseActor } = this.props;
+    if (typeof releaseActor !== "function") {
+      return;
+    }
+
+    const { actors } = this.props;
+    for (let actor of actors) {
+      releaseActor(actor);
+    }
+  }
+
+  getItemChildren(item) {
+    const {
+      loadedProperties
+    } = this.props;
+    const { cachedNodes } = this;
+
+    return getChildren({
+      loadedProperties,
+      cachedNodes,
+      item
+    });
+  }
+
+  getRoots() {
+    return this.props.roots;
+  }
+
+  getNodeKey(item) {
+    return item.path || JSON.stringify(item);
+  }
+
+  setExpanded(item, expand) {
+    if (nodeIsPrimitive(item)) {
+      return;
+    }
+
+    const {
+      createObjectClient,
+      loadedProperties,
+      nodeExpand,
+      nodeCollapse,
+      roots
+    } = this.props;
+
+    if (expand === true) {
+      const gripItem = getClosestGripNode(item);
+      const value = getValue(gripItem);
+      const isRoot = value && roots.some(root => {
+        const rootValue = getValue(root);
+        return rootValue && rootValue.actor === value.actor;
+      });
+      const actor = isRoot || !value ? null : value.actor;
+      nodeExpand(item, actor, loadedProperties, createObjectClient);
+    } else {
+      nodeCollapse(item);
+    }
+  }
+
+  focusItem(item) {
+    const {
+      focusedItem,
+      onFocus
+    } = this.props;
+
+    if (focusedItem !== item && onFocus) {
+      onFocus(item);
+    }
+  }
+
+  getTreeItemLabelAndValue(item, depth, expanded) {
+    let label = item.name;
+    const isPrimitive = nodeIsPrimitive(item);
+
+    if (nodeIsOptimizedOut(item)) {
+      return {
+        label,
+        value: dom.span({ className: "unavailable" }, "(optimized away)")
+      };
+    }
+
+    if (nodeIsUninitializedBinding(item)) {
+      return {
+        label,
+        value: dom.span({ className: "unavailable" }, "(uninitialized)")
+      };
+    }
+
+    if (nodeIsUnmappedBinding(item)) {
+      return {
+        label,
+        value: dom.span({ className: "unavailable" }, "(unmapped)")
+      };
+    }
+
+    if (nodeIsUnscopedBinding(item)) {
+      return {
+        label,
+        value: dom.span({ className: "unavailable" }, "(unscoped)")
+      };
+    }
+
+    if (nodeIsOptimizedOut(item)) {
+      return {
+        label,
+        value: dom.span({ className: "unavailable" }, "(optimized away)")
+      };
+    }
+
+    const itemValue = getValue(item);
+    const unavailable = isPrimitive && itemValue && itemValue.hasOwnProperty && itemValue.hasOwnProperty("unavailable");
+
+    if (nodeIsMissingArguments(item) || unavailable) {
+      return {
+        label,
+        value: dom.span({ className: "unavailable" }, "(unavailable)")
+      };
+    }
+
+    if (nodeIsFunction(item) && !nodeIsGetter(item) && !nodeIsSetter(item) && (this.props.mode === MODE.TINY || !this.props.mode)) {
+      return {
+        label: this.renderGrip(item, {
+          ...this.props,
+          functionName: label
+        })
+      };
+    }
+
+    if (nodeHasProperties(item) || nodeHasAccessors(item) || nodeIsMapEntry(item) || isPrimitive) {
+      let repsProp = { ...this.props };
+      if (depth > 0) {
+        repsProp.mode = this.props.mode === MODE.LONG ? MODE.SHORT : MODE.TINY;
+      }
+      if (expanded) {
+        repsProp.mode = MODE.TINY;
+      }
+
+      return {
+        label,
+        value: this.renderGrip(item, repsProp)
+      };
+    }
+
+    return {
+      label
+    };
+  }
+
+  renderTreeItemLabel(label, item, depth, focused, expanded) {
+    if (label === null || typeof label === "undefined") {
+      return null;
+    }
+
+    const {
+      onLabelClick
+    } = this.props;
+
+    return dom.span({
+      className: "object-label",
+      onClick: onLabelClick ? event => {
+        event.stopPropagation();
+
+        // If the user selected text, bail out.
+        if (Utils.selection.documentHasSelection()) {
+          return;
+        }
+
+        onLabelClick(item, {
+          depth,
+          focused,
+          expanded,
+          setExpanded: this.setExpanded
+        });
+      } : undefined
+    }, label);
+  }
+
+  getTreeTopElementProps(item, depth, focused, expanded) {
+    const {
+      onDoubleClick,
+      dimTopLevelWindow
+    } = this.props;
+
+    let parentElementProps = {
+      className: classnames("node object-node", {
+        focused,
+        lessen: !expanded && (nodeIsDefaultProperties(item) || nodeIsPrototype(item) || dimTopLevelWindow === true && nodeIsWindow(item) && depth === 0),
+        block: nodeIsBlock(item)
+      }),
+      onClick: e => {
+        e.stopPropagation();
+
+        // If the user selected text, bail out.
+        if (Utils.selection.documentHasSelection()) {
+          return;
+        }
+
+        this.setExpanded(item, !expanded);
+      }
+    };
+
+    if (onDoubleClick) {
+      parentElementProps.onDoubleClick = e => {
+        e.stopPropagation();
+        onDoubleClick(item, {
+          depth,
+          focused,
+          expanded
+        });
+      };
+    }
+
+    return parentElementProps;
+  }
+
+  renderTreeItem(item, depth, focused, arrow, expanded) {
+    const { label, value } = this.getTreeItemLabelAndValue(item, depth, expanded);
+    const labelElement = this.renderTreeItemLabel(label, item, depth, focused, expanded);
+    const delimiter = value && labelElement ? dom.span({ className: "object-delimiter" }, ": ") : null;
+
+    return dom.div(this.getTreeTopElementProps(item, depth, focused, expanded), arrow, labelElement, delimiter, value);
+  }
+
+  renderGrip(item, props) {
+    const object = getValue(item);
+    return Rep({
+      ...props,
+      object,
+      mode: props.mode || MODE.TINY,
+      defaultRep: Grip
+    });
+  }
+
+  render() {
+    const {
+      autoExpandAll = true,
+      autoExpandDepth = 1,
+      disabledFocus,
+      disableWrap = false,
+      expandedPaths,
+      focusedItem,
+      inline
+    } = this.props;
+
+    let roots = this.getRoots();
+    if (roots.length === 1) {
+      const root = roots[0];
+      const name = root && root.name;
+      if (nodeIsPrimitive(root) && (name === null || typeof name === "undefined")) {
+        return this.renderGrip(root, this.props);
+      }
+    }
+
+    return Tree({
+      className: classnames({
+        inline,
+        nowrap: disableWrap,
+        "object-inspector": true
+      }),
+      autoExpandAll,
+      autoExpandDepth,
+      disabledFocus,
+
+      isExpanded: item => expandedPaths && expandedPaths.has(this.getNodeKey(item)),
+      isExpandable: item => nodeIsPrimitive(item) === false,
+      focused: focusedItem,
+
+      getRoots: this.getRoots,
+      getParent,
+      getChildren: this.getItemChildren,
+      getKey: this.getNodeKey,
+
+      onExpand: item => this.setExpanded(item, true),
+      onCollapse: item => this.setExpanded(item, false),
+      onFocus: this.focusItem,
+
+      renderItem: this.renderTreeItem
+    });
+  }
+}
+
+function mapStateToProps(state, props) {
+  return {
+    actors: state.actors,
+    expandedPaths: state.expandedPaths,
+    focusedItem: state.focusedItem,
+    loadedProperties: state.loadedProperties
+  };
+}
+
+function mapDispatchToProps(dispatch) {
+  return bindActionCreators(__webpack_require__(3617), dispatch);
+}
+
+module.exports = connect(mapStateToProps, mapDispatchToProps)(ObjectInspector);
+
+/***/ }),
+
+/***/ 3616:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const { ELEMENT_NODE } = __webpack_require__(1449);
+
+function documentHasSelection() {
+  const selection = getSelection();
+  if (!selection) {
+    return false;
+  }
+
+  const {
+    anchorNode,
+    focusNode
+  } = selection;
+
+  // When clicking the arrow, which is an inline svg element, the selection do have a type
+  // of "Range". We need to have an explicit case when the anchor and the focus node are
+  // the same and they have an arrow ancestor.
+  if (focusNode && focusNode === anchorNode && focusNode.nodeType == ELEMENT_NODE && focusNode.closest(".arrow")) {
+    return false;
+  }
+
+  return selection.type === "Range";
+}
+
+module.exports = {
+  documentHasSelection
+};
+
+/***/ }),
+
+/***/ 3617:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+const {
+  loadItemProperties
+} = __webpack_require__(2017); /* This Source Code Form is subject to the terms of the Mozilla Public
+                                         * License, v. 2.0. If a copy of the MPL was not distributed with this
+                                         * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * This action is responsible for expanding a given node,
+ * which also means that it will call the action responsible to fetch properties.
+ */
+function nodeExpand(node, actor, loadedProperties, createObjectClient) {
+  return async ({ dispatch }) => {
+    dispatch({
+      type: "NODE_EXPAND",
+      data: { node }
+    });
+    dispatch(nodeLoadProperties(node, actor, loadedProperties, createObjectClient));
+  };
+}
+
+function nodeCollapse(node) {
+  return {
+    type: "NODE_COLLAPSE",
+    data: { node }
+  };
+}
+
+function nodeFocus(node) {
+  return {
+    type: "NODE_FOCUS",
+    data: { node }
+  };
+}
+/*
+ * This action checks if we need to fetch properties, entries, prototype and symbols
+ * for a given node. If we do, it will call the appropriate ObjectClient functions.
+ */
+function nodeLoadProperties(item, actor, loadedProperties, createObjectClient) {
+  return async ({ dispatch }) => {
+    try {
+      const properties = await loadItemProperties(item, createObjectClient, loadedProperties);
+      if (Object.keys(properties).length > 0) {
+        dispatch(nodePropertiesLoaded(item, actor, properties));
+      }
+    } catch (e) {
+      console.error(e);
+    }
+  };
+}
+
+function nodePropertiesLoaded(node, actor, properties) {
+  return {
+    type: "NODE_PROPERTIES_LOADED",
+    data: { node, actor, properties }
+  };
+}
+
+module.exports = {
+  nodeExpand,
+  nodeCollapse,
+  nodeFocus,
+  nodeLoadProperties,
+  nodePropertiesLoaded
+};
+
+/***/ }),
+
+/***/ 3618:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const { applyMiddleware, createStore } = __webpack_require__(3593);
+const { thunk } = __webpack_require__(3619);
+const { waitUntilService } = __webpack_require__(3620);
+const reducer = __webpack_require__(3621);
+
+function createInitialState(overrides) {
+  return {
+    actors: new Set(),
+    expandedPaths: new Set(),
+    focusedItem: null,
+    loadedProperties: new Map(),
+    ...overrides
+  };
+}
+
+module.exports = props => {
+  const middlewares = [thunk];
+  if (props.injectWaitService) {
+    middlewares.push(waitUntilService);
+  }
+
+  return createStore(reducer, createInitialState(props), applyMiddleware(...middlewares));
+};
+
+/***/ }),
+
+/***/ 3619:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * A middleware that allows thunks (functions) to be dispatched.
+ * If it's a thunk, it is called with `dispatch` and `getState`,
+ * allowing the action to create multiple actions (most likely
+ * asynchronously).
+ */
+function thunk({ dispatch, getState }) {
+  return next => action => {
+    return typeof action === "function" ? action({ dispatch, getState }) : next(action);
+  };
+}
+exports.thunk = thunk;
+
+/***/ }),
+
 /***/ 362:
 /***/ (function(module, exports) {
 
 module.exports = "<!-- This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. --><svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" viewBox=\"0 0 20 16\" stroke=\"none\" fillrule=\"evenodd\"><rect x=\"3\" y=\"10\" width=\"3\" height=\"3\" rx=\"1\"></rect><rect x=\"12\" y=\"3\" width=\"2\" height=\"9\" rx=\"1\"></rect><rect transform=\"translate(13.000000, 7.500000) rotate(60.000000) translate(-13.000000, -7.500000) \" x=\"12\" y=\"3\" width=\"2\" height=\"9\" rx=\"1\"></rect><rect transform=\"translate(13.000000, 7.500000) rotate(-60.000000) translate(-13.000000, -7.500000) \" x=\"12\" y=\"3\" width=\"2\" height=\"9\" rx=\"1\"></rect></svg>"
 
 /***/ }),
 
+/***/ 3620:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const WAIT_UNTIL_TYPE = "@@service/waitUntil";
+/**
+ * A middleware which acts like a service, because it is stateful
+ * and "long-running" in the background. It provides the ability
+ * for actions to install a function to be run once when a specific
+ * condition is met by an action coming through the system. Think of
+ * it as a thunk that blocks until the condition is met. Example:
+ *
+ * ```js
+ * const services = { WAIT_UNTIL: require('wait-service').NAME };
+ *
+ * { type: services.WAIT_UNTIL,
+ *   predicate: action => action.type === "ADD_ITEM",
+ *   run: (dispatch, getState, action) => {
+ *     // Do anything here. You only need to accept the arguments
+ *     // if you need them. `action` is the action that satisfied
+ *     // the predicate.
+ *   }
+ * }
+ * ```
+ */
+function waitUntilService({ dispatch, getState }) {
+  let pending = [];
+
+  function checkPending(action) {
+    const readyRequests = [];
+    const stillPending = [];
+
+    // Find the pending requests whose predicates are satisfied with
+    // this action. Wait to run the requests until after we update the
+    // pending queue because the request handler may synchronously
+    // dispatch again and run this service (that use case is
+    // completely valid).
+    for (const request of pending) {
+      if (request.predicate(action)) {
+        readyRequests.push(request);
+      } else {
+        stillPending.push(request);
+      }
+    }
+
+    pending = stillPending;
+    for (const request of readyRequests) {
+      request.run(dispatch, getState, action);
+    }
+  }
+
+  return next => action => {
+    if (action.type === WAIT_UNTIL_TYPE) {
+      pending.push(action);
+      return null;
+    }
+    const result = next(action);
+    checkPending(action);
+    return result;
+  };
+}
+
+module.exports = {
+  WAIT_UNTIL_TYPE,
+  waitUntilService
+};
+
+/***/ }),
+
+/***/ 3621:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+function reducer(state = {}, action) {
+  const {
+    type,
+    data
+  } = action;
+
+  const cloneState = overrides => ({ ...state, ...overrides });
+
+  if (type === "NODE_EXPAND") {
+    return cloneState({
+      expandedPaths: new Set(state.expandedPaths).add(data.node.path)
+    });
+  }
+
+  if (type === "NODE_COLLAPSE") {
+    const expandedPaths = new Set(state.expandedPaths);
+    expandedPaths.delete(data.node.path);
+    return cloneState({ expandedPaths });
+  }
+
+  if (type === "NODE_PROPERTIES_LOADED") {
+    return cloneState({
+      actors: data.actor ? new Set(state.actors || []).add(data.actor) : state.actors,
+      loadedProperties: new Map(state.loadedProperties).set(data.node.path, action.data.properties)
+    });
+  }
+
+  if (type === "NODE_FOCUS") {
+    return cloneState({
+      focusedItem: data.node
+    });
+  }
+
+  return state;
+} /* This Source Code Form is subject to the terms of the Mozilla Public
+   * License, v. 2.0. If a copy of the MPL was not distributed with this
+   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+module.exports = reducer;
+
+/***/ }),
+
 /***/ 363:
 /***/ (function(module, exports) {
 
 module.exports = "<!-- This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. --><svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:svg=\"http://www.w3.org/2000/svg\"><path fill=\"black\" id=\"svg_1\" fill-rule=\"evenodd\" d=\"m4.55195,12.97461l7.4,-5l-7.4,-5l0,10zm-0.925,0l0,-10c0,-0.785 0.8,-1.264 1.415,-0.848l7.4,5c0.58,0.392 0.58,1.304 0,1.696l-7.4,5c-0.615,0.416 -1.415,-0.063 -1.415,-0.848z\"></path></svg>"
 
 /***/ }),
 
 /***/ 364:
--- a/devtools/client/debugger/new/parser-worker.js
+++ b/devtools/client/debugger/new/parser-worker.js
@@ -1929,42 +1929,45 @@ var _steps = __webpack_require__(1625);
 var _validate = __webpack_require__(1629);
 
 var _frameworks = __webpack_require__(1703);
 
 var _pauseLocation = __webpack_require__(2422);
 
 var _pausePoints = __webpack_require__(3612);
 
+var _mapOriginalExpression = __webpack_require__(3613);
+
+var _mapOriginalExpression2 = _interopRequireDefault(_mapOriginalExpression);
+
 var _devtoolsUtils = __webpack_require__(1363);
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
-
-const { workerHandler } = _devtoolsUtils.workerUtils;
+const { workerHandler } = _devtoolsUtils.workerUtils; /* This Source Code Form is subject to the terms of the Mozilla Public
+                                                       * License, v. 2.0. If a copy of the MPL was not distributed with this
+                                                       * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 self.onmessage = workerHandler({
   getClosestExpression: _closest.getClosestExpression,
   findOutOfScopeLocations: _findOutOfScopeLocations2.default,
   getSymbols: _getSymbols.getSymbols,
   getScopes: _getScopes2.default,
   clearSymbols: _getSymbols.clearSymbols,
   clearScopes: _getScopes.clearScopes,
   clearASTs: _ast.clearASTs,
   hasSource: _sources.hasSource,
   setSource: _sources.setSource,
   clearSources: _sources.clearSources,
   isInvalidPauseLocation: _pauseLocation.isInvalidPauseLocation,
   getNextStep: _steps.getNextStep,
   hasSyntaxError: _validate.hasSyntaxError,
   getFramework: _frameworks.getFramework,
-  getPausePoints: _pausePoints.getPausePoints
+  getPausePoints: _pausePoints.getPausePoints,
+  mapOriginalExpression: _mapOriginalExpression2.default
 });
 
 /***/ }),
 
 /***/ 1620:
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -2458,16 +2461,74 @@ function findLastIndex(array, predicate,
   return baseFindIndex(array, baseIteratee(predicate, 3), index, true);
 }
 
 module.exports = findLastIndex;
 
 
 /***/ }),
 
+/***/ 1687:
+/***/ (function(module, exports, __webpack_require__) {
+
+var toInteger = __webpack_require__(302);
+
+/**
+ * Checks if `value` is an integer.
+ *
+ * **Note:** This method is based on
+ * [`Number.isInteger`](https://mdn.io/Number/isInteger).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an integer, else `false`.
+ * @example
+ *
+ * _.isInteger(3);
+ * // => true
+ *
+ * _.isInteger(Number.MIN_VALUE);
+ * // => false
+ *
+ * _.isInteger(Infinity);
+ * // => false
+ *
+ * _.isInteger('3');
+ * // => false
+ */
+function isInteger(value) {
+  return typeof value == 'number' && value == toInteger(value);
+}
+
+module.exports = isInteger;
+
+
+/***/ }),
+
+/***/ 1689:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+module.exports = function (str) {
+	var tail = str.length;
+
+	while (/[\s\uFEFF\u00A0]/.test(str[tail - 1])) {
+		tail--;
+	}
+
+	return str.slice(0, tail);
+};
+
+
+/***/ }),
+
 /***/ 1703:
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
@@ -3448,16 +3509,18 @@ exports.isTSConstructorType = isTSConstr
 exports.isTSTypeReference = isTSTypeReference;
 exports.isTSTypePredicate = isTSTypePredicate;
 exports.isTSTypeQuery = isTSTypeQuery;
 exports.isTSTypeLiteral = isTSTypeLiteral;
 exports.isTSArrayType = isTSArrayType;
 exports.isTSTupleType = isTSTupleType;
 exports.isTSUnionType = isTSUnionType;
 exports.isTSIntersectionType = isTSIntersectionType;
+exports.isTSConditionalType = isTSConditionalType;
+exports.isTSInferType = isTSInferType;
 exports.isTSParenthesizedType = isTSParenthesizedType;
 exports.isTSTypeOperator = isTSTypeOperator;
 exports.isTSIndexedAccessType = isTSIndexedAccessType;
 exports.isTSMappedType = isTSMappedType;
 exports.isTSLiteralType = isTSLiteralType;
 exports.isTSExpressionWithTypeArguments = isTSExpressionWithTypeArguments;
 exports.isTSInterfaceDeclaration = isTSInterfaceDeclaration;
 exports.isTSInterfaceBody = isTSInterfaceBody;
@@ -4246,16 +4309,24 @@ function isTSTupleType(node, opts) {
 function isTSUnionType(node, opts) {
   return (0, _is.default)("TSUnionType", node, opts);
 }
 
 function isTSIntersectionType(node, opts) {
   return (0, _is.default)("TSIntersectionType", node, opts);
 }
 
+function isTSConditionalType(node, opts) {
+  return (0, _is.default)("TSConditionalType", node, opts);
+}
+
+function isTSInferType(node, opts) {
+  return (0, _is.default)("TSInferType", node, opts);
+}
+
 function isTSParenthesizedType(node, opts) {
   return (0, _is.default)("TSParenthesizedType", node, opts);
 }
 
 function isTSTypeOperator(node, opts) {
   return (0, _is.default)("TSTypeOperator", node, opts);
 }
 
@@ -4716,16 +4787,18 @@ exports.tSConstructorType = exports.tsCo
 exports.tSTypeReference = exports.tsTypeReference = exports.TSTypeReference = TSTypeReference;
 exports.tSTypePredicate = exports.tsTypePredicate = exports.TSTypePredicate = TSTypePredicate;
 exports.tSTypeQuery = exports.tsTypeQuery = exports.TSTypeQuery = TSTypeQuery;
 exports.tSTypeLiteral = exports.tsTypeLiteral = exports.TSTypeLiteral = TSTypeLiteral;
 exports.tSArrayType = exports.tsArrayType = exports.TSArrayType = TSArrayType;
 exports.tSTupleType = exports.tsTupleType = exports.TSTupleType = TSTupleType;
 exports.tSUnionType = exports.tsUnionType = exports.TSUnionType = TSUnionType;
 exports.tSIntersectionType = exports.tsIntersectionType = exports.TSIntersectionType = TSIntersectionType;
+exports.tSConditionalType = exports.tsConditionalType = exports.TSConditionalType = TSConditionalType;
+exports.tSInferType = exports.tsInferType = exports.TSInferType = TSInferType;
 exports.tSParenthesizedType = exports.tsParenthesizedType = exports.TSParenthesizedType = TSParenthesizedType;
 exports.tSTypeOperator = exports.tsTypeOperator = exports.TSTypeOperator = TSTypeOperator;
 exports.tSIndexedAccessType = exports.tsIndexedAccessType = exports.TSIndexedAccessType = TSIndexedAccessType;
 exports.tSMappedType = exports.tsMappedType = exports.TSMappedType = TSMappedType;
 exports.tSLiteralType = exports.tsLiteralType = exports.TSLiteralType = TSLiteralType;
 exports.tSExpressionWithTypeArguments = exports.tsExpressionWithTypeArguments = exports.TSExpressionWithTypeArguments = TSExpressionWithTypeArguments;
 exports.tSInterfaceDeclaration = exports.tsInterfaceDeclaration = exports.TSInterfaceDeclaration = TSInterfaceDeclaration;
 exports.tSInterfaceBody = exports.tsInterfaceBody = exports.TSInterfaceBody = TSInterfaceBody;
@@ -6197,243 +6270,259 @@ function TSUnionType() {
 function TSIntersectionType() {
   for (var _len181 = arguments.length, args = new Array(_len181), _key181 = 0; _key181 < _len181; _key181++) {
     args[_key181] = arguments[_key181];
   }
 
   return _builder.default.apply(void 0, ["TSIntersectionType"].concat(args));
 }
 
-function TSParenthesizedType() {
+function TSConditionalType() {
   for (var _len182 = arguments.length, args = new Array(_len182), _key182 = 0; _key182 < _len182; _key182++) {
     args[_key182] = arguments[_key182];
   }
 
+  return _builder.default.apply(void 0, ["TSConditionalType"].concat(args));
+}
+
+function TSInferType() {
+  for (var _len183 = arguments.length, args = new Array(_len183), _key183 = 0; _key183 < _len183; _key183++) {
+    args[_key183] = arguments[_key183];
+  }
+
+  return _builder.default.apply(void 0, ["TSInferType"].concat(args));
+}
+
+function TSParenthesizedType() {
+  for (var _len184 = arguments.length, args = new Array(_len184), _key184 = 0; _key184 < _len184; _key184++) {
+    args[_key184] = arguments[_key184];
+  }
+
   return _builder.default.apply(void 0, ["TSParenthesizedType"].concat(args));
 }
 
 function TSTypeOperator() {
-  for (var _len183 = arguments.length, args = new Array(_len183), _key183 = 0; _key183 < _len183; _key183++) {
-    args[_key183] = arguments[_key183];
+  for (var _len185 = arguments.length, args = new Array(_len185), _key185 = 0; _key185 < _len185; _key185++) {
+    args[_key185] = arguments[_key185];
   }
 
   return _builder.default.apply(void 0, ["TSTypeOperator"].concat(args));
 }
 
 function TSIndexedAccessType() {
-  for (var _len184 = arguments.length, args = new Array(_len184), _key184 = 0; _key184 < _len184; _key184++) {
-    args[_key184] = arguments[_key184];
+  for (var _len186 = arguments.length, args = new Array(_len186), _key186 = 0; _key186 < _len186; _key186++) {
+    args[_key186] = arguments[_key186];
   }
 
   return _builder.default.apply(void 0, ["TSIndexedAccessType"].concat(args));
 }
 
 function TSMappedType() {
-  for (var _len185 = arguments.length, args = new Array(_len185), _key185 = 0; _key185 < _len185; _key185++) {
-    args[_key185] = arguments[_key185];
+  for (var _len187 = arguments.length, args = new Array(_len187), _key187 = 0; _key187 < _len187; _key187++) {
+    args[_key187] = arguments[_key187];
   }
 
   return _builder.default.apply(void 0, ["TSMappedType"].concat(args));
 }
 
 function TSLiteralType() {
-  for (var _len186 = arguments.length, args = new Array(_len186), _key186 = 0; _key186 < _len186; _key186++) {
-    args[_key186] = arguments[_key186];
+  for (var _len188 = arguments.length, args = new Array(_len188), _key188 = 0; _key188 < _len188; _key188++) {
+    args[_key188] = arguments[_key188];
   }
 
   return _builder.default.apply(void 0, ["TSLiteralType"].concat(args));
 }
 
 function TSExpressionWithTypeArguments() {
-  for (var _len187 = arguments.length, args = new Array(_len187), _key187 = 0; _key187 < _len187; _key187++) {
-    args[_key187] = arguments[_key187];
+  for (var _len189 = arguments.length, args = new Array(_len189), _key189 = 0; _key189 < _len189; _key189++) {
+    args[_key189] = arguments[_key189];
   }
 
   return _builder.default.apply(void 0, ["TSExpressionWithTypeArguments"].concat(args));
 }
 
 function TSInterfaceDeclaration() {
-  for (var _len188 = arguments.length, args = new Array(_len188), _key188 = 0; _key188 < _len188; _key188++) {
-    args[_key188] = arguments[_key188];
+  for (var _len190 = arguments.length, args = new Array(_len190), _key190 = 0; _key190 < _len190; _key190++) {
+    args[_key190] = arguments[_key190];
   }
 
   return _builder.default.apply(void 0, ["TSInterfaceDeclaration"].concat(args));
 }
 
 function TSInterfaceBody() {
-  for (var _len189 = arguments.length, args = new Array(_len189), _key189 = 0; _key189 < _len189; _key189++) {
-    args[_key189] = arguments[_key189];
+  for (var _len191 = arguments.length, args = new Array(_len191), _key191 = 0; _key191 < _len191; _key191++) {
+    args[_key191] = arguments[_key191];
   }
 
   return _builder.default.apply(void 0, ["TSInterfaceBody"].concat(args));
 }
 
 function TSTypeAliasDeclaration() {
-  for (var _len190 = arguments.length, args = new Array(_len190), _key190 = 0; _key190 < _len190; _key190++) {
-    args[_key190] = arguments[_key190];
+  for (var _len192 = arguments.length, args = new Array(_len192), _key192 = 0; _key192 < _len192; _key192++) {
+    args[_key192] = arguments[_key192];
   }
 
   return _builder.default.apply(void 0, ["TSTypeAliasDeclaration"].concat(args));
 }
 
 function TSAsExpression() {
-  for (var _len191 = arguments.length, args = new Array(_len191), _key191 = 0; _key191 < _len191; _key191++) {
-    args[_key191] = arguments[_key191];
+  for (var _len193 = arguments.length, args = new Array(_len193), _key193 = 0; _key193 < _len193; _key193++) {
+    args[_key193] = arguments[_key193];
   }
 
   return _builder.default.apply(void 0, ["TSAsExpression"].concat(args));
 }
 
 function TSTypeAssertion() {
-  for (var _len192 = arguments.length, args = new Array(_len192), _key192 = 0; _key192 < _len192; _key192++) {
-    args[_key192] = arguments[_key192];
+  for (var _len194 = arguments.length, args = new Array(_len194), _key194 = 0; _key194 < _len194; _key194++) {
+    args[_key194] = arguments[_key194];
   }
 
   return _builder.default.apply(void 0, ["TSTypeAssertion"].concat(args));
 }
 
 function TSEnumDeclaration() {
-  for (var _len193 = arguments.length, args = new Array(_len193), _key193 = 0; _key193 < _len193; _key193++) {
-    args[_key193] = arguments[_key193];
+  for (var _len195 = arguments.length, args = new Array(_len195), _key195 = 0; _key195 < _len195; _key195++) {
+    args[_key195] = arguments[_key195];
   }
 
   return _builder.default.apply(void 0, ["TSEnumDeclaration"].concat(args));
 }
 
 function TSEnumMember() {
-  for (var _len194 = arguments.length, args = new Array(_len194), _key194 = 0; _key194 < _len194; _key194++) {
-    args[_key194] = arguments[_key194];
+  for (var _len196 = arguments.length, args = new Array(_len196), _key196 = 0; _key196 < _len196; _key196++) {
+    args[_key196] = arguments[_key196];
   }
 
   return _builder.default.apply(void 0, ["TSEnumMember"].concat(args));
 }
 
 function TSModuleDeclaration() {
-  for (var _len195 = arguments.length, args = new Array(_len195), _key195 = 0; _key195 < _len195; _key195++) {
-    args[_key195] = arguments[_key195];
+  for (var _len197 = arguments.length, args = new Array(_len197), _key197 = 0; _key197 < _len197; _key197++) {
+    args[_key197] = arguments[_key197];
   }
 
   return _builder.default.apply(void 0, ["TSModuleDeclaration"].concat(args));
 }
 
 function TSModuleBlock() {
-  for (var _len196 = arguments.length, args = new Array(_len196), _key196 = 0; _key196 < _len196; _key196++) {
-    args[_key196] = arguments[_key196];
+  for (var _len198 = arguments.length, args = new Array(_len198), _key198 = 0; _key198 < _len198; _key198++) {
+    args[_key198] = arguments[_key198];
   }
 
   return _builder.default.apply(void 0, ["TSModuleBlock"].concat(args));
 }
 
 function TSImportEqualsDeclaration() {
-  for (var _len197 = arguments.length, args = new Array(_len197), _key197 = 0; _key197 < _len197; _key197++) {
-    args[_key197] = arguments[_key197];
+  for (var _len199 = arguments.length, args = new Array(_len199), _key199 = 0; _key199 < _len199; _key199++) {
+    args[_key199] = arguments[_key199];
   }
 
   return _builder.default.apply(void 0, ["TSImportEqualsDeclaration"].concat(args));
 }
 
 function TSExternalModuleReference() {
-  for (var _len198 = arguments.length, args = new Array(_len198), _key198 = 0; _key198 < _len198; _key198++) {
-    args[_key198] = arguments[_key198];
+  for (var _len200 = arguments.length, args = new Array(_len200), _key200 = 0; _key200 < _len200; _key200++) {
+    args[_key200] = arguments[_key200];
   }
 
   return _builder.default.apply(void 0, ["TSExternalModuleReference"].concat(args));
 }
 
 function TSNonNullExpression() {
-  for (var _len199 = arguments.length, args = new Array(_len199), _key199 = 0; _key199 < _len199; _key199++) {
-    args[_key199] = arguments[_key199];
+  for (var _len201 = arguments.length, args = new Array(_len201), _key201 = 0; _key201 < _len201; _key201++) {
+    args[_key201] = arguments[_key201];
   }
 
   return _builder.default.apply(void 0, ["TSNonNullExpression"].concat(args));
 }
 
 function TSExportAssignment() {
-  for (var _len200 = arguments.length, args = new Array(_len200), _key200 = 0; _key200 < _len200; _key200++) {
-    args[_key200] = arguments[_key200];
+  for (var _len202 = arguments.length, args = new Array(_len202), _key202 = 0; _key202 < _len202; _key202++) {
+    args[_key202] = arguments[_key202];
   }
 
   return _builder.default.apply(void 0, ["TSExportAssignment"].concat(args));
 }
 
 function TSNamespaceExportDeclaration() {
-  for (var _len201 = arguments.length, args = new Array(_len201), _key201 = 0; _key201 < _len201; _key201++) {
-    args[_key201] = arguments[_key201];
+  for (var _len203 = arguments.length, args = new Array(_len203), _key203 = 0; _key203 < _len203; _key203++) {
+    args[_key203] = arguments[_key203];
   }
 
   return _builder.default.apply(void 0, ["TSNamespaceExportDeclaration"].concat(args));
 }
 
 function TSTypeAnnotation() {
-  for (var _len202 = arguments.length, args = new Array(_len202), _key202 = 0; _key202 < _len202; _key202++) {
-    args[_key202] = arguments[_key202];
+  for (var _len204 = arguments.length, args = new Array(_len204), _key204 = 0; _key204 < _len204; _key204++) {
+    args[_key204] = arguments[_key204];
   }
 
   return _builder.default.apply(void 0, ["TSTypeAnnotation"].concat(args));
 }
 
 function TSTypeParameterInstantiation() {
-  for (var _len203 = arguments.length, args = new Array(_len203), _key203 = 0; _key203 < _len203; _key203++) {
-    args[_key203] = arguments[_key203];
+  for (var _len205 = arguments.length, args = new Array(_len205), _key205 = 0; _key205 < _len205; _key205++) {
+    args[_key205] = arguments[_key205];
   }
 
   return _builder.default.apply(void 0, ["TSTypeParameterInstantiation"].concat(args));
 }
 
 function TSTypeParameterDeclaration() {
-  for (var _len204 = arguments.length, args = new Array(_len204), _key204 = 0; _key204 < _len204; _key204++) {
-    args[_key204] = arguments[_key204];
+  for (var _len206 = arguments.length, args = new Array(_len206), _key206 = 0; _key206 < _len206; _key206++) {
+    args[_key206] = arguments[_key206];
   }
 
   return _builder.default.apply(void 0, ["TSTypeParameterDeclaration"].concat(args));
 }
 
 function TSTypeParameter() {
-  for (var _len205 = arguments.length, args = new Array(_len205), _key205 = 0; _key205 < _len205; _key205++) {
-    args[_key205] = arguments[_key205];
+  for (var _len207 = arguments.length, args = new Array(_len207), _key207 = 0; _key207 < _len207; _key207++) {
+    args[_key207] = arguments[_key207];
   }
 
   return _builder.default.apply(void 0, ["TSTypeParameter"].concat(args));
 }
 
 function NumberLiteral() {
   console.trace("The node type NumberLiteral has been renamed to NumericLiteral");
 
-  for (var _len206 = arguments.length, args = new Array(_len206), _key206 = 0; _key206 < _len206; _key206++) {
-    args[_key206] = arguments[_key206];
+  for (var _len208 = arguments.length, args = new Array(_len208), _key208 = 0; _key208 < _len208; _key208++) {
+    args[_key208] = arguments[_key208];
   }
 
   return NumberLiteral.apply(void 0, ["NumberLiteral"].concat(args));
 }
 
 function RegexLiteral() {
   console.trace("The node type RegexLiteral has been renamed to RegExpLiteral");
 
-  for (var _len207 = arguments.length, args = new Array(_len207), _key207 = 0; _key207 < _len207; _key207++) {
-    args[_key207] = arguments[_key207];
+  for (var _len209 = arguments.length, args = new Array(_len209), _key209 = 0; _key209 < _len209; _key209++) {
+    args[_key209] = arguments[_key209];
   }
 
   return RegexLiteral.apply(void 0, ["RegexLiteral"].concat(args));
 }
 
 function RestProperty() {
   console.trace("The node type RestProperty has been renamed to RestElement");
 
-  for (var _len208 = arguments.length, args = new Array(_len208), _key208 = 0; _key208 < _len208; _key208++) {
-    args[_key208] = arguments[_key208];
+  for (var _len210 = arguments.length, args = new Array(_len210), _key210 = 0; _key210 < _len210; _key210++) {
+    args[_key210] = arguments[_key210];
   }
 
   return RestProperty.apply(void 0, ["RestProperty"].concat(args));
 }
 
 function SpreadProperty() {
   console.trace("The node type SpreadProperty has been renamed to SpreadElement");
 
-  for (var _len209 = arguments.length, args = new Array(_len209), _key209 = 0; _key209 < _len209; _key209++) {
-    args[_key209] = arguments[_key209];
+  for (var _len211 = arguments.length, args = new Array(_len211), _key211 = 0; _key211 < _len211; _key211++) {
+    args[_key211] = arguments[_key211];
   }
 
   return SpreadProperty.apply(void 0, ["SpreadProperty"].concat(args));
 }
 
 /***/ }),
 
 /***/ 2257:
@@ -7006,16 +7095,19 @@ getBindingIdentifiers.keys = {
   ImportNamespaceSpecifier: ["local"],
   ImportDefaultSpecifier: ["local"],
   ImportDeclaration: ["specifiers"],
   ExportSpecifier: ["exported"],
   ExportNamespaceSpecifier: ["exported"],
   ExportDefaultSpecifier: ["exported"],
   FunctionDeclaration: ["id", "params"],
   FunctionExpression: ["id", "params"],
+  ArrowFunctionExpression: ["params"],
+  ObjectMethod: ["params"],
+  ClassMethod: ["params"],
   ForInStatement: ["left"],
   ForOfStatement: ["left"],
   ClassDeclaration: ["id"],
   ClassExpression: ["id"],
   RestElement: ["argument"],
   UpdateExpression: ["argument"],
   ObjectProperty: ["value"],
   AssignmentPattern: ["left"],
@@ -7082,16 +7174,20 @@ var _isValidIdentifier = _interopRequire
 var _constants = __webpack_require__(2259);
 
 var _utils = _interopRequireWildcard(__webpack_require__(2258));
 
 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
+function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
+
+function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
 (0, _utils.default)("ArrayExpression", {
   fields: {
     elements: {
       validate: (0, _utils.chain)((0, _utils.assertValueType)("array"), (0, _utils.assertEach)((0, _utils.assertNodeOrValueType)("null", "Expression", "SpreadElement"))),
       default: []
     }
   },
   visitor: ["elements"],
@@ -7320,41 +7416,43 @@ var functionTypeAnnotationCommon = {
     optional: true
   },
   typeParameters: {
     validate: (0, _utils.assertNodeType)("TypeParameterDeclaration", "TSTypeParameterDeclaration", "Noop"),
     optional: true
   }
 };
 exports.functionTypeAnnotationCommon = functionTypeAnnotationCommon;
-var functionDeclarationCommon = Object.assign({}, functionCommon, {
+
+var functionDeclarationCommon = _objectSpread({}, functionCommon, {
   declare: {
     validate: (0, _utils.assertValueType)("boolean"),
     optional: true
   },
   id: {
     validate: (0, _utils.assertNodeType)("Identifier"),
     optional: true
   }
 });
+
 exports.functionDeclarationCommon = functionDeclarationCommon;
 (0, _utils.default)("FunctionDeclaration", {
   builder: ["id", "params", "body", "generator", "async"],
   visitor: ["id", "params", "body", "returnType", "typeParameters"],
-  fields: Object.assign({}, functionDeclarationCommon, functionTypeAnnotationCommon, {
+  fields: _objectSpread({}, functionDeclarationCommon, functionTypeAnnotationCommon, {
     body: {
       validate: (0, _utils.assertNodeType)("BlockStatement")
     }
   }),
   aliases: ["Scopable", "Function", "BlockParent", "FunctionParent", "Statement", "Pureish", "Declaration"]
 });
 (0, _utils.default)("FunctionExpression", {
   inherits: "FunctionDeclaration",
   aliases: ["Scopable", "Function", "BlockParent", "FunctionParent", "Expression", "Pureish"],
-  fields: Object.assign({}, functionCommon, functionTypeAnnotationCommon, {
+  fields: _objectSpread({}, functionCommon, functionTypeAnnotationCommon, {
     id: {
       validate: (0, _utils.assertNodeType)("Identifier"),
       optional: true
     },
     body: {
       validate: (0, _utils.assertNodeType)("BlockStatement")
     }
   })
@@ -7368,17 +7466,17 @@ var patternLikeCommon = {
     validate: (0, _utils.chain)((0, _utils.assertValueType)("array"), (0, _utils.assertEach)((0, _utils.assertNodeType)("Decorator")))
   }
 };
 exports.patternLikeCommon = patternLikeCommon;
 (0, _utils.default)("Identifier", {
   builder: ["name"],
   visitor: ["typeAnnotation"],
   aliases: ["Expression", "PatternLike", "LVal", "TSEntityName"],
-  fields: Object.assign({}, patternLikeCommon, {
+  fields: _objectSpread({}, patternLikeCommon, {
     name: {
       validate: (0, _utils.chain)(function (node, key, val) {
         if (!(0, _isValidIdentifier.default)(val)) {}
       }, (0, _utils.assertValueType)("string"))
     },
     optional: {
       validate: (0, _utils.assertValueType)("boolean"),
       optional: true
@@ -7531,17 +7629,17 @@ exports.patternLikeCommon = patternLikeC
   fields: {
     properties: {
       validate: (0, _utils.chain)((0, _utils.assertValueType)("array"), (0, _utils.assertEach)((0, _utils.assertNodeType)("ObjectMethod", "ObjectProperty", "SpreadElement")))
     }
   }
 });
 (0, _utils.default)("ObjectMethod", {
   builder: ["kind", "key", "params", "body", "computed"],
-  fields: Object.assign({}, functionCommon, functionTypeAnnotationCommon, {
+  fields: _objectSpread({}, functionCommon, functionTypeAnnotationCommon, {
     kind: {
       validate: (0, _utils.chain)((0, _utils.assertValueType)("string"), (0, _utils.assertOneOf)("method", "get", "set")),
       default: "method"
     },
     computed: {
       validate: (0, _utils.assertValueType)("boolean"),
       default: false
     },
@@ -7597,17 +7695,17 @@ exports.patternLikeCommon = patternLikeC
   visitor: ["key", "value", "decorators"],
   aliases: ["UserWhitespacable", "Property", "ObjectMember"]
 });
 (0, _utils.default)("RestElement", {
   visitor: ["argument", "typeAnnotation"],
   builder: ["argument"],
   aliases: ["LVal", "PatternLike"],
   deprecatedAlias: "RestProperty",
-  fields: Object.assign({}, patternLikeCommon, {
+  fields: _objectSpread({}, patternLikeCommon, {
     argument: {
       validate: (0, _utils.assertNodeType)("LVal")
     }
   })
 });
 (0, _utils.default)("ReturnStatement", {
   visitor: ["argument"],
   aliases: ["Statement", "Terminatorless", "CompletionStatement"],
@@ -7730,16 +7828,20 @@ exports.patternLikeCommon = patternLikeC
   }
 });
 (0, _utils.default)("VariableDeclarator", {
   visitor: ["id", "init"],
   fields: {
     id: {
       validate: (0, _utils.assertNodeType)("LVal")
     },
+    definite: {
+      optional: true,
+      validate: (0, _utils.assertValueType)("boolean")
+    },
     init: {
       optional: true,
       validate: (0, _utils.assertNodeType)("Expression")
     }
   }
 });
 (0, _utils.default)("WhileStatement", {
   visitor: ["test", "body"],
@@ -7778,50 +7880,54 @@ exports.__esModule = true;
 exports.classMethodOrDeclareMethodCommon = exports.classMethodOrPropertyCommon = void 0;
 
 var _utils = _interopRequireWildcard(__webpack_require__(2258));
 
 var _core = __webpack_require__(2265);
 
 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
 
+function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
+
+function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
 (0, _utils.default)("AssignmentPattern", {
   visitor: ["left", "right"],
   builder: ["left", "right"],
   aliases: ["Pattern", "PatternLike", "LVal"],
-  fields: Object.assign({}, _core.patternLikeCommon, {
+  fields: _objectSpread({}, _core.patternLikeCommon, {
     left: {
       validate: (0, _utils.assertNodeType)("Identifier", "ObjectPattern", "ArrayPattern")
     },
     right: {
       validate: (0, _utils.assertNodeType)("Expression")
     },
     decorators: {
       validate: (0, _utils.chain)((0, _utils.assertValueType)("array"), (0, _utils.assertEach)((0, _utils.assertNodeType)("Decorator")))
     }
   })
 });
 (0, _utils.default)("ArrayPattern", {
   visitor: ["elements", "typeAnnotation"],
   builder: ["elements"],
   aliases: ["Pattern", "PatternLike", "LVal"],
-  fields: Object.assign({}, _core.patternLikeCommon, {
+  fields: _objectSpread({}, _core.patternLikeCommon, {
     elements: {
       validate: (0, _utils.chain)((0, _utils.assertValueType)("array"), (0, _utils.assertEach)((0, _utils.assertNodeType)("PatternLike")))
     },
     decorators: {
       validate: (0, _utils.chain)((0, _utils.assertValueType)("array"), (0, _utils.assertEach)((0, _utils.assertNodeType)("Decorator")))
     }
   })
 });
 (0, _utils.default)("ArrowFunctionExpression", {
   builder: ["params", "body", "async"],
   visitor: ["params", "body", "returnType", "typeParameters"],
   aliases: ["Scopable", "Function", "BlockParent", "FunctionParent", "Expression", "Pureish"],
-  fields: Object.assign({}, _core.functionCommon, _core.functionTypeAnnotationCommon, {
+  fields: _objectSpread({}, _core.functionCommon, _core.functionTypeAnnotationCommon, {
     expression: {
       validate: (0, _utils.assertValueType)("boolean")
     },
     body: {
       validate: (0, _utils.assertNodeType)("BlockStatement", "Expression")
     }
   })
 });
@@ -7853,17 +7959,17 @@ var classCommon = {
     validate: (0, _utils.chain)((0, _utils.assertValueType)("array"), (0, _utils.assertEach)((0, _utils.assertNodeType)("TSExpressionWithTypeArguments", "ClassImplements"))),
     optional: true
   }
 };
 (0, _utils.default)("ClassDeclaration", {
   builder: ["id", "superClass", "body", "decorators"],
   visitor: ["id", "body", "superClass", "mixins", "typeParameters", "superTypeParameters", "implements", "decorators"],
   aliases: ["Scopable", "Class", "Statement", "Declaration", "Pureish"],
-  fields: Object.assign({}, classCommon, {
+  fields: _objectSpread({}, classCommon, {
     declare: {
       validate: (0, _utils.assertValueType)("boolean"),
       optional: true
     },
     abstract: {
       validate: (0, _utils.assertValueType)("boolean"),
       optional: true
     },
@@ -7875,17 +7981,17 @@ var classCommon = {
       validate: (0, _utils.chain)((0, _utils.assertValueType)("array"), (0, _utils.assertEach)((0, _utils.assertNodeType)("Decorator"))),
       optional: true
     }
   })
 });
 (0, _utils.default)("ClassExpression", {
   inherits: "ClassDeclaration",
   aliases: ["Scopable", "Class", "Expression", "Pureish"],
-  fields: Object.assign({}, classCommon, {
+  fields: _objectSpread({}, classCommon, {
     id: {
       optional: true,
       validate: (0, _utils.assertNodeType)("Identifier")
     },
     body: {
       validate: (0, _utils.assertNodeType)("ClassBody")
     },
     superClass: {
@@ -8049,46 +8155,48 @@ var classMethodOrPropertyCommon = {
       return function (node, key, val) {
         var validator = node.computed ? computed : normal;
         validator(node, key, val);
       };
     }(), (0, _utils.assertNodeType)("Identifier", "StringLiteral", "NumericLiteral", "Expression"))
   }
 };
 exports.classMethodOrPropertyCommon = classMethodOrPropertyCommon;
-var classMethodOrDeclareMethodCommon = Object.assign({}, _core.functionCommon, classMethodOrPropertyCommon, {
+
+var classMethodOrDeclareMethodCommon = _objectSpread({}, _core.functionCommon, classMethodOrPropertyCommon, {
   kind: {
     validate: (0, _utils.chain)((0, _utils.assertValueType)("string"), (0, _utils.assertOneOf)("get", "set", "method", "constructor")),
     default: "method"
   },
   access: {
     validate: (0, _utils.chain)((0, _utils.assertValueType)("string"), (0, _utils.assertOneOf)("public", "private", "protected")),
     optional: true
   },
   decorators: {
     validate: (0, _utils.chain)((0, _utils.assertValueType)("array"), (0, _utils.assertEach)((0, _utils.assertNodeType)("Decorator"))),
     optional: true
   }
 });
+
 exports.classMethodOrDeclareMethodCommon = classMethodOrDeclareMethodCommon;
 (0, _utils.default)("ClassMethod", {
   aliases: ["Function", "Scopable", "BlockParent", "FunctionParent", "Method"],
   builder: ["kind", "key", "params", "body", "computed", "static"],
   visitor: ["key", "params", "body", "decorators", "returnType", "typeParameters"],
-  fields: Object.assign({}, classMethodOrDeclareMethodCommon, _core.functionTypeAnnotationCommon, {
+  fields: _objectSpread({}, classMethodOrDeclareMethodCommon, _core.functionTypeAnnotationCommon, {
     body: {
       validate: (0, _utils.assertNodeType)("BlockStatement")
     }
   })
 });
 (0, _utils.default)("ObjectPattern", {
   visitor: ["properties", "typeAnnotation"],
   builder: ["properties"],
   aliases: ["Pattern", "PatternLike", "LVal"],
-  fields: Object.assign({}, _core.patternLikeCommon, {
+  fields: _objectSpread({}, _core.patternLikeCommon, {
     properties: {
       validate: (0, _utils.chain)((0, _utils.assertValueType)("array"), (0, _utils.assertEach)((0, _utils.assertNodeType)("RestElement", "ObjectProperty")))
     }
   })
 });
 (0, _utils.default)("SpreadElement", {
   visitor: ["argument"],
   aliases: ["UnaryLike"],
@@ -9437,21 +9545,25 @@ function _interopRequireWildcard(obj) { 
   }
 });
 (0, _utils.default)("NumberTypeAnnotation", {
   aliases: ["Flow", "FlowType", "FlowBaseAnnotation"]
 });
 (0, _utils.default)("ObjectTypeAnnotation", {
   visitor: ["properties", "indexers", "callProperties"],
   aliases: ["Flow", "FlowType"],
+  builder: ["properties", "indexers", "callProperties", "exact"],
   fields: {
     properties: (0, _utils.validate)((0, _utils.arrayOfType)(["ObjectTypeProperty", "ObjectTypeSpreadProperty"])),
     indexers: (0, _utils.validateOptional)((0, _utils.arrayOfType)("ObjectTypeIndexer")),
     callProperties: (0, _utils.validateOptional)((0, _utils.arrayOfType)("ObjectTypeCallProperty")),
-    exact: (0, _utils.validate)((0, _utils.assertValueType)("boolean"))
+    exact: {
+      validate: (0, _utils.assertValueType)("boolean"),
+      default: false
+    }
   }
 });
 (0, _utils.default)("ObjectTypeCallProperty", {
   visitor: ["value"],
   aliases: ["Flow", "UserWhitespacable"],
   fields: {
     value: (0, _utils.validateType)("FlowType"),
     static: (0, _utils.validate)((0, _utils.assertValueType)("boolean"))
@@ -9794,16 +9906,20 @@ function _interopRequireWildcard(obj) { 
 
 
 var _utils = _interopRequireWildcard(__webpack_require__(2258));
 
 var _es = __webpack_require__(2266);
 
 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
 
+function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
+
+function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
 (0, _utils.default)("AwaitExpression", {
   builder: ["argument"],
   visitor: ["argument"],
   aliases: ["Expression", "Terminatorless"],
   fields: {
     argument: {
       validate: (0, _utils.assertNodeType)("Expression")
     }
@@ -9813,21 +9929,25 @@ function _interopRequireWildcard(obj) { 
   visitor: ["object", "callee"],
   aliases: ["Expression"],
   fields: {}
 });
 (0, _utils.default)("ClassProperty", {
   visitor: ["key", "value", "typeAnnotation", "decorators"],
   builder: ["key", "value", "typeAnnotation", "decorators", "computed"],
   aliases: ["Property"],
-  fields: Object.assign({}, _es.classMethodOrPropertyCommon, {
+  fields: _objectSpread({}, _es.classMethodOrPropertyCommon, {
     value: {
       validate: (0, _utils.assertNodeType)("Expression"),
       optional: true
     },
+    definite: {
+      validate: (0, _utils.assertValueType)("boolean"),
+      optional: true
+    },
     typeAnnotation: {
       validate: (0, _utils.assertNodeType)("TypeAnnotation", "TSTypeAnnotation", "Noop"),
       optional: true
     },
     decorators: {
       validate: (0, _utils.chain)((0, _utils.assertValueType)("array"), (0, _utils.assertEach)((0, _utils.assertNodeType)("Decorator"))),
       optional: true
     },
@@ -9933,16 +10053,20 @@ function _interopRequireWildcard(obj) { 
 var _utils = _interopRequireWildcard(__webpack_require__(2258));
 
 var _core = __webpack_require__(2265);
 
 var _es = __webpack_require__(2266);
 
 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
 
+function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
+
+function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
 var bool = (0, _utils.assertValueType)("boolean");
 var tSFunctionTypeAnnotationCommon = {
   returnType: {
     validate: (0, _utils.assertNodeType)("TSTypeAnnotation", "Noop"),
     optional: true
   },
   typeParameters: {
     validate: (0, _utils.assertNodeType)("TSTypeParameterDeclaration", "Noop"),
@@ -9964,21 +10088,21 @@ var tSFunctionTypeAnnotationCommon = {
     parameter: {
       validate: (0, _utils.assertNodeType)("Identifier", "AssignmentPattern")
     }
   }
 });
 (0, _utils.default)("TSDeclareFunction", {
   aliases: ["Statement", "Declaration"],
   visitor: ["id", "typeParameters", "params", "returnType"],
-  fields: Object.assign({}, _core.functionDeclarationCommon, tSFunctionTypeAnnotationCommon)
+  fields: _objectSpread({}, _core.functionDeclarationCommon, tSFunctionTypeAnnotationCommon)
 });
 (0, _utils.default)("TSDeclareMethod", {
   visitor: ["decorators", "key", "typeParameters", "params", "returnType"],
-  fields: Object.assign({}, _es.classMethodOrDeclareMethodCommon, tSFunctionTypeAnnotationCommon)
+  fields: _objectSpread({}, _es.classMethodOrDeclareMethodCommon, tSFunctionTypeAnnotationCommon)
 });
 (0, _utils.default)("TSQualifiedName", {
   aliases: ["TSEntityName"],
   visitor: ["left", "right"],
   fields: {
     left: (0, _utils.validateType)("TSEntityName"),
     right: (0, _utils.validateType)("Identifier")
   }
@@ -9998,26 +10122,26 @@ var callConstructSignatureDeclaration = 
 var namedTypeElementCommon = {
   key: (0, _utils.validateType)("Expression"),
   computed: (0, _utils.validate)(bool),
   optional: (0, _utils.validateOptional)(bool)
 };
 (0, _utils.default)("TSPropertySignature", {
   aliases: ["TSTypeElement"],
   visitor: ["key", "typeAnnotation", "initializer"],
-  fields: Object.assign({}, namedTypeElementCommon, {
+  fields: _objectSpread({}, namedTypeElementCommon, {
     readonly: (0, _utils.validateOptional)(bool),
     typeAnnotation: (0, _utils.validateOptionalType)("TSTypeAnnotation"),
     initializer: (0, _utils.validateOptionalType)("Expression")
   })
 });
 (0, _utils.default)("TSMethodSignature", {
   aliases: ["TSTypeElement"],
   visitor: ["key", "typeParameters", "parameters", "typeAnnotation"],
-  fields: Object.assign({}, signatureDeclarationCommon, namedTypeElementCommon)
+  fields: _objectSpread({}, signatureDeclarationCommon, namedTypeElementCommon)
 });
 (0, _utils.default)("TSIndexSignature", {
   aliases: ["TSTypeElement"],
   visitor: ["parameters", "typeAnnotation"],
   fields: {
     readonly: (0, _utils.validateOptional)(bool),
     parameters: (0, _utils.validateArrayOfType)("Identifier"),
     typeAnnotation: (0, _utils.validateOptionalType)("TSTypeAnnotation")
@@ -10094,16 +10218,33 @@ var unionOrIntersection = {
   aliases: ["TSType"],
   visitor: ["types"],
   fields: {
     types: (0, _utils.validateArrayOfType)("TSType")
   }
 };
 (0, _utils.default)("TSUnionType", unionOrIntersection);
 (0, _utils.default)("TSIntersectionType", unionOrIntersection);
+(0, _utils.default)("TSConditionalType", {
+  aliases: ["TSType"],
+  visitor: ["checkType", "extendsType", "trueType", "falseType"],
+  fields: {
+    checkType: (0, _utils.validateType)("TSType"),
+    extendsType: (0, _utils.validateType)("TSType"),
+    trueType: (0, _utils.validateType)("TSType"),
+    falseType: (0, _utils.validateType)("TSType")
+  }
+});
+(0, _utils.default)("TSInferType", {
+  aliases: ["TSType"],
+  visitor: ["typeParameter"],
+  fields: {
+    typeParameter: (0, _utils.validateType)("TSType")
+  }
+});
 (0, _utils.default)("TSParenthesizedType", {
   aliases: ["TSType"],
   visitor: ["typeAnnotation"],
   fields: {
     typeAnnotation: (0, _utils.validateType)("TSType")
   }
 });
 (0, _utils.default)("TSTypeOperator", {
@@ -10662,16 +10803,18 @@ exports.assertTSConstructorType = assert
 exports.assertTSTypeReference = assertTSTypeReference;
 exports.assertTSTypePredicate = assertTSTypePredicate;
 exports.assertTSTypeQuery = assertTSTypeQuery;
 exports.assertTSTypeLiteral = assertTSTypeLiteral;
 exports.assertTSArrayType = assertTSArrayType;
 exports.assertTSTupleType = assertTSTupleType;
 exports.assertTSUnionType = assertTSUnionType;
 exports.assertTSIntersectionType = assertTSIntersectionType;
+exports.assertTSConditionalType = assertTSConditionalType;
+exports.assertTSInferType = assertTSInferType;
 exports.assertTSParenthesizedType = assertTSParenthesizedType;
 exports.assertTSTypeOperator = assertTSTypeOperator;
 exports.assertTSIndexedAccessType = assertTSIndexedAccessType;
 exports.assertTSMappedType = assertTSMappedType;
 exports.assertTSLiteralType = assertTSLiteralType;
 exports.assertTSExpressionWithTypeArguments = assertTSExpressionWithTypeArguments;
 exports.assertTSInterfaceDeclaration = assertTSInterfaceDeclaration;
 exports.assertTSInterfaceBody = assertTSInterfaceBody;
@@ -12190,16 +12333,32 @@ function assertTSUnionType(node, opts) {
 function assertTSIntersectionType(node, opts) {
   if (opts === void 0) {
     opts = {};
   }
 
   assert("TSIntersectionType", node, opts);
 }
 
+function assertTSConditionalType(node, opts) {
+  if (opts === void 0) {
+    opts = {};
+  }
+
+  assert("TSConditionalType", node, opts);
+}
+
+function assertTSInferType(node, opts) {
+  if (opts === void 0) {
+    opts = {};
+  }
+
+  assert("TSInferType", node, opts);
+}
+
 function assertTSParenthesizedType(node, opts) {
   if (opts === void 0) {
     opts = {};
   }
 
   assert("TSParenthesizedType", node, opts);
 }
 
@@ -14193,16 +14352,4684 @@ function parseFragment(str) {
   return null;
 }
 
 exports.default = parseFragment;
 exports.parseFragment = parseFragment;
 
 /***/ }),
 
+/***/ 2347:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+exports.__esModule = true;
+exports.Identifier = Identifier;
+exports.SpreadElement = exports.RestElement = RestElement;
+exports.ObjectPattern = exports.ObjectExpression = ObjectExpression;
+exports.ObjectMethod = ObjectMethod;
+exports.ObjectProperty = ObjectProperty;
+exports.ArrayPattern = exports.ArrayExpression = ArrayExpression;
+exports.RegExpLiteral = RegExpLiteral;
+exports.BooleanLiteral = BooleanLiteral;
+exports.NullLiteral = NullLiteral;
+exports.NumericLiteral = NumericLiteral;
+exports.StringLiteral = StringLiteral;
+
+var t = _interopRequireWildcard(__webpack_require__(2268));
+
+var _jsesc = _interopRequireDefault(__webpack_require__(2377));
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
+
+function Identifier(node) {
+  this.word(node.name);
+}
+
+function RestElement(node) {
+  this.token("...");
+  this.print(node.argument, node);
+}
+
+function ObjectExpression(node) {
+  var props = node.properties;
+  this.token("{");
+  this.printInnerComments(node);
+
+  if (props.length) {
+    this.space();
+    this.printList(props, node, {
+      indent: true,
+      statement: true
+    });
+    this.space();
+  }
+
+  this.token("}");
+}
+
+function ObjectMethod(node) {
+  this.printJoin(node.decorators, node);
+
+  this._methodHead(node);
+
+  this.space();
+  this.print(node.body, node);
+}
+
+function ObjectProperty(node) {
+  this.printJoin(node.decorators, node);
+
+  if (node.computed) {
+    this.token("[");
+    this.print(node.key, node);
+    this.token("]");
+  } else {
+    if (t.isAssignmentPattern(node.value) && t.isIdentifier(node.key) && node.key.name === node.value.left.name) {
+      this.print(node.value, node);
+      return;
+    }
+
+    this.print(node.key, node);
+
+    if (node.shorthand && t.isIdentifier(node.key) && t.isIdentifier(node.value) && node.key.name === node.value.name) {
+      return;
+    }
+  }
+
+  this.token(":");
+  this.space();
+  this.print(node.value, node);
+}
+
+function ArrayExpression(node) {
+  var elems = node.elements;
+  var len = elems.length;
+  this.token("[");
+  this.printInnerComments(node);
+
+  for (var i = 0; i < elems.length; i++) {
+    var elem = elems[i];
+
+    if (elem) {
+      if (i > 0) this.space();
+      this.print(elem, node);
+      if (i < len - 1) this.token(",");
+    } else {
+      this.token(",");
+    }
+  }
+
+  this.token("]");
+}
+
+function RegExpLiteral(node) {
+  this.word("/" + node.pattern + "/" + node.flags);
+}
+
+function BooleanLiteral(node) {
+  this.word(node.value ? "true" : "false");
+}
+
+function NullLiteral() {
+  this.word("null");
+}
+
+function NumericLiteral(node) {
+  var raw = this.getPossibleRaw(node);
+  var value = node.value + "";
+
+  if (raw == null) {
+    this.number(value);
+  } else if (this.format.minified) {
+    this.number(raw.length < value.length ? raw : value);
+  } else {
+    this.number(raw);
+  }
+}
+
+function StringLiteral(node) {
+  var raw = this.getPossibleRaw(node);
+
+  if (!this.format.minified && raw != null) {
+    this.token(raw);
+    return;
+  }
+
+  var opts = {
+    quotes: "double",
+    wrap: true
+  };
+
+  if (this.format.jsonCompatibleStrings) {
+    opts.json = true;
+  }
+
+  var val = (0, _jsesc.default)(node.value, opts);
+  return this.token(val);
+}
+
+/***/ }),
+
+/***/ 2353:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+exports.__esModule = true;
+exports.needsWhitespace = needsWhitespace;
+exports.needsWhitespaceBefore = needsWhitespaceBefore;
+exports.needsWhitespaceAfter = needsWhitespaceAfter;
+exports.needsParens = needsParens;
+
+var whitespace = _interopRequireWildcard(__webpack_require__(2369));
+
+var parens = _interopRequireWildcard(__webpack_require__(2370));
+
+var t = _interopRequireWildcard(__webpack_require__(2268));
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
+
+function expandAliases(obj) {
+  var newObj = {};
+
+  function add(type, func) {
+    var fn = newObj[type];
+    newObj[type] = fn ? function (node, parent, stack) {
+      var result = fn(node, parent, stack);
+      return result == null ? func(node, parent, stack) : result;
+    } : func;
+  }
+
+  var _arr = Object.keys(obj);
+
+  for (var _i = 0; _i < _arr.length; _i++) {
+    var type = _arr[_i];
+    var aliases = t.FLIPPED_ALIAS_KEYS[type];
+
+    if (aliases) {
+      for (var _iterator = aliases, _isArray = Array.isArray(_iterator), _i2 = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
+        var _ref;
+
+        if (_isArray) {
+          if (_i2 >= _iterator.length) break;
+          _ref = _iterator[_i2++];
+        } else {
+          _i2 = _iterator.next();
+          if (_i2.done) break;
+          _ref = _i2.value;
+        }
+
+        var _alias = _ref;
+        add(_alias, obj[type]);
+      }
+    } else {
+      add(type, obj[type]);
+    }
+  }
+
+  return newObj;
+}
+
+var expandedParens = expandAliases(parens);
+var expandedWhitespaceNodes = expandAliases(whitespace.nodes);
+var expandedWhitespaceList = expandAliases(whitespace.list);
+
+function find(obj, node, parent, printStack) {
+  var fn = obj[node.type];
+  return fn ? fn(node, parent, printStack) : null;
+}
+
+function isOrHasCallExpression(node) {
+  if (t.isCallExpression(node)) {
+    return true;
+  }
+
+  if (t.isMemberExpression(node)) {
+    return isOrHasCallExpression(node.object) || !node.computed && isOrHasCallExpression(node.property);
+  } else {
+    return false;
+  }
+}
+
+function needsWhitespace(node, parent, type) {
+  if (!node) return 0;
+
+  if (t.isExpressionStatement(node)) {
+    node = node.expression;
+  }
+
+  var linesInfo = find(expandedWhitespaceNodes, node, parent);
+
+  if (!linesInfo) {
+    var items = find(expandedWhitespaceList, node, parent);
+
+    if (items) {
+      for (var i = 0; i < items.length; i++) {
+        linesInfo = needsWhitespace(items[i], node, type);
+        if (linesInfo) break;
+      }
+    }
+  }
+
+  if (typeof linesInfo === "object" && linesInfo !== null) {
+    return linesInfo[type] || 0;
+  }
+
+  return 0;
+}
+
+function needsWhitespaceBefore(node, parent) {
+  return needsWhitespace(node, parent, "before");
+}
+
+function needsWhitespaceAfter(node, parent) {
+  return needsWhitespace(node, parent, "after");
+}
+
+function needsParens(node, parent, printStack) {
+  if (!parent) return false;
+
+  if (t.isNewExpression(parent) && parent.callee === node) {
+    if (isOrHasCallExpression(node)) return true;
+  }
+
+  return find(expandedParens, node, parent, printStack);
+}
+
+/***/ }),
+
+/***/ 2354:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+exports.__esModule = true;
+exports.ImportSpecifier = ImportSpecifier;
+exports.ImportDefaultSpecifier = ImportDefaultSpecifier;
+exports.ExportDefaultSpecifier = ExportDefaultSpecifier;
+exports.ExportSpecifier = ExportSpecifier;
+exports.ExportNamespaceSpecifier = ExportNamespaceSpecifier;
+exports.ExportAllDeclaration = ExportAllDeclaration;
+exports.ExportNamedDeclaration = ExportNamedDeclaration;
+exports.ExportDefaultDeclaration = ExportDefaultDeclaration;
+exports.ImportDeclaration = ImportDeclaration;
+exports.ImportNamespaceSpecifier = ImportNamespaceSpecifier;
+
+var t = _interopRequireWildcard(__webpack_require__(2268));
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
+
+function ImportSpecifier(node) {
+  if (node.importKind === "type" || node.importKind === "typeof") {
+    this.word(node.importKind);
+    this.space();
+  }
+
+  this.print(node.imported, node);
+
+  if (node.local && node.local.name !== node.imported.name) {
+    this.space();
+    this.word("as");
+    this.space();
+    this.print(node.local, node);
+  }
+}
+
+function ImportDefaultSpecifier(node) {
+  this.print(node.local, node);
+}
+
+function ExportDefaultSpecifier(node) {
+  this.print(node.exported, node);
+}
+
+function ExportSpecifier(node) {
+  this.print(node.local, node);
+
+  if (node.exported && node.local.name !== node.exported.name) {
+    this.space();
+    this.word("as");
+    this.space();
+    this.print(node.exported, node);
+  }
+}
+
+function ExportNamespaceSpecifier(node) {
+  this.token("*");
+  this.space();
+  this.word("as");
+  this.space();
+  this.print(node.exported, node);
+}
+
+function ExportAllDeclaration(node) {
+  this.word("export");
+  this.space();
+
+  if (node.exportKind === "type") {
+    this.word("type");
+    this.space();
+  }
+
+  this.token("*");
+  this.space();
+  this.word("from");
+  this.space();
+  this.print(node.source, node);
+  this.semicolon();
+}
+
+function ExportNamedDeclaration(node) {
+  if (t.isClassDeclaration(node.declaration)) {
+    this.printJoin(node.declaration.decorators, node);
+  }
+
+  this.word("export");
+  this.space();
+  ExportDeclaration.apply(this, arguments);
+}
+
+function ExportDefaultDeclaration(node) {
+  if (t.isClassDeclaration(node.declaration)) {
+    this.printJoin(node.declaration.decorators, node);
+  }
+
+  this.word("export");
+  this.space();
+  this.word("default");
+  this.space();
+  ExportDeclaration.apply(this, arguments);
+}
+
+function ExportDeclaration(node) {
+  if (node.declaration) {
+    var declar = node.declaration;
+    this.print(declar, node);
+    if (!t.isStatement(declar)) this.semicolon();
+  } else {
+    if (node.exportKind === "type") {
+      this.word("type");
+      this.space();
+    }
+
+    var specifiers = node.specifiers.slice(0);
+    var hasSpecial = false;
+
+    while (true) {
+      var first = specifiers[0];
+
+      if (t.isExportDefaultSpecifier(first) || t.isExportNamespaceSpecifier(first)) {
+        hasSpecial = true;
+        this.print(specifiers.shift(), node);
+
+        if (specifiers.length) {
+          this.token(",");
+          this.space();
+        }
+      } else {
+        break;
+      }
+    }
+
+    if (specifiers.length || !specifiers.length && !hasSpecial) {
+      this.token("{");
+
+      if (specifiers.length) {
+        this.space();
+        this.printList(specifiers, node);
+        this.space();
+      }
+
+      this.token("}");
+    }
+
+    if (node.source) {
+      this.space();
+      this.word("from");
+      this.space();
+      this.print(node.source, node);
+    }
+
+    this.semicolon();
+  }
+}
+
+function ImportDeclaration(node) {
+  this.word("import");
+  this.space();
+
+  if (node.importKind === "type" || node.importKind === "typeof") {
+    this.word(node.importKind);
+    this.space();
+  }
+
+  var specifiers = node.specifiers.slice(0);
+
+  if (specifiers && specifiers.length) {
+    while (true) {
+      var first = specifiers[0];
+
+      if (t.isImportDefaultSpecifier(first) || t.isImportNamespaceSpecifier(first)) {
+        this.print(specifiers.shift(), node);
+
+        if (specifiers.length) {
+          this.token(",");
+          this.space();
+        }
+      } else {
+        break;
+      }
+    }
+
+    if (specifiers.length) {
+      this.token("{");
+      this.space();
+      this.printList(specifiers, node);
+      this.space();
+      this.token("}");
+    }
+
+    this.space();
+    this.word("from");
+    this.space();
+  }
+
+  this.print(node.source, node);
+  this.semicolon();
+}
+
+function ImportNamespaceSpecifier(node) {
+  this.token("*");
+  this.space();
+  this.word("as");
+  this.space();
+  this.print(node.local, node);
+}
+
+/***/ }),
+
+/***/ 2365:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+exports.__esModule = true;
+exports.default = _default;
+exports.CodeGenerator = void 0;
+
+var _sourceMap = _interopRequireDefault(__webpack_require__(2366));
+
+var _printer = _interopRequireDefault(__webpack_require__(2367));
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
+
+var Generator = function (_Printer) {
+  _inheritsLoose(Generator, _Printer);
+
+  function Generator(ast, opts, code) {
+    var _this;
+
+    if (opts === void 0) {
+      opts = {};
+    }
+
+    var format = normalizeOptions(code, opts);
+    var map = opts.sourceMaps ? new _sourceMap.default(opts, code) : null;
+    _this = _Printer.call(this, format, map) || this;
+    _this.ast = ast;
+    return _this;
+  }
+
+  var _proto = Generator.prototype;
+
+  _proto.generate = function generate() {
+    return _Printer.prototype.generate.call(this, this.ast);
+  };
+
+  return Generator;
+}(_printer.default);
+
+function normalizeOptions(code, opts) {
+  var format = {
+    auxiliaryCommentBefore: opts.auxiliaryCommentBefore,
+    auxiliaryCommentAfter: opts.auxiliaryCommentAfter,
+    shouldPrintComment: opts.shouldPrintComment,
+    retainLines: opts.retainLines,
+    retainFunctionParens: opts.retainFunctionParens,
+    comments: opts.comments == null || opts.comments,
+    compact: opts.compact,
+    minified: opts.minified,
+    concise: opts.concise,
+    jsonCompatibleStrings: opts.jsonCompatibleStrings,
+    indent: {
+      adjustMultilineComment: true,
+      style: "  ",
+      base: 0
+    }
+  };
+
+  if (format.minified) {
+    format.compact = true;
+
+    format.shouldPrintComment = format.shouldPrintComment || function () {
+      return format.comments;
+    };
+  } else {
+    format.shouldPrintComment = format.shouldPrintComment || function (value) {
+      return format.comments || value.indexOf("@license") >= 0 || value.indexOf("@preserve") >= 0;
+    };
+  }
+
+  if (format.compact === "auto") {
+    format.compact = code.length > 500000;
+
+    if (format.compact) {
+      console.error("[BABEL] Note: The code generator has deoptimised the styling of " + (opts.filename + " as it exceeds the max of " + "500KB" + "."));
+    }
+  }
+
+  if (format.compact) {
+    format.indent.adjustMultilineComment = false;
+  }
+
+  return format;
+}
+
+var CodeGenerator = function () {
+  function CodeGenerator(ast, opts, code) {
+    this._generator = new Generator(ast, opts, code);
+  }
+
+  var _proto2 = CodeGenerator.prototype;
+
+  _proto2.generate = function generate() {
+    return this._generator.generate();
+  };
+
+  return CodeGenerator;
+}();
+
+exports.CodeGenerator = CodeGenerator;
+
+function _default(ast, opts, code) {
+  var gen = new Generator(ast, opts, code);
+  return gen.generate();
+}
+
+/***/ }),
+
+/***/ 2366:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+exports.__esModule = true;
+exports.default = void 0;
+
+var _sourceMap = _interopRequireDefault(__webpack_require__(815));
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var SourceMap = function () {
+  function SourceMap(opts, code) {
+    this._cachedMap = null;
+    this._code = code;
+    this._opts = opts;
+    this._rawMappings = [];
+  }
+
+  var _proto = SourceMap.prototype;
+
+  _proto.get = function get() {
+    if (!this._cachedMap) {
+      var map = this._cachedMap = new _sourceMap.default.SourceMapGenerator({
+        sourceRoot: this._opts.sourceRoot
+      });
+      var code = this._code;
+
+      if (typeof code === "string") {
+        map.setSourceContent(this._opts.sourceFileName, code);
+      } else if (typeof code === "object") {
+        Object.keys(code).forEach(function (sourceFileName) {
+          map.setSourceContent(sourceFileName, code[sourceFileName]);
+        });
+      }
+
+      this._rawMappings.forEach(map.addMapping, map);
+    }
+
+    return this._cachedMap.toJSON();
+  };
+
+  _proto.getRawMappings = function getRawMappings() {
+    return this._rawMappings.slice();
+  };
+
+  _proto.mark = function mark(generatedLine, generatedColumn, line, column, identifierName, filename) {
+    if (this._lastGenLine !== generatedLine && line === null) return;
+
+    if (this._lastGenLine === generatedLine && this._lastSourceLine === line && this._lastSourceColumn === column) {
+      return;
+    }
+
+    this._cachedMap = null;
+    this._lastGenLine = generatedLine;
+    this._lastSourceLine = line;
+    this._lastSourceColumn = column;
+
+    this._rawMappings.push({
+      name: identifierName || undefined,
+      generated: {
+        line: generatedLine,
+        column: generatedColumn
+      },
+      source: line == null ? undefined : filename || this._opts.sourceFileName,
+      original: line == null ? undefined : {
+        line: line,
+        column: column
+      }
+    });
+  };
+
+  return SourceMap;
+}();
+
+exports.default = SourceMap;
+
+/***/ }),
+
+/***/ 2367:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+exports.__esModule = true;
+exports.default = void 0;
+
+var _isInteger = _interopRequireDefault(__webpack_require__(1687));
+
+var _repeat = _interopRequireDefault(__webpack_require__(605));
+
+var _buffer = _interopRequireDefault(__webpack_require__(2368));
+
+var n = _interopRequireWildcard(__webpack_require__(2353));
+
+var t = _interopRequireWildcard(__webpack_require__(2268));
+
+var generatorFunctions = _interopRequireWildcard(__webpack_require__(2371));
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var SCIENTIFIC_NOTATION = /e/i;
+var ZERO_DECIMAL_INTEGER = /\.0+$/;
+var NON_DECIMAL_LITERAL = /^0[box]/;
+
+var Printer = function () {
+  function Printer(format, map) {
+    this.inForStatementInitCounter = 0;
+    this._printStack = [];
+    this._indent = 0;
+    this._insideAux = false;
+    this._printedCommentStarts = {};
+    this._parenPushNewlineState = null;
+    this._noLineTerminator = false;
+    this._printAuxAfterOnNextUserNode = false;
+    this._printedComments = new WeakSet();
+    this._endsWithInteger = false;
+    this._endsWithWord = false;
+    this.format = format || {};
+    this._buf = new _buffer.default(map);
+  }
+
+  var _proto = Printer.prototype;
+
+  _proto.generate = function generate(ast) {
+    this.print(ast);
+
+    this._maybeAddAuxComment();
+
+    return this._buf.get();
+  };
+
+  _proto.indent = function indent() {
+    if (this.format.compact || this.format.concise) return;
+    this._indent++;
+  };
+
+  _proto.dedent = function dedent() {
+    if (this.format.compact || this.format.concise) return;
+    this._indent--;
+  };
+
+  _proto.semicolon = function semicolon(force) {
+    if (force === void 0) {
+      force = false;
+    }
+
+    this._maybeAddAuxComment();
+
+    this._append(";", !force);
+  };
+
+  _proto.rightBrace = function rightBrace() {
+    if (this.format.minified) {
+      this._buf.removeLastSemicolon();
+    }
+
+    this.token("}");
+  };
+
+  _proto.space = function space(force) {
+    if (force === void 0) {
+      force = false;
+    }
+
+    if (this.format.compact) return;
+
+    if (this._buf.hasContent() && !this.endsWith(" ") && !this.endsWith("\n") || force) {
+      this._space();
+    }
+  };
+
+  _proto.word = function word(str) {
+    if (this._endsWithWord || this.endsWith("/") && str.indexOf("/") === 0) {
+      this._space();
+    }
+
+    this._maybeAddAuxComment();
+
+    this._append(str);
+
+    this._endsWithWord = true;
+  };
+
+  _proto.number = function number(str) {
+    this.word(str);
+    this._endsWithInteger = (0, _isInteger.default)(+str) && !NON_DECIMAL_LITERAL.test(str) && !SCIENTIFIC_NOTATION.test(str) && !ZERO_DECIMAL_INTEGER.test(str) && str[str.length - 1] !== ".";
+  };
+
+  _proto.token = function token(str) {
+    if (str === "--" && this.endsWith("!") || str[0] === "+" && this.endsWith("+") || str[0] === "-" && this.endsWith("-") || str[0] === "." && this._endsWithInteger) {
+      this._space();
+    }
+
+    this._maybeAddAuxComment();
+
+    this._append(str);
+  };
+
+  _proto.newline = function newline(i) {
+    if (this.format.retainLines || this.format.compact) return;
+
+    if (this.format.concise) {
+      this.space();
+      return;
+    }
+
+    if (this.endsWith("\n\n")) return;
+    if (typeof i !== "number") i = 1;
+    i = Math.min(2, i);
+    if (this.endsWith("{\n") || this.endsWith(":\n")) i--;
+    if (i <= 0) return;
+
+    for (var j = 0; j < i; j++) {
+      this._newline();
+    }
+  };
+
+  _proto.endsWith = function endsWith(str) {
+    return this._buf.endsWith(str);
+  };
+
+  _proto.removeTrailingNewline = function removeTrailingNewline() {
+    this._buf.removeTrailingNewline();
+  };
+
+  _proto.source = function source(prop, loc) {
+    this._catchUp(prop, loc);
+
+    this._buf.source(prop, loc);
+  };
+
+  _proto.withSource = function withSource(prop, loc, cb) {
+    this._catchUp(prop, loc);
+
+    this._buf.withSource(prop, loc, cb);
+  };
+
+  _proto._space = function _space() {
+    this._append(" ", true);
+  };
+
+  _proto._newline = function _newline() {
+    this._append("\n", true);
+  };
+
+  _proto._append = function _append(str, queue) {
+    if (queue === void 0) {
+      queue = false;
+    }
+
+    this._maybeAddParen(str);
+
+    this._maybeIndent(str);
+
+    if (queue) this._buf.queue(str);else this._buf.append(str);
+    this._endsWithWord = false;
+    this._endsWithInteger = false;
+  };
+
+  _proto._maybeIndent = function _maybeIndent(str) {
+    if (this._indent && this.endsWith("\n") && str[0] !== "\n") {
+      this._buf.queue(this._getIndent());
+    }
+  };
+
+  _proto._maybeAddParen = function _maybeAddParen(str) {
+    var parenPushNewlineState = this._parenPushNewlineState;
+    if (!parenPushNewlineState) return;
+    this._parenPushNewlineState = null;
+    var i;
+
+    for (i = 0; i < str.length && str[i] === " "; i++) {
+      continue;
+    }
+
+    if (i === str.length) return;
+    var cha = str[i];
+
+    if (cha !== "\n") {
+      if (cha !== "/") return;
+      if (i + 1 === str.length) return;
+      var chaPost = str[i + 1];
+      if (chaPost !== "/" && chaPost !== "*") return;
+    }
+
+    this.token("(");
+    this.indent();
+    parenPushNewlineState.printed = true;
+  };
+
+  _proto._catchUp = function _catchUp(prop, loc) {
+    if (!this.format.retainLines) return;
+    var pos = loc ? loc[prop] : null;
+
+    if (pos && pos.line !== null) {
+      var count = pos.line - this._buf.getCurrentLine();
+
+      for (var i = 0; i < count; i++) {
+        this._newline();
+      }
+    }
+  };
+
+  _proto._getIndent = function _getIndent() {
+    return (0, _repeat.default)(this.format.indent.style, this._indent);
+  };
+
+  _proto.startTerminatorless = function startTerminatorless(isLabel) {
+    if (isLabel === void 0) {
+      isLabel = false;
+    }
+
+    if (isLabel) {
+      this._noLineTerminator = true;
+      return null;
+    } else {
+      return this._parenPushNewlineState = {
+        printed: false
+      };
+    }
+  };
+
+  _proto.endTerminatorless = function endTerminatorless(state) {
+    this._noLineTerminator = false;
+
+    if (state && state.printed) {
+      this.dedent();
+      this.newline();
+      this.token(")");
+    }
+  };
+
+  _proto.print = function print(node, parent) {
+    var _this = this;
+
+    if (!node) return;
+    var oldConcise = this.format.concise;
+
+    if (node._compact) {
+      this.format.concise = true;
+    }
+
+    var printMethod = this[node.type];
+
+    if (!printMethod) {
+      throw new ReferenceError("unknown node of type " + JSON.stringify(node.type) + " with constructor " + JSON.stringify(node && node.constructor.name));
+    }
+
+    this._printStack.push(node);
+
+    var oldInAux = this._insideAux;
+    this._insideAux = !node.loc;
+
+    this._maybeAddAuxComment(this._insideAux && !oldInAux);
+
+    var needsParens = n.needsParens(node, parent, this._printStack);
+
+    if (this.format.retainFunctionParens && node.type === "FunctionExpression" && node.extra && node.extra.parenthesized) {
+      needsParens = true;
+    }
+
+    if (needsParens) this.token("(");
+
+    this._printLeadingComments(node, parent);
+
+    var loc = t.isProgram(node) || t.isFile(node) ? null : node.loc;
+    this.withSource("start", loc, function () {
+      _this[node.type](node, parent);
+    });
+
+    this._printTrailingComments(node, parent);
+
+    if (needsParens) this.token(")");
+
+    this._printStack.pop();
+
+    this.format.concise = oldConcise;
+    this._insideAux = oldInAux;
+  };
+
+  _proto._maybeAddAuxComment = function _maybeAddAuxComment(enteredPositionlessNode) {
+    if (enteredPositionlessNode) this._printAuxBeforeComment();
+    if (!this._insideAux) this._printAuxAfterComment();
+  };
+
+  _proto._printAuxBeforeComment = function _printAuxBeforeComment() {
+    if (this._printAuxAfterOnNextUserNode) return;
+    this._printAuxAfterOnNextUserNode = true;
+    var comment = this.format.auxiliaryCommentBefore;
+
+    if (comment) {
+      this._printComment({
+        type: "CommentBlock",
+        value: comment
+      });
+    }
+  };
+
+  _proto._printAuxAfterComment = function _printAuxAfterComment() {
+    if (!this._printAuxAfterOnNextUserNode) return;
+    this._printAuxAfterOnNextUserNode = false;
+    var comment = this.format.auxiliaryCommentAfter;
+
+    if (comment) {
+      this._printComment({
+        type: "CommentBlock",
+        value: comment
+      });
+    }
+  };
+
+  _proto.getPossibleRaw = function getPossibleRaw(node) {
+    var extra = node.extra;
+
+    if (extra && extra.raw != null && extra.rawValue != null && node.value === extra.rawValue) {
+      return extra.raw;
+    }
+  };
+
+  _proto.printJoin = function printJoin(nodes, parent, opts) {
+    if (opts === void 0) {
+      opts = {};
+    }
+
+    if (!nodes || !nodes.length) return;
+    if (opts.indent) this.indent();
+    var newlineOpts = {
+      addNewlines: opts.addNewlines
+    };
+
+    for (var i = 0; i < nodes.length; i++) {
+      var node = nodes[i];
+      if (!node) continue;
+      if (opts.statement) this._printNewline(true, node, parent, newlineOpts);
+      this.print(node, parent);
+
+      if (opts.iterator) {
+        opts.iterator(node, i);
+      }
+
+      if (opts.separator && i < nodes.length - 1) {
+        opts.separator.call(this);
+      }
+
+      if (opts.statement) this._printNewline(false, node, parent, newlineOpts);
+    }
+
+    if (opts.indent) this.dedent();
+  };
+
+  _proto.printAndIndentOnComments = function printAndIndentOnComments(node, parent) {
+    var indent = node.leadingComments && node.leadingComments.length > 0;
+    if (indent) this.indent();
+    this.print(node, parent);
+    if (indent) this.dedent();
+  };
+
+  _proto.printBlock = function printBlock(parent) {
+    var node = parent.body;
+
+    if (!t.isEmptyStatement(node)) {
+      this.space();
+    }
+
+    this.print(node, parent);
+  };
+
+  _proto._printTrailingComments = function _printTrailingComments(node, parent) {
+    this._printComments(this._getComments(false, node, parent));
+  };
+
+  _proto._printLeadingComments = function _printLeadingComments(node, parent) {
+    this._printComments(this._getComments(true, node, parent));
+  };
+
+  _proto.printInnerComments = function printInnerComments(node, indent) {
+    if (indent === void 0) {
+      indent = true;
+    }
+
+    if (!node.innerComments || !node.innerComments.length) return;
+    if (indent) this.indent();
+
+    this._printComments(node.innerComments);
+
+    if (indent) this.dedent();
+  };
+
+  _proto.printSequence = function printSequence(nodes, parent, opts) {
+    if (opts === void 0) {
+      opts = {};
+    }
+
+    opts.statement = true;
+    return this.printJoin(nodes, parent, opts);
+  };
+
+  _proto.printList = function printList(items, parent, opts) {
+    if (opts === void 0) {
+      opts = {};
+    }
+
+    if (opts.separator == null) {
+      opts.separator = commaSeparator;
+    }
+
+    return this.printJoin(items, parent, opts);
+  };
+
+  _proto._printNewline = function _printNewline(leading, node, parent, opts) {
+    if (this.format.retainLines || this.format.compact) return;
+
+    if (this.format.concise) {
+      this.space();
+      return;
+    }
+
+    var lines = 0;
+
+    if (this._buf.hasContent()) {
+      if (!leading) lines++;
+      if (opts.addNewlines) lines += opts.addNewlines(leading, node) || 0;
+      var needs = leading ? n.needsWhitespaceBefore : n.needsWhitespaceAfter;
+      if (needs(node, parent)) lines++;
+    }
+
+    this.newline(lines);
+  };
+
+  _proto._getComments = function _getComments(leading, node) {
+    return node && (leading ? node.leadingComments : node.trailingComments) || [];
+  };
+
+  _proto._printComment = function _printComment(comment) {
+    var _this2 = this;
+
+    if (!this.format.shouldPrintComment(comment.value)) return;
+    if (comment.ignore) return;
+    if (this._printedComments.has(comment)) return;
+
+    this._printedComments.add(comment);
+
+    if (comment.start != null) {
+      if (this._printedCommentStarts[comment.start]) return;
+      this._printedCommentStarts[comment.start] = true;
+    }
+
+    var isBlockComment = comment.type === "CommentBlock";
+    this.newline(this._buf.hasContent() && !this._noLineTerminator && isBlockComment ? 1 : 0);
+    if (!this.endsWith("[") && !this.endsWith("{")) this.space();
+    var val = !isBlockComment && !this._noLineTerminator ? "//" + comment.value + "\n" : "/*" + comment.value + "*/";
+
+    if (isBlockComment && this.format.indent.adjustMultilineComment) {
+      var offset = comment.loc && comment.loc.start.column;
+
+      if (offset) {
+        var newlineRegex = new RegExp("\\n\\s{1," + offset + "}", "g");
+        val = val.replace(newlineRegex, "\n");
+      }
+
+      var indentSize = Math.max(this._getIndent().length, this._buf.getCurrentColumn());
+      val = val.replace(/\n(?!$)/g, "\n" + (0, _repeat.default)(" ", indentSize));
+    }
+
+    if (this.endsWith("/")) this._space();
+    this.withSource("start", comment.loc, function () {
+      _this2._append(val);
+    });
+    this.newline(isBlockComment && !this._noLineTerminator ? 1 : 0);
+  };
+
+  _proto._printComments = function _printComments(comments) {
+    if (!comments || !comments.length) return;
+
+    for (var _iterator = comments, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
+      var _ref;
+
+      if (_isArray) {
+        if (_i >= _iterator.length) break;
+        _ref = _iterator[_i++];
+      } else {
+        _i = _iterator.next();
+        if (_i.done) break;
+        _ref = _i.value;
+      }
+
+      var _comment2 = _ref;
+
+      this._printComment(_comment2);
+    }
+  };
+
+  return Printer;
+}();
+
+exports.default = Printer;
+Object.assign(Printer.prototype, generatorFunctions);
+
+function commaSeparator() {
+  this.token(",");
+  this.space();
+}
+
+/***/ }),
+
+/***/ 2368:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+exports.__esModule = true;
+exports.default = void 0;
+
+var _trimRight = _interopRequireDefault(__webpack_require__(1689));
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var SPACES_RE = /^[ \t]+$/;
+
+var Buffer = function () {
+  function Buffer(map) {
+    this._map = null;
+    this._buf = [];
+    this._last = "";
+    this._queue = [];
+    this._position = {
+      line: 1,
+      column: 0
+    };
+    this._sourcePosition = {
+      identifierName: null,
+      line: null,
+      column: null,
+      filename: null
+    };
+    this._map = map;
+  }
+
+  var _proto = Buffer.prototype;
+
+  _proto.get = function get() {
+    this._flush();
+
+    var map = this._map;
+    var result = {
+      code: (0, _trimRight.default)(this._buf.join("")),
+      map: null,
+      rawMappings: map && map.getRawMappings()
+    };
+
+    if (map) {
+      Object.defineProperty(result, "map", {
+        configurable: true,
+        enumerable: true,
+        get: function get() {
+          return this.map = map.get();
+        },
+        set: function set(value) {
+          Object.defineProperty(this, "map", {
+            value: value,
+            writable: true
+          });
+        }
+      });
+    }
+
+    return result;
+  };
+
+  _proto.append = function append(str) {
+    this._flush();
+
+    var _sourcePosition = this._sourcePosition,
+        line = _sourcePosition.line,
+        column = _sourcePosition.column,
+        filename = _sourcePosition.filename,
+        identifierName = _sourcePosition.identifierName;
+
+    this._append(str, line, column, identifierName, filename);
+  };
+
+  _proto.queue = function queue(str) {
+    if (str === "\n") {
+      while (this._queue.length > 0 && SPACES_RE.test(this._queue[0][0])) {
+        this._queue.shift();
+      }
+    }
+
+    var _sourcePosition2 = this._sourcePosition,
+        line = _sourcePosition2.line,
+        column = _sourcePosition2.column,
+        filename = _sourcePosition2.filename,
+        identifierName = _sourcePosition2.identifierName;
+
+    this._queue.unshift([str, line, column, identifierName, filename]);
+  };
+
+  _proto._flush = function _flush() {
+    var item;
+
+    while (item = this._queue.pop()) {
+      this._append.apply(this, item);
+    }
+  };
+
+  _proto._append = function _append(str, line, column, identifierName, filename) {
+    if (this._map && str[0] !== "\n") {
+      this._map.mark(this._position.line, this._position.column, line, column, identifierName, filename);
+    }
+
+    this._buf.push(str);
+
+    this._last = str[str.length - 1];
+
+    for (var i = 0; i < str.length; i++) {
+      if (str[i] === "\n") {
+        this._position.line++;
+        this._position.column = 0;
+      } else {
+        this._position.column++;
+      }
+    }
+  };
+
+  _proto.removeTrailingNewline = function removeTrailingNewline() {
+    if (this._queue.length > 0 && this._queue[0][0] === "\n") {
+      this._queue.shift();
+    }
+  };
+
+  _proto.removeLastSemicolon = function removeLastSemicolon() {
+    if (this._queue.length > 0 && this._queue[0][0] === ";") {
+      this._queue.shift();
+    }
+  };
+
+  _proto.endsWith = function endsWith(suffix) {
+    if (suffix.length === 1) {
+      var last;
+
+      if (this._queue.length > 0) {
+        var str = this._queue[0][0];
+        last = str[str.length - 1];
+      } else {
+        last = this._last;
+      }
+
+      return last === suffix;
+    }
+
+    var end = this._last + this._queue.reduce(function (acc, item) {
+      return item[0] + acc;
+    }, "");
+
+    if (suffix.length <= end.length) {
+      return end.slice(-suffix.length) === suffix;
+    }
+
+    return false;
+  };
+
+  _proto.hasContent = function hasContent() {
+    return this._queue.length > 0 || !!this._last;
+  };
+
+  _proto.source = function source(prop, loc) {
+    if (prop && !loc) return;
+    var pos = loc ? loc[prop] : null;
+    this._sourcePosition.identifierName = loc && loc.identifierName || null;
+    this._sourcePosition.line = pos ? pos.line : null;
+    this._sourcePosition.column = pos ? pos.column : null;
+    this._sourcePosition.filename = loc && loc.filename || null;
+  };
+
+  _proto.withSource = function withSource(prop, loc, cb) {
+    if (!this._map) return cb();
+    var originalLine = this._sourcePosition.line;
+    var originalColumn = this._sourcePosition.column;
+    var originalFilename = this._sourcePosition.filename;
+    var originalIdentifierName = this._sourcePosition.identifierName;
+    this.source(prop, loc);
+    cb();
+    this._sourcePosition.line = originalLine;
+    this._sourcePosition.column = originalColumn;
+    this._sourcePosition.filename = originalFilename;
+    this._sourcePosition.identifierName = originalIdentifierName;
+  };
+
+  _proto.getCurrentColumn = function getCurrentColumn() {
+    var extra = this._queue.reduce(function (acc, item) {
+      return item[0] + acc;
+    }, "");
+
+    var lastIndex = extra.lastIndexOf("\n");
+    return lastIndex === -1 ? this._position.column + extra.length : extra.length - 1 - lastIndex;
+  };
+
+  _proto.getCurrentLine = function getCurrentLine() {
+    var extra = this._queue.reduce(function (acc, item) {
+      return item[0] + acc;
+    }, "");
+
+    var count = 0;
+
+    for (var i = 0; i < extra.length; i++) {
+      if (extra[i] === "\n") count++;
+    }
+
+    return this._position.line + count;
+  };
+
+  return Buffer;
+}();
+
+exports.default = Buffer;
+
+/***/ }),
+
+/***/ 2369:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+exports.__esModule = true;
+exports.list = exports.nodes = void 0;
+
+var t = _interopRequireWildcard(__webpack_require__(2268));
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
+
+function crawl(node, state) {
+  if (state === void 0) {
+    state = {};
+  }
+
+  if (t.isMemberExpression(node)) {
+    crawl(node.object, state);
+    if (node.computed) crawl(node.property, state);
+  } else if (t.isBinary(node) || t.isAssignmentExpression(node)) {
+    crawl(node.left, state);
+    crawl(node.right, state);
+  } else if (t.isCallExpression(node)) {
+    state.hasCall = true;
+    crawl(node.callee, state);
+  } else if (t.isFunction(node)) {
+    state.hasFunction = true;
+  } else if (t.isIdentifier(node)) {
+    state.hasHelper = state.hasHelper || isHelper(node.callee);
+  }
+
+  return state;
+}
+
+function isHelper(node) {
+  if (t.isMemberExpression(node)) {
+    return isHelper(node.object) || isHelper(node.property);
+  } else if (t.isIdentifier(node)) {
+    return node.name === "require" || node.name[0] === "_";
+  } else if (t.isCallExpression(node)) {
+    return isHelper(node.callee);
+  } else if (t.isBinary(node) || t.isAssignmentExpression(node)) {
+    return t.isIdentifier(node.left) && isHelper(node.left) || isHelper(node.right);
+  } else {
+    return false;
+  }
+}
+
+function isType(node) {
+  return t.isLiteral(node) || t.isObjectExpression(node) || t.isArrayExpression(node) || t.isIdentifier(node) || t.isMemberExpression(node);
+}
+
+var nodes = {
+  AssignmentExpression: function AssignmentExpression(node) {
+    var state = crawl(node.right);
+
+    if (state.hasCall && state.hasHelper || state.hasFunction) {
+      return {
+        before: state.hasFunction,
+        after: true
+      };
+    }
+  },
+  SwitchCase: function SwitchCase(node, parent) {
+    return {
+      before: node.consequent.length || parent.cases[0] === node,
+      after: !node.consequent.length && parent.cases[parent.cases.length - 1] === node
+    };
+  },
+  LogicalExpression: function LogicalExpression(node) {
+    if (t.isFunction(node.left) || t.isFunction(node.right)) {
+      return {
+        after: true
+      };
+    }
+  },
+  Literal: function Literal(node) {
+    if (node.value === "use strict") {
+      return {
+        after: true
+      };
+    }
+  },
+  CallExpression: function CallExpression(node) {
+    if (t.isFunction(node.callee) || isHelper(node)) {
+      return {
+        before: true,
+        after: true
+      };
+    }
+  },
+  VariableDeclaration: function VariableDeclaration(node) {
+    for (var i = 0; i < node.declarations.length; i++) {
+      var declar = node.declarations[i];
+      var enabled = isHelper(declar.id) && !isType(declar.init);
+
+      if (!enabled) {
+        var state = crawl(declar.init);
+        enabled = isHelper(declar.init) && state.hasCall || state.hasFunction;
+      }
+
+      if (enabled) {
+        return {
+          before: true,
+          after: true
+        };
+      }
+    }
+  },
+  IfStatement: function IfStatement(node) {
+    if (t.isBlockStatement(node.consequent)) {
+      return {
+        before: true,
+        after: true
+      };
+    }
+  }
+};
+exports.nodes = nodes;
+
+nodes.ObjectProperty = nodes.ObjectTypeProperty = nodes.ObjectMethod = function (node, parent) {
+  if (parent.properties[0] === node) {
+    return {
+      before: true
+    };
+  }
+};
+
+nodes.ObjectTypeCallProperty = function (node, parent) {
+  if (parent.callProperties[0] === node && (!parent.properties || !parent.properties.length)) {
+    return {
+      before: true
+    };
+  }
+};
+
+nodes.ObjectTypeIndexer = function (node, parent) {
+  if (parent.indexers[0] === node && (!parent.properties || !parent.properties.length) && (!parent.callProperties || !parent.callProperties.length)) {
+    return {
+      before: true
+    };
+  }
+};
+
+var list = {
+  VariableDeclaration: function VariableDeclaration(node) {
+    return node.declarations.map(function (decl) {
+      return decl.init;
+    });
+  },
+  ArrayExpression: function ArrayExpression(node) {
+    return node.elements;
+  },
+  ObjectExpression: function ObjectExpression(node) {
+    return node.properties;
+  }
+};
+exports.list = list;
+[["Function", true], ["Class", true], ["Loop", true], ["LabeledStatement", true], ["SwitchStatement", true], ["TryStatement", true]].forEach(function (_ref) {
+  var type = _ref[0],
+      amounts = _ref[1];
+
+  if (typeof amounts === "boolean") {
+    amounts = {
+      after: amounts,
+      before: amounts
+    };
+  }
+
+  [type].concat(t.FLIPPED_ALIAS_KEYS[type] || []).forEach(function (type) {
+    nodes[type] = function () {
+      return amounts;
+    };
+  });
+});
+
+/***/ }),
+
+/***/ 2370:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+exports.__esModule = true;
+exports.FunctionTypeAnnotation = exports.NullableTypeAnnotation = NullableTypeAnnotation;
+exports.UpdateExpression = UpdateExpression;
+exports.ObjectExpression = ObjectExpression;
+exports.DoExpression = DoExpression;
+exports.Binary = Binary;
+exports.IntersectionTypeAnnotation = exports.UnionTypeAnnotation = UnionTypeAnnotation;
+exports.TSAsExpression = TSAsExpression;
+exports.TSTypeAssertion = TSTypeAssertion;
+exports.BinaryExpression = BinaryExpression;
+exports.SequenceExpression = SequenceExpression;
+exports.AwaitExpression = exports.YieldExpression = YieldExpression;
+exports.ClassExpression = ClassExpression;
+exports.UnaryLike = UnaryLike;
+exports.FunctionExpression = FunctionExpression;
+exports.ArrowFunctionExpression = ArrowFunctionExpression;
+exports.ConditionalExpression = ConditionalExpression;
+exports.AssignmentExpression = AssignmentExpression;
+exports.NewExpression = NewExpression;
+
+var t = _interopRequireWildcard(__webpack_require__(2268));
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
+
+var PRECEDENCE = {
+  "||": 0,
+  "&&": 1,
+  "|": 2,
+  "^": 3,
+  "&": 4,
+  "==": 5,
+  "===": 5,
+  "!=": 5,
+  "!==": 5,
+  "<": 6,
+  ">": 6,
+  "<=": 6,
+  ">=": 6,
+  in: 6,
+  instanceof: 6,
+  ">>": 7,
+  "<<": 7,
+  ">>>": 7,
+  "+": 8,
+  "-": 8,
+  "*": 9,
+  "/": 9,
+  "%": 9,
+  "**": 10
+};
+
+var isClassExtendsClause = function isClassExtendsClause(node, parent) {
+  return (t.isClassDeclaration(parent) || t.isClassExpression(parent)) && parent.superClass === node;
+};
+
+function NullableTypeAnnotation(node, parent) {
+  return t.isArrayTypeAnnotation(parent);
+}
+
+function UpdateExpression(node, parent) {
+  return t.isMemberExpression(parent, {
+    object: node
+  }) || t.isCallExpression(parent, {
+    callee: node
+  }) || t.isNewExpression(parent, {
+    callee: node
+  }) || isClassExtendsClause(node, parent);
+}
+
+function ObjectExpression(node, parent, printStack) {
+  return isFirstInStatement(printStack, {
+    considerArrow: true
+  });
+}
+
+function DoExpression(node, parent, printStack) {
+  return isFirstInStatement(printStack);
+}
+
+function Binary(node, parent) {
+  if (node.operator === "**" && t.isBinaryExpression(parent, {
+    operator: "**"
+  })) {
+    return parent.left === node;
+  }
+
+  if (isClassExtendsClause(node, parent)) {
+    return true;
+  }
+
+  if ((t.isCallExpression(parent) || t.isNewExpression(parent)) && parent.callee === node || t.isUnaryLike(parent) || t.isMemberExpression(parent) && parent.object === node || t.isAwaitExpression(parent)) {
+    return true;
+  }
+
+  if (t.isBinary(parent)) {
+    var parentOp = parent.operator;
+    var parentPos = PRECEDENCE[parentOp];
+    var nodeOp = node.operator;
+    var nodePos = PRECEDENCE[nodeOp];
+
+    if (parentPos === nodePos && parent.right === node && !t.isLogicalExpression(parent) || parentPos > nodePos) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+function UnionTypeAnnotation(node, parent) {
+  return t.isArrayTypeAnnotation(parent) || t.isNullableTypeAnnotation(parent) || t.isIntersectionTypeAnnotation(parent) || t.isUnionTypeAnnotation(parent);
+}
+
+function TSAsExpression() {
+  return true;
+}
+
+function TSTypeAssertion() {
+  return true;
+}
+
+function BinaryExpression(node, parent) {
+  return node.operator === "in" && (t.isVariableDeclarator(parent) || t.isFor(parent));
+}
+
+function SequenceExpression(node, parent) {
+  if (t.isForStatement(parent) || t.isThrowStatement(parent) || t.isReturnStatement(parent) || t.isIfStatement(parent) && parent.test === node || t.isWhileStatement(parent) && parent.test === node || t.isForInStatement(parent) && parent.right === node || t.isSwitchStatement(parent) && parent.discriminant === node || t.isExpressionStatement(parent) && parent.expression === node) {
+    return false;
+  }
+
+  return true;
+}
+
+function YieldExpression(node, parent) {
+  return t.isBinary(parent) || t.isUnaryLike(parent) || t.isCallExpression(parent) || t.isMemberExpression(parent) || t.isNewExpression(parent) || t.isConditionalExpression(parent) && node === parent.test || isClassExtendsClause(node, parent);
+}
+
+function ClassExpression(node, parent, printStack) {
+  return isFirstInStatement(printStack, {
+    considerDefaultExports: true
+  });
+}
+
+function UnaryLike(node, parent) {
+  return t.isMemberExpression(parent, {
+    object: node
+  }) || t.isCallExpression(parent, {
+    callee: node
+  }) || t.isNewExpression(parent, {
+    callee: node
+  }) || t.isBinaryExpression(parent, {
+    operator: "**",
+    left: node
+  }) || isClassExtendsClause(node, parent);
+}
+
+function FunctionExpression(node, parent, printStack) {
+  return isFirstInStatement(printStack, {
+    considerDefaultExports: true
+  });
+}
+
+function ArrowFunctionExpression(node, parent) {
+  return t.isExportDeclaration(parent) || ConditionalExpression(node, parent);
+}
+
+function ConditionalExpression(node, parent) {
+  if (t.isUnaryLike(parent) || t.isBinary(parent) || t.isConditionalExpression(parent, {
+    test: node
+  }) || t.isAwaitExpression(parent) || t.isTaggedTemplateExpression(parent) || t.isTSTypeAssertion(parent) || t.isTSAsExpression(parent)) {
+    return true;
+  }
+
+  return UnaryLike(node, parent);
+}
+
+function AssignmentExpression(node) {
+  if (t.isObjectPattern(node.left)) {
+    return true;
+  } else {
+    return ConditionalExpression.apply(void 0, arguments);
+  }
+}
+
+function NewExpression(node, parent) {
+  return isClassExtendsClause(node, parent);
+}
+
+function isFirstInStatement(printStack, _temp) {
+  var _ref = _temp === void 0 ? {} : _temp,
+      _ref$considerArrow = _ref.considerArrow,
+      considerArrow = _ref$considerArrow === void 0 ? false : _ref$considerArrow,
+      _ref$considerDefaultE = _ref.considerDefaultExports,
+      considerDefaultExports = _ref$considerDefaultE === void 0 ? false : _ref$considerDefaultE;
+
+  var i = printStack.length - 1;
+  var node = printStack[i];
+  i--;
+  var parent = printStack[i];
+
+  while (i > 0) {
+    if (t.isExpressionStatement(parent, {
+      expression: node
+    }) || t.isTaggedTemplateExpression(parent) || considerDefaultExports && t.isExportDefaultDeclaration(parent, {
+      declaration: node
+    }) || considerArrow && t.isArrowFunctionExpression(parent, {
+      body: node
+    })) {
+      return true;
+    }
+
+    if (t.isCallExpression(parent, {
+      callee: node
+    }) || t.isSequenceExpression(parent) && parent.expressions[0] === node || t.isMemberExpression(parent, {
+      object: node
+    }) || t.isConditional(parent, {
+      test: node
+    }) || t.isBinary(parent, {
+      left: node
+    }) || t.isAssignmentExpression(parent, {
+      left: node
+    })) {
+      node = parent;
+      i--;
+      parent = printStack[i];
+    } else {
+      return false;
+    }
+  }
+
+  return false;
+}
+
+/***/ }),
+
+/***/ 2371:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+exports.__esModule = true;
+
+var _templateLiterals = __webpack_require__(2372);
+
+Object.keys(_templateLiterals).forEach(function (key) {
+  if (key === "default" || key === "__esModule") return;
+  exports[key] = _templateLiterals[key];
+});
+
+var _expressions = __webpack_require__(2373);
+
+Object.keys(_expressions).forEach(function (key) {
+  if (key === "default" || key === "__esModule") return;
+  exports[key] = _expressions[key];
+});
+
+var _statements = __webpack_require__(2374);
+
+Object.keys(_statements).forEach(function (key) {
+  if (key === "default" || key === "__esModule") return;
+  exports[key] = _statements[key];
+});
+
+var _classes = __webpack_require__(2375);
+
+Object.keys(_classes).forEach(function (key) {
+  if (key === "default" || key === "__esModule") return;
+  exports[key] = _classes[key];
+});
+
+var _methods = __webpack_require__(2376);
+
+Object.keys(_methods).forEach(function (key) {
+  if (key === "default" || key === "__esModule") return;
+  exports[key] = _methods[key];
+});
+
+var _modules = __webpack_require__(2354);
+
+Object.keys(_modules).forEach(function (key) {
+  if (key === "default" || key === "__esModule") return;
+  exports[key] = _modules[key];
+});
+
+var _types = __webpack_require__(2347);
+
+Object.keys(_types).forEach(function (key) {
+  if (key === "default" || key === "__esModule") return;
+  exports[key] = _types[key];
+});
+
+var _flow = __webpack_require__(2378);
+
+Object.keys(_flow).forEach(function (key) {
+  if (key === "default" || key === "__esModule") return;
+  exports[key] = _flow[key];
+});
+
+var _base = __webpack_require__(2379);
+
+Object.keys(_base).forEach(function (key) {
+  if (key === "default" || key === "__esModule") return;
+  exports[key] = _base[key];
+});
+
+var _jsx = __webpack_require__(2380);
+
+Object.keys(_jsx).forEach(function (key) {
+  if (key === "default" || key === "__esModule") return;
+  exports[key] = _jsx[key];
+});
+
+var _typescript = __webpack_require__(2381);
+
+Object.keys(_typescript).forEach(function (key) {
+  if (key === "default" || key === "__esModule") return;
+  exports[key] = _typescript[key];
+});
+
+/***/ }),
+
+/***/ 2372:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+exports.__esModule = true;
+exports.TaggedTemplateExpression = TaggedTemplateExpression;
+exports.TemplateElement = TemplateElement;
+exports.TemplateLiteral = TemplateLiteral;
+
+function TaggedTemplateExpression(node) {
+  this.print(node.tag, node);
+  this.print(node.quasi, node);
+}
+
+function TemplateElement(node, parent) {
+  var isFirst = parent.quasis[0] === node;
+  var isLast = parent.quasis[parent.quasis.length - 1] === node;
+  var value = (isFirst ? "`" : "}") + node.value.raw + (isLast ? "`" : "${");
+  this.token(value);
+}
+
+function TemplateLiteral(node) {
+  var quasis = node.quasis;
+
+  for (var i = 0; i < quasis.length; i++) {
+    this.print(quasis[i], node);
+
+    if (i + 1 < quasis.length) {
+      this.print(node.expressions[i], node);
+    }
+  }
+}
+
+/***/ }),
+
+/***/ 2373:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+exports.__esModule = true;
+exports.UnaryExpression = UnaryExpression;
+exports.DoExpression = DoExpression;
+exports.ParenthesizedExpression = ParenthesizedExpression;
+exports.UpdateExpression = UpdateExpression;
+exports.ConditionalExpression = ConditionalExpression;
+exports.NewExpression = NewExpression;
+exports.SequenceExpression = SequenceExpression;
+exports.ThisExpression = ThisExpression;
+exports.Super = Super;
+exports.Decorator = Decorator;
+exports.OptionalMemberExpression = OptionalMemberExpression;
+exports.OptionalCallExpression = OptionalCallExpression;
+exports.CallExpression = CallExpression;
+exports.Import = Import;
+exports.EmptyStatement = EmptyStatement;
+exports.ExpressionStatement = ExpressionStatement;
+exports.AssignmentPattern = AssignmentPattern;
+exports.LogicalExpression = exports.BinaryExpression = exports.AssignmentExpression = AssignmentExpression;
+exports.BindExpression = BindExpression;
+exports.MemberExpression = MemberExpression;
+exports.MetaProperty = MetaProperty;
+exports.AwaitExpression = exports.YieldExpression = void 0;
+
+var t = _interopRequireWildcard(__webpack_require__(2268));
+
+var n = _interopRequireWildcard(__webpack_require__(2353));
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
+
+function UnaryExpression(node) {
+  if (node.operator === "void" || node.operator === "delete" || node.operator === "typeof") {
+    this.word(node.operator);
+    this.space();
+  } else {
+    this.token(node.operator);
+  }
+
+  this.print(node.argument, node);
+}
+
+function DoExpression(node) {
+  this.word("do");
+  this.space();
+  this.print(node.body, node);
+}
+
+function ParenthesizedExpression(node) {
+  this.token("(");
+  this.print(node.expression, node);
+  this.token(")");
+}
+
+function UpdateExpression(node) {
+  if (node.prefix) {
+    this.token(node.operator);
+    this.print(node.argument, node);
+  } else {
+    this.startTerminatorless(true);
+    this.print(node.argument, node);
+    this.endTerminatorless();
+    this.token(node.operator);
+  }
+}
+
+function ConditionalExpression(node) {
+  this.print(node.test, node);
+  this.space();
+  this.token("?");
+  this.space();
+  this.print(node.consequent, node);
+  this.space();
+  this.token(":");
+  this.space();
+  this.print(node.alternate, node);
+}
+
+function NewExpression(node, parent) {
+  this.word("new");
+  this.space();
+  this.print(node.callee, node);
+
+  if (this.format.minified && node.arguments.length === 0 && !node.optional && !t.isCallExpression(parent, {
+    callee: node
+  }) && !t.isMemberExpression(parent) && !t.isNewExpression(parent)) {
+    return;
+  }
+
+  this.print(node.typeParameters, node);
+
+  if (node.optional) {
+    this.token("?.");
+  }
+
+  this.token("(");
+  this.printList(node.arguments, node);
+  this.token(")");
+}
+
+function SequenceExpression(node) {
+  this.printList(node.expressions, node);
+}
+
+function ThisExpression() {
+  this.word("this");
+}
+
+function Super() {
+  this.word("super");
+}
+
+function Decorator(node) {
+  this.token("@");
+  this.print(node.expression, node);
+  this.newline();
+}
+
+function OptionalMemberExpression(node) {
+  this.print(node.object, node);
+
+  if (!node.computed && t.isMemberExpression(node.property)) {
+    throw new TypeError("Got a MemberExpression for MemberExpression property");
+  }
+
+  var computed = node.computed;
+
+  if (t.isLiteral(node.property) && typeof node.property.value === "number") {
+    computed = true;
+  }
+
+  if (node.optional) {
+    this.token("?.");
+  }
+
+  if (computed) {
+    this.token("[");
+    this.print(node.property, node);
+    this.token("]");
+  } else {
+    if (!node.optional) {
+      this.token(".");
+    }
+
+    this.print(node.property, node);
+  }
+}
+
+function OptionalCallExpression(node) {
+  this.print(node.callee, node);
+  this.print(node.typeParameters, node);
+
+  if (node.optional) {
+    this.token("?.");
+  }
+
+  this.token("(");
+  this.printList(node.arguments, node);
+  this.token(")");
+}
+
+function CallExpression(node) {
+  this.print(node.callee, node);
+  this.print(node.typeParameters, node);
+  this.token("(");
+  this.printList(node.arguments, node);
+  this.token(")");
+}
+
+function Import() {
+  this.word("import");
+}
+
+function buildYieldAwait(keyword) {
+  return function (node) {
+    this.word(keyword);
+
+    if (node.delegate) {
+      this.token("*");
+    }
+
+    if (node.argument) {
+      this.space();
+      var terminatorState = this.startTerminatorless();
+      this.print(node.argument, node);
+      this.endTerminatorless(terminatorState);
+    }
+  };
+}
+
+var YieldExpression = buildYieldAwait("yield");
+exports.YieldExpression = YieldExpression;
+var AwaitExpression = buildYieldAwait("await");
+exports.AwaitExpression = AwaitExpression;
+
+function EmptyStatement() {
+  this.semicolon(true);
+}
+
+function ExpressionStatement(node) {
+  this.print(node.expression, node);
+  this.semicolon();
+}
+
+function AssignmentPattern(node) {
+  this.print(node.left, node);
+  if (node.left.optional) this.token("?");
+  this.print(node.left.typeAnnotation, node);
+  this.space();
+  this.token("=");
+  this.space();
+  this.print(node.right, node);
+}
+
+function AssignmentExpression(node, parent) {
+  var parens = this.inForStatementInitCounter && node.operator === "in" && !n.needsParens(node, parent);
+
+  if (parens) {
+    this.token("(");
+  }
+
+  this.print(node.left, node);
+  this.space();
+
+  if (node.operator === "in" || node.operator === "instanceof") {
+    this.word(node.operator);
+  } else {
+    this.token(node.operator);
+  }
+
+  this.space();
+  this.print(node.right, node);
+
+  if (parens) {
+    this.token(")");
+  }
+}
+
+function BindExpression(node) {
+  this.print(node.object, node);
+  this.token("::");
+  this.print(node.callee, node);
+}
+
+function MemberExpression(node) {
+  this.print(node.object, node);
+
+  if (!node.computed && t.isMemberExpression(node.property)) {
+    throw new TypeError("Got a MemberExpression for MemberExpression property");
+  }
+
+  var computed = node.computed;
+
+  if (t.isLiteral(node.property) && typeof node.property.value === "number") {
+    computed = true;
+  }
+
+  if (computed) {
+    this.token("[");
+    this.print(node.property, node);
+    this.token("]");
+  } else {
+    this.token(".");
+    this.print(node.property, node);
+  }
+}
+
+function MetaProperty(node) {
+  this.print(node.meta, node);
+  this.token(".");
+  this.print(node.property, node);
+}
+
+/***/ }),
+
+/***/ 2374:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+exports.__esModule = true;
+exports.WithStatement = WithStatement;
+exports.IfStatement = IfStatement;
+exports.ForStatement = ForStatement;
+exports.WhileStatement = WhileStatement;
+exports.DoWhileStatement = DoWhileStatement;
+exports.LabeledStatement = LabeledStatement;
+exports.TryStatement = TryStatement;
+exports.CatchClause = CatchClause;
+exports.SwitchStatement = SwitchStatement;
+exports.SwitchCase = SwitchCase;
+exports.DebuggerStatement = DebuggerStatement;
+exports.VariableDeclaration = VariableDeclaration;
+exports.VariableDeclarator = VariableDeclarator;
+exports.ThrowStatement = exports.BreakStatement = exports.ReturnStatement = exports.ContinueStatement = exports.ForOfStatement = exports.ForInStatement = void 0;
+
+var t = _interopRequireWildcard(__webpack_require__(2268));
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
+
+function WithStatement(node) {
+  this.word("with");
+  this.space();
+  this.token("(");
+  this.print(node.object, node);
+  this.token(")");
+  this.printBlock(node);
+}
+
+function IfStatement(node) {
+  this.word("if");
+  this.space();
+  this.token("(");
+  this.print(node.test, node);
+  this.token(")");
+  this.space();
+  var needsBlock = node.alternate && t.isIfStatement(getLastStatement(node.consequent));
+
+  if (needsBlock) {
+    this.token("{");
+    this.newline();
+    this.indent();
+  }
+
+  this.printAndIndentOnComments(node.consequent, node);
+
+  if (needsBlock) {
+    this.dedent();
+    this.newline();
+    this.token("}");
+  }
+
+  if (node.alternate) {
+    if (this.endsWith("}")) this.space();
+    this.word("else");
+    this.space();
+    this.printAndIndentOnComments(node.alternate, node);
+  }
+}
+
+function getLastStatement(statement) {
+  if (!t.isStatement(statement.body)) return statement;
+  return getLastStatement(statement.body);
+}
+
+function ForStatement(node) {
+  this.word("for");
+  this.space();
+  this.token("(");
+  this.inForStatementInitCounter++;
+  this.print(node.init, node);
+  this.inForStatementInitCounter--;
+  this.token(";");
+
+  if (node.test) {
+    this.space();
+    this.print(node.test, node);
+  }
+
+  this.token(";");
+
+  if (node.update) {
+    this.space();
+    this.print(node.update, node);
+  }
+
+  this.token(")");
+  this.printBlock(node);
+}
+
+function WhileStatement(node) {
+  this.word("while");
+  this.space();
+  this.token("(");
+  this.print(node.test, node);
+  this.token(")");
+  this.printBlock(node);
+}
+
+var buildForXStatement = function buildForXStatement(op) {
+  return function (node) {
+    this.word("for");
+    this.space();
+
+    if (op === "of" && node.await) {
+      this.word("await");
+      this.space();
+    }
+
+    this.token("(");
+    this.print(node.left, node);
+    this.space();
+    this.word(op);
+    this.space();
+    this.print(node.right, node);
+    this.token(")");
+    this.printBlock(node);
+  };
+};
+
+var ForInStatement = buildForXStatement("in");
+exports.ForInStatement = ForInStatement;
+var ForOfStatement = buildForXStatement("of");
+exports.ForOfStatement = ForOfStatement;
+
+function DoWhileStatement(node) {
+  this.word("do");
+  this.space();
+  this.print(node.body, node);
+  this.space();
+  this.word("while");
+  this.space();
+  this.token("(");
+  this.print(node.test, node);
+  this.token(")");
+  this.semicolon();
+}
+
+function buildLabelStatement(prefix, key) {
+  if (key === void 0) {
+    key = "label";
+  }
+
+  return function (node) {
+    this.word(prefix);
+    var label = node[key];
+
+    if (label) {
+      this.space();
+      var isLabel = key == "label";
+      var terminatorState = this.startTerminatorless(isLabel);
+      this.print(label, node);
+      this.endTerminatorless(terminatorState);
+    }
+
+    this.semicolon();
+  };
+}
+
+var ContinueStatement = buildLabelStatement("continue");
+exports.ContinueStatement = ContinueStatement;
+var ReturnStatement = buildLabelStatement("return", "argument");
+exports.ReturnStatement = ReturnStatement;
+var BreakStatement = buildLabelStatement("break");
+exports.BreakStatement = BreakStatement;
+var ThrowStatement = buildLabelStatement("throw", "argument");
+exports.ThrowStatement = ThrowStatement;
+
+function LabeledStatement(node) {
+  this.print(node.label, node);
+  this.token(":");
+  this.space();
+  this.print(node.body, node);
+}
+
+function TryStatement(node) {
+  this.word("try");
+  this.space();
+  this.print(node.block, node);
+  this.space();
+
+  if (node.handlers) {
+    this.print(node.handlers[0], node);
+  } else {
+    this.print(node.handler, node);
+  }
+
+  if (node.finalizer) {
+    this.space();
+    this.word("finally");
+    this.space();
+    this.print(node.finalizer, node);
+  }
+}
+
+function CatchClause(node) {
+  this.word("catch");
+  this.space();
+
+  if (node.param) {
+    this.token("(");
+    this.print(node.param, node);
+    this.token(")");
+    this.space();
+  }
+
+  this.print(node.body, node);
+}
+
+function SwitchStatement(node) {
+  this.word("switch");
+  this.space();
+  this.token("(");
+  this.print(node.discriminant, node);
+  this.token(")");
+  this.space();
+  this.token("{");
+  this.printSequence(node.cases, node, {
+    indent: true,
+    addNewlines: function addNewlines(leading, cas) {
+      if (!leading && node.cases[node.cases.length - 1] === cas) return -1;
+    }
+  });
+  this.token("}");
+}
+
+function SwitchCase(node) {
+  if (node.test) {
+    this.word("case");
+    this.space();
+    this.print(node.test, node);
+    this.token(":");
+  } else {
+    this.word("default");
+    this.token(":");
+  }
+
+  if (node.consequent.length) {
+    this.newline();
+    this.printSequence(node.consequent, node, {
+      indent: true
+    });
+  }
+}
+
+function DebuggerStatement() {
+  this.word("debugger");
+  this.semicolon();
+}
+
+function variableDeclarationIndent() {
+  this.token(",");
+  this.newline();
+  if (this.endsWith("\n")) for (var i = 0; i < 4; i++) {
+    this.space(true);
+  }
+}
+
+function constDeclarationIndent() {
+  this.token(",");
+  this.newline();
+  if (this.endsWith("\n")) for (var i = 0; i < 6; i++) {
+    this.space(true);
+  }
+}
+
+function VariableDeclaration(node, parent) {
+  if (node.declare) {
+    this.word("declare");
+    this.space();
+  }
+
+  this.word(node.kind);
+  this.space();
+  var hasInits = false;
+
+  if (!t.isFor(parent)) {
+    var _arr = node.declarations;
+
+    for (var _i = 0; _i < _arr.length; _i++) {
+      var declar = _arr[_i];
+
+      if (declar.init) {
+        hasInits = true;
+      }
+    }
+  }
+
+  var separator;
+
+  if (hasInits) {
+    separator = node.kind === "const" ? constDeclarationIndent : variableDeclarationIndent;
+  }
+
+  this.printList(node.declarations, node, {
+    separator: separator
+  });
+
+  if (t.isFor(parent)) {
+    if (parent.left === node || parent.init === node) return;
+  }
+
+  this.semicolon();
+}
+
+function VariableDeclarator(node) {
+  this.print(node.id, node);
+  if (node.definite) this.token("!");
+  this.print(node.id.typeAnnotation, node);
+
+  if (node.init) {
+    this.space();
+    this.token("=");
+    this.space();
+    this.print(node.init, node);
+  }
+}
+
+/***/ }),
+
+/***/ 2375:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+exports.__esModule = true;
+exports.ClassExpression = exports.ClassDeclaration = ClassDeclaration;
+exports.ClassBody = ClassBody;
+exports.ClassProperty = ClassProperty;
+exports.ClassMethod = ClassMethod;
+exports._classMethodHead = _classMethodHead;
+
+var t = _interopRequireWildcard(__webpack_require__(2268));
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
+
+function ClassDeclaration(node, parent) {
+  if (!t.isExportDefaultDeclaration(parent) && !t.isExportNamedDeclaration(parent)) {
+    this.printJoin(node.decorators, node);
+  }
+
+  if (node.declare) {
+    this.word("declare");
+    this.space();
+  }
+
+  if (node.abstract) {
+    this.word("abstract");
+    this.space();
+  }
+
+  this.word("class");
+
+  if (node.id) {
+    this.space();
+    this.print(node.id, node);
+  }
+
+  this.print(node.typeParameters, node);
+
+  if (node.superClass) {
+    this.space();
+    this.word("extends");
+    this.space();
+    this.print(node.superClass, node);
+    this.print(node.superTypeParameters, node);
+  }
+
+  if (node.implements) {
+    this.space();
+    this.word("implements");
+    this.space();
+    this.printList(node.implements, node);
+  }
+
+  this.space();
+  this.print(node.body, node);
+}
+
+function ClassBody(node) {
+  this.token("{");
+  this.printInnerComments(node);
+
+  if (node.body.length === 0) {
+    this.token("}");
+  } else {
+    this.newline();
+    this.indent();
+    this.printSequence(node.body, node);
+    this.dedent();
+    if (!this.endsWith("\n")) this.newline();
+    this.rightBrace();
+  }
+}
+
+function ClassProperty(node) {
+  this.printJoin(node.decorators, node);
+
+  if (node.accessibility) {
+    this.word(node.accessibility);
+    this.space();
+  }
+
+  if (node.static) {
+    this.word("static");
+    this.space();
+  }
+
+  if (node.abstract) {
+    this.word("abstract");
+    this.space();
+  }
+
+  if (node.readonly) {
+    this.word("readonly");
+    this.space();
+  }
+
+  if (node.computed) {
+    this.token("[");
+    this.print(node.key, node);
+    this.token("]");
+  } else {
+    this._variance(node);
+
+    this.print(node.key, node);
+  }
+
+  if (node.optional) {
+    this.token("?");
+  }
+
+  if (node.definite) {
+    this.token("!");
+  }
+
+  this.print(node.typeAnnotation, node);
+
+  if (node.value) {
+    this.space();
+    this.token("=");
+    this.space();
+    this.print(node.value, node);
+  }
+
+  this.semicolon();
+}
+
+function ClassMethod(node) {
+  this._classMethodHead(node);
+
+  this.space();
+  this.print(node.body, node);
+}
+
+function _classMethodHead(node) {
+  this.printJoin(node.decorators, node);
+
+  if (node.accessibility) {
+    this.word(node.accessibility);
+    this.space();
+  }
+
+  if (node.abstract) {
+    this.word("abstract");
+    this.space();
+  }
+
+  if (node.static) {
+    this.word("static");
+    this.space();
+  }
+
+  this._methodHead(node);
+}
+
+/***/ }),
+
+/***/ 2376:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+exports.__esModule = true;
+exports._params = _params;
+exports._parameters = _parameters;
+exports._param = _param;
+exports._methodHead = _methodHead;
+exports._predicate = _predicate;
+exports._functionHead = _functionHead;
+exports.FunctionDeclaration = exports.FunctionExpression = FunctionExpression;
+exports.ArrowFunctionExpression = ArrowFunctionExpression;
+
+var t = _interopRequireWildcard(__webpack_require__(2268));
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
+
+function _params(node) {
+  this.print(node.typeParameters, node);
+  this.token("(");
+
+  this._parameters(node.params, node);
+
+  this.token(")");
+  this.print(node.returnType, node);
+}
+
+function _parameters(parameters, parent) {
+  for (var i = 0; i < parameters.length; i++) {
+    this._param(parameters[i], parent);
+
+    if (i < parameters.length - 1) {
+      this.token(",");
+      this.space();
+    }
+  }
+}
+
+function _param(parameter, parent) {
+  this.printJoin(parameter.decorators, parameter);
+  this.print(parameter, parent);
+  if (parameter.optional) this.token("?");
+  this.print(parameter.typeAnnotation, parameter);
+}
+
+function _methodHead(node) {
+  var kind = node.kind;
+  var key = node.key;
+
+  if (kind === "get" || kind === "set") {
+    this.word(kind);
+    this.space();
+  }
+
+  if (node.async) {
+    this.word("async");
+    this.space();
+  }
+
+  if (kind === "method" || kind === "init") {
+    if (node.generator) {
+      this.token("*");
+    }
+  }
+
+  if (node.computed) {
+    this.token("[");
+    this.print(key, node);
+    this.token("]");
+  } else {
+    this.print(key, node);
+  }
+
+  if (node.optional) {
+    this.token("?");
+  }
+
+  this._params(node);
+}
+
+function _predicate(node) {
+  if (node.predicate) {
+    if (!node.returnType) {
+      this.token(":");
+    }
+
+    this.space();
+    this.print(node.predicate, node);
+  }
+}
+
+function _functionHead(node) {
+  if (node.async) {
+    this.word("async");
+    this.space();
+  }
+
+  this.word("function");
+  if (node.generator) this.token("*");
+  this.space();
+
+  if (node.id) {
+    this.print(node.id, node);
+  }
+
+  this._params(node);
+
+  this._predicate(node);
+}
+
+function FunctionExpression(node) {
+  this._functionHead(node);
+
+  this.space();
+  this.print(node.body, node);
+}
+
+function ArrowFunctionExpression(node) {
+  if (node.async) {
+    this.word("async");
+    this.space();
+  }
+
+  var firstParam = node.params[0];
+
+  if (node.params.length === 1 && t.isIdentifier(firstParam) && !hasTypes(node, firstParam)) {
+    this.print(firstParam, node);
+  } else {
+    this._params(node);
+  }
+
+  this._predicate(node);
+
+  this.space();
+  this.token("=>");
+  this.space();
+  this.print(node.body, node);
+}
+
+function hasTypes(node, param) {
+  return node.typeParameters || node.returnType || param.typeAnnotation || param.optional || param.trailingComments;
+}
+
+/***/ }),
+
+/***/ 2377:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+/* WEBPACK VAR INJECTION */(function(Buffer) {
+
+const object = {};
+const hasOwnProperty = object.hasOwnProperty;
+const forOwn = (object, callback) => {
+	for (const key in object) {
+		if (hasOwnProperty.call(object, key)) {
+			callback(key, object[key]);
+		}
+	}
+};
+
+const extend = (destination, source) => {
+	if (!source) {
+		return destination;
+	}
+	forOwn(source, (key, value) => {
+		destination[key] = value;
+	});
+	return destination;
+};
+
+const forEach = (array, callback) => {
+	const length = array.length;
+	let index = -1;
+	while (++index < length) {
+		callback(array[index]);
+	}
+};
+
+const toString = object.toString;
+const isArray = Array.isArray;
+const isBuffer = Buffer.isBuffer;
+const isObject = (value) => {
+	// This is a very simple check, but it’s good enough for what we need.
+	return toString.call(value) == '[object Object]';
+};
+const isString = (value) => {
+	return typeof value == 'string' ||
+		toString.call(value) == '[object String]';
+};
+const isNumber = (value) => {
+	return typeof value == 'number' ||
+		toString.call(value) == '[object Number]';
+};
+const isFunction = (value) => {
+	return typeof value == 'function';
+};
+const isMap = (value) => {
+	return toString.call(value) == '[object Map]';
+};
+const isSet = (value) => {
+	return toString.call(value) == '[object Set]';
+};
+
+/*--------------------------------------------------------------------------*/
+
+// https://mathiasbynens.be/notes/javascript-escapes#single
+const singleEscapes = {
+	'"': '\\"',
+	'\'': '\\\'',
+	'\\': '\\\\',
+	'\b': '\\b',
+	'\f': '\\f',
+	'\n': '\\n',
+	'\r': '\\r',
+	'\t': '\\t'
+	// `\v` is omitted intentionally, because in IE < 9, '\v' == 'v'.
+	// '\v': '\\x0B'
+};
+const regexSingleEscape = /["'\\\b\f\n\r\t]/;
+
+const regexDigit = /[0-9]/;
+const regexWhitelist = /[ !#-&\(-\[\]-~]/;
+
+const jsesc = (argument, options) => {
+	const increaseIndentation = () => {
+		oldIndent = indent;
+		++options.indentLevel;
+		indent = options.indent.repeat(options.indentLevel)
+	};
+	// Handle options
+	const defaults = {
+		'escapeEverything': false,
+		'minimal': false,
+		'isScriptContext': false,
+		'quotes': 'single',
+		'wrap': false,
+		'es6': false,
+		'json': false,
+		'compact': true,
+		'lowercaseHex': false,
+		'numbers': 'decimal',
+		'indent': '\t',
+		'indentLevel': 0,
+		'__inline1__': false,
+		'__inline2__': false
+	};
+	const json = options && options.json;
+	if (json) {
+		defaults.quotes = 'double';
+		defaults.wrap = true;
+	}
+	options = extend(defaults, options);
+	if (
+		options.quotes != 'single' &&
+		options.quotes != 'double' &&
+		options.quotes != 'backtick'
+	) {
+		options.quotes = 'single';
+	}
+	const quote = options.quotes == 'double' ?
+		'"' :
+		(options.quotes == 'backtick' ?
+			'`' :
+			'\''
+		);
+	const compact = options.compact;
+	const lowercaseHex = options.lowercaseHex;
+	let indent = options.indent.repeat(options.indentLevel);
+	let oldIndent = '';
+	const inline1 = options.__inline1__;
+	const inline2 = options.__inline2__;
+	const newLine = compact ? '' : '\n';
+	let result;
+	let isEmpty = true;
+	const useBinNumbers = options.numbers == 'binary';
+	const useOctNumbers = options.numbers == 'octal';
+	const useDecNumbers = options.numbers == 'decimal';
+	const useHexNumbers = options.numbers == 'hexadecimal';
+
+	if (json && argument && isFunction(argument.toJSON)) {
+		argument = argument.toJSON();
+	}
+
+	if (!isString(argument)) {
+		if (isMap(argument)) {
+			if (argument.size == 0) {
+				return 'new Map()';
+			}
+			if (!compact) {
+				options.__inline1__ = true;
+				options.__inline2__ = false;
+			}
+			return 'new Map(' + jsesc(Array.from(argument), options) + ')';
+		}
+		if (isSet(argument)) {
+			if (argument.size == 0) {
+				return 'new Set()';
+			}
+			return 'new Set(' + jsesc(Array.from(argument), options) + ')';
+		}
+		if (isBuffer(argument)) {
+			if (argument.length == 0) {
+				return 'Buffer.from([])';
+			}
+			return 'Buffer.from(' + jsesc(Array.from(argument), options) + ')';
+		}
+		if (isArray(argument)) {
+			result = [];
+			options.wrap = true;
+			if (inline1) {
+				options.__inline1__ = false;
+				options.__inline2__ = true;
+			}
+			if (!inline2) {
+				increaseIndentation();
+			}
+			forEach(argument, (value) => {
+				isEmpty = false;
+				if (inline2) {
+					options.__inline2__ = false;
+				}
+				result.push(
+					(compact || inline2 ? '' : indent) +
+					jsesc(value, options)
+				);
+			});
+			if (isEmpty) {
+				return '[]';
+			}
+			if (inline2) {
+				return '[' + result.join(', ') + ']';
+			}
+			return '[' + newLine + result.join(',' + newLine) + newLine +
+				(compact ? '' : oldIndent) + ']';
+		} else if (isNumber(argument)) {
+			if (json) {
+				// Some number values (e.g. `Infinity`) cannot be represented in JSON.
+				return JSON.stringify(argument);
+			}
+			if (useDecNumbers) {
+				return String(argument);
+			}
+			if (useHexNumbers) {
+				let hexadecimal = argument.toString(16);
+				if (!lowercaseHex) {
+					hexadecimal = hexadecimal.toUpperCase();
+				}
+				return '0x' + hexadecimal;
+			}