Merge m-i to m-c, a=merge
authorPhil Ringnalda <philringnalda@gmail.com>
Sat, 21 Jan 2017 15:24:42 -0800
changeset 375554 d5343b0f7e6a9619dfdf333d259cff6b4f773bff
parent 375485 160914d65dac284bba2646f52a1ce1a5aa2d22b1 (current diff)
parent 375553 26366617b865bd2caca18b060695ffaf9b5b414d (diff)
child 375556 5f0652e323af9ec2e3768fefca22f7a65449313c
child 375557 7a28f51037094413286d828c1952af57d1a59322
push id6996
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 20:48:21 +0000
treeherdermozilla-beta@d89512dab048 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone53.0a1
first release with
nightly mac
d5343b0f7e6a / 53.0a1 / 20170122030212 / files
nightly win32
d5343b0f7e6a / 53.0a1 / 20170122030212 / files
nightly win64
d5343b0f7e6a / 53.0a1 / 20170122030212 / files
nightly linux32
nightly linux64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly mac
nightly win32
nightly win64
Merge m-i to m-c, a=merge
browser/modules/ExtensionsUI.jsm
devtools/client/debugger/new/test/mochitest/examples/bundle.js
devtools/client/debugger/new/test/mochitest/examples/bundle.js.map
modules/libpref/init/all.js
security/nss/fuzz/nssfuzz.cc
security/nss/fuzz/quickder_targets.cc
security/nss/fuzz/registry.h
security/nss/gtests/common/common.gyp
security/nss/lib/freebl/ecl/tests/ec_naft.c
security/nss/lib/freebl/ecl/tests/ecp_test.c
security/nss/lib/freebl/os2_rand.c
tools/profiler/public/GeckoProfilerFunc.h
tools/profiler/public/GeckoProfilerImpl.h
tools/profiler/public/GeckoProfilerTypes.h
--- a/accessible/tests/mochitest/events.js
+++ b/accessible/tests/mochitest/events.js
@@ -1766,16 +1766,29 @@ function nofocusChecker(aID)
 function textChangeChecker(aID, aStart, aEnd, aTextOrFunc, aIsInserted, aFromUser)
 {
   this.target = getNode(aID);
   this.type = aIsInserted ? EVENT_TEXT_INSERTED : EVENT_TEXT_REMOVED;
   this.startOffset = aStart;
   this.endOffset = aEnd;
   this.textOrFunc = aTextOrFunc;
 
+  this.match = function stextChangeChecker_match(aEvent)
+  {
+    if (!(aEvent instanceof nsIAccessibleTextChangeEvent) ||
+        aEvent.accessible !== getAccessible(this.target)) {
+      return false;
+    }
+
+    let tcEvent = aEvent.QueryInterface(nsIAccessibleTextChangeEvent);
+    let modifiedText = (typeof this.textOrFunc === "function") ?
+      this.textOrFunc() : this.textOrFunc;
+    return modifiedText === tcEvent.modifiedText;
+  };
+
   this.check = function textChangeChecker_check(aEvent)
   {
     aEvent.QueryInterface(nsIAccessibleTextChangeEvent);
 
     var modifiedText = (typeof this.textOrFunc == "function") ?
       this.textOrFunc() : this.textOrFunc;
     var modifiedTextLen =
       (this.endOffset == -1) ? modifiedText.length : aEnd - aStart;
--- a/browser/base/content/aboutNetError.xhtml
+++ b/browser/base/content/aboutNetError.xhtml
@@ -590,17 +590,17 @@
 
         <!-- Short Description -->
         <div id="errorShortDesc">
           <p id="errorShortDescText" />
         </div>
         <p id="badStsCertExplanation" hidden="true">&certerror.whatShouldIDo.badStsCertExplanation;</p>
 
         <div id="wrongSystemTimePanel" style="display: none;">
-          &certerror.wrongSystemTime;
+          &certerror.wrongSystemTime2;
         </div>
 
         <div id="wrongSystemTimeWithoutReferencePanel" style="display: none;">
           &certerror.wrongSystemTimeWithoutReference;
         </div>
 
         <!-- Long Description (Note: See netError.dtd for used XHTML tags) -->
         <div id="errorLongDesc" />
--- a/browser/base/content/test/chrome/test_aboutCrashed.xul
+++ b/browser/base/content/test/chrome/test_aboutCrashed.xul
@@ -11,76 +11,72 @@
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
   <iframe type="content" id="frame1"/>
   <iframe type="content" id="frame2" onload="doTest()"/>
   <script type="application/javascript"><![CDATA[
     const Ci = Components.interfaces;
     const Cu = Components.utils;
 
     Cu.import("resource://gre/modules/Services.jsm");
-    Cu.import("resource://gre/modules/Task.jsm");
-    Cu.import("resource://gre/modules/Promise.jsm");
     Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
     SimpleTest.waitForExplicitFinish();
 
     // Load error pages do not fire "load" events, so let's use a progressListener.
     function waitForErrorPage(frame) {
-      let errorPageDeferred = Promise.defer();
-
-      let progressListener = {
-        onLocationChange: function(aWebProgress, aRequest, aLocation, aFlags) {
-          if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) {
-            frame.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
-                          .getInterface(Ci.nsIWebProgress)
-                          .removeProgressListener(progressListener,
-                                                  Ci.nsIWebProgress.NOTIFY_LOCATION);
+      return new Promise(resolve => {
+        let progressListener = {
+          onLocationChange: function(aWebProgress, aRequest, aLocation, aFlags) {
+            if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) {
+              frame.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+                            .getInterface(Ci.nsIWebProgress)
+                            .removeProgressListener(progressListener,
+                                                    Ci.nsIWebProgress.NOTIFY_LOCATION);
 
-            errorPageDeferred.resolve();
-          }
-        },
+              resolve();
+            }
+          },
 
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
-                                               Ci.nsISupportsWeakReference])
-      };
+          QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
+                                                 Ci.nsISupportsWeakReference])
+        };
 
-      frame.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIWebProgress)
-                    .addProgressListener(progressListener,
-                                         Ci.nsIWebProgress.NOTIFY_LOCATION);
-
-      return errorPageDeferred.promise;
+        frame.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+                      .getInterface(Ci.nsIWebProgress)
+                      .addProgressListener(progressListener,
+                                           Ci.nsIWebProgress.NOTIFY_LOCATION);
+      });
     }
 
   function doTest() {
-    Task.spawn(function test_aboutCrashed() {
+    (async function testBody() {
       let frame1 = document.getElementById("frame1");
       let frame2 = document.getElementById("frame2");
       let uri1 = Services.io.newURI("http://www.example.com/1", null, null);
       let uri2 = Services.io.newURI("http://www.example.com/2", null, null);
 
       let errorPageReady = waitForErrorPage(frame1);
       frame1.docShell.chromeEventHandler.setAttribute("crashedPageTitle", "pageTitle");
       frame1.docShell.displayLoadError(Components.results.NS_ERROR_CONTENT_CRASHED, uri1, null);
 
-      yield errorPageReady;
+      await errorPageReady;
       frame1.docShell.chromeEventHandler.removeAttribute("crashedPageTitle");
 
       SimpleTest.is(frame1.contentDocument.documentURI,
                     "about:tabcrashed?e=tabcrashed&u=http%3A//www.example.com/1&c=UTF-8&f=regular&d=pageTitle",
                     "Correct about:tabcrashed displayed for page with title.");
 
       errorPageReady = waitForErrorPage(frame2);
       frame2.docShell.displayLoadError(Components.results.NS_ERROR_CONTENT_CRASHED, uri2, null);
 
-      yield errorPageReady;
+      await errorPageReady;
 
       SimpleTest.is(frame2.contentDocument.documentURI,
                     "about:tabcrashed?e=tabcrashed&u=http%3A//www.example.com/2&c=UTF-8&f=regular&d=%20",
                     "Correct about:tabcrashed displayed for page with no title.");
 
       SimpleTest.finish();
-  });
+    })().catch(ex => SimpleTest.ok(false, ex));
   }
   ]]></script>
 
   <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;" />
 </window>
--- a/browser/base/content/test/general/browser_misused_characters_in_strings.js
+++ b/browser/base/content/test/general/browser_misused_characters_in_strings.js
@@ -25,17 +25,17 @@ let gWhitelist = [{
     key: "weakCryptoAdvanced.override",
     type: "single-quote"
   }, {
     file: "netError.dtd",
     key: "inadequateSecurityError.longDesc",
     type: "single-quote"
   }, {
     file: "netError.dtd",
-    key: "certerror.wrongSystemTime",
+    key: "certerror.wrongSystemTime2",
     type: "single-quote"
   }, {
     file: "netError.dtd",
     key: "certerror.wrongSystemTimeWithoutReference",
     type: "single-quote"
   }, {
     file: "phishing-afterload-warning-message.dtd",
     key: "safeb.blocked.malwarePage.shortDesc",
--- a/browser/base/content/test/popupNotifications/browser_popupNotification_5.js
+++ b/browser/base/content/test/popupNotifications/browser_popupNotification_5.js
@@ -174,41 +174,55 @@ var tests = [
     }
   },
   // Test that persistent panels are still open after switching to another
   // window and back.
   { id: "Test#7",
     *run() {
       this.oldSelectedTab = gBrowser.selectedTab;
       yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
+      let firstTab = gBrowser.selectedTab;
+
+      yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
 
       let shown = waitForNotificationPanel();
       let notifyObj = new BasicNotification(this.id);
       notifyObj.options.persistent = true;
       this.notification = showNotification(notifyObj);
       yield shown;
 
-      ok(notifyObj.shownCallbackTriggered, "Should have triggered the shown callback");
+      ok(notifyObj.shownCallbackTriggered, "Should have triggered the shown event");
+      ok(notifyObj.showingCallbackTriggered, "Should have triggered the showing event");
+      // Reset to false so that we can ensure these are not fired a second time.
+      notifyObj.shownCallbackTriggered = false;
+      notifyObj.showingCallbackTriggered = false;
 
-      yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
       let promiseWin = BrowserTestUtils.waitForNewWindow();
-      gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
+      gBrowser.replaceTabWithWindow(firstTab);
       let win = yield promiseWin;
 
       let anchor = win.document.getElementById("default-notification-icon");
       win.PopupNotifications._reshowNotifications(anchor);
       ok(win.PopupNotifications.panel.childNodes.length == 0,
          "no notification displayed in new window");
 
       yield BrowserTestUtils.closeWindow(win);
       yield waitForWindowReadyForPopupNotifications(window);
 
       let id = PopupNotifications.panel.firstChild.getAttribute("popupid");
       ok(id.endsWith("Test#7"), "Should have found the notification from Test7");
-      ok(PopupNotifications.isPanelOpen, "Should have shown the popup again after getting back to the window");
+      ok(PopupNotifications.isPanelOpen,
+         "Should have kept the popup on the first window");
+      ok(!notifyObj.dismissalCallbackTriggered,
+         "Should not have triggered a dismissed event");
+      ok(!notifyObj.shownCallbackTriggered,
+         "Should not have triggered a second shown event");
+      ok(!notifyObj.showingCallbackTriggered,
+         "Should not have triggered a second showing event");
+
       this.notification.remove();
       gBrowser.removeTab(gBrowser.selectedTab);
       gBrowser.selectedTab = this.oldSelectedTab;
 
       goNext();
     }
   },
   // Test that only the first persistent notification is shown on update
--- a/browser/components/downloads/test/browser/browser_libraryDrop.js
+++ b/browser/components/downloads/test/browser/browser_libraryDrop.js
@@ -12,27 +12,27 @@ registerCleanupFunction(function*() {
 });
 
 add_task(function* test_indicatorDrop() {
   let scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
       getService(Ci.mozIJSSubScriptLoader);
   let EventUtils = {};
   scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/EventUtils.js", EventUtils);
 
-  function task_drop(win, urls) {
+  async function drop(win, urls) {
     let dragData = [[{type: "text/plain", data: urls.join("\n")}]];
 
     let listBox = win.document.getElementById("downloadsRichListBox");
     ok(listBox, "download list box present");
 
-    let list = yield Downloads.getList(Downloads.ALL);
+    let list = await Downloads.getList(Downloads.ALL);
 
     let added = new Set();
     let succeeded = new Set();
-    yield new Promise(function(resolve) {
+    await new Promise(resolve => {
       let view = {
         onDownloadAdded: function(download) {
           added.add(download.source.url);
         },
         onDownloadChanged: function(download) {
           if (!added.has(download.source.url))
             return;
           if (!download.succeeded)
@@ -60,13 +60,13 @@ add_task(function* test_indicatorDrop() 
 
   startServer();
 
   let win = yield openLibrary("Downloads");
   registerCleanupFunction(function() {
     win.close();
   });
 
-  yield* task_drop(win, [httpUrl("file1.txt")]);
-  yield* task_drop(win, [httpUrl("file1.txt"),
-                         httpUrl("file2.txt"),
-                         httpUrl("file3.txt")]);
+  yield drop(win, [httpUrl("file1.txt")]);
+  yield drop(win, [httpUrl("file1.txt"),
+                   httpUrl("file2.txt"),
+                   httpUrl("file3.txt")]);
 });
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_DownloadLastDirWithCPS.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_DownloadLastDirWithCPS.js
@@ -2,63 +2,50 @@
 /* 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/. */
 
 var gTests;
 function test() {
   waitForExplicitFinish();
   requestLongerTimeout(2);
-  gTests = runTest();
-  gTests.next();
+  runTest().catch(ex => ok(false, ex));
 }
 
 /*
  * ================
  * Helper functions
  * ================
  */
 
-function moveAlong(aResult) {
-  try {
-    gTests.send(aResult);
-  } catch (x if x instanceof StopIteration) {
-    finish();
-  }
-}
-
 function createWindow(aOptions) {
-  whenNewWindowLoaded(aOptions, function(win) {
-    moveAlong(win);
-  });
+  return new Promise(resolve => whenNewWindowLoaded(aOptions, resolve));
 }
 
 function getFile(downloadLastDir, aURI) {
-  downloadLastDir.getFileAsync(aURI, function(result) {
-    moveAlong(result);
-  });
+  return new Promise(resolve => downloadLastDir.getFileAsync(aURI, resolve));
 }
 
 function setFile(downloadLastDir, aURI, aValue) {
   downloadLastDir.setFile(aURI, aValue);
-  executeSoon(moveAlong);
+  return new Promise(resolve => executeSoon(resolve));
 }
 
 function clearHistoryAndWait() {
   clearHistory();
-  executeSoon(() => executeSoon(moveAlong));
+  return new Promise(resolve => executeSoon(_ => executeSoon(resolve)));
 }
 
 /*
  * ===================
  * Function with tests
  * ===================
  */
 
-function runTest() {
+async function runTest() {
   let FileUtils =
     Cu.import("resource://gre/modules/FileUtils.jsm", {}).FileUtils;
   let DownloadLastDir =
     Cu.import("resource://gre/modules/DownloadLastDir.jsm", {}).DownloadLastDir;
 
   let tmpDir = FileUtils.getDir("TmpD", [], true);
   let dir1 = newDirectory();
   let dir2 = newDirectory();
@@ -76,207 +63,209 @@ function runTest() {
     [dir1, dir2, dir3].forEach(dir => dir.remove(true));
     win.close();
     pbWin.close();
   });
 
   function checkDownloadLastDir(gDownloadLastDir, aLastDir) {
     is(gDownloadLastDir.file.path, aLastDir.path,
        "gDownloadLastDir should point to the expected last directory");
-    getFile(gDownloadLastDir, uri1);
+    return getFile(gDownloadLastDir, uri1);
   }
 
   function checkDownloadLastDirNull(gDownloadLastDir) {
     is(gDownloadLastDir.file, null, "gDownloadLastDir should be null");
-    getFile(gDownloadLastDir, uri1);
+    return getFile(gDownloadLastDir, uri1);
   }
 
   /*
    * ================================
    * Create a regular and a PB window
    * ================================
    */
 
-  let win = yield createWindow({private: false});
-  let pbWin = yield createWindow({private: true});
+  let win = await createWindow({private: false});
+  let pbWin = await createWindow({private: true});
 
   let downloadLastDir = new DownloadLastDir(win);
   let pbDownloadLastDir = new DownloadLastDir(pbWin);
 
   /*
    * ==================
    * Beginning of tests
    * ==================
    */
 
   is(typeof downloadLastDir, "object",
      "downloadLastDir should be a valid object");
   is(downloadLastDir.file, null,
      "LastDir pref should be null to start with");
 
   // set up last dir
-  yield setFile(downloadLastDir, null, tmpDir);
+  await setFile(downloadLastDir, null, tmpDir);
   is(downloadLastDir.file.path, tmpDir.path,
      "LastDir should point to the tmpDir");
   isnot(downloadLastDir.file, tmpDir,
         "downloadLastDir.file should not be pointing to tmpDir");
 
   // set uri1 to dir1, all should now return dir1
   // also check that a new object is returned
-  yield setFile(downloadLastDir, uri1, dir1);
+  await setFile(downloadLastDir, uri1, dir1);
   is(downloadLastDir.file.path, dir1.path,
      "downloadLastDir should return dir1");
   isnot(downloadLastDir.file, dir1,
         "downloadLastDir.file should not return dir1");
-  is((yield getFile(downloadLastDir, uri1)).path, dir1.path,
+  is((await getFile(downloadLastDir, uri1)).path, dir1.path,
      "uri1 should return dir1"); // set in CPS
-  isnot((yield getFile(downloadLastDir, uri1)), dir1,
+  isnot((await getFile(downloadLastDir, uri1)), dir1,
         "getFile on uri1 should not return dir1");
-  is((yield getFile(downloadLastDir, uri2)).path, dir1.path,
+  is((await getFile(downloadLastDir, uri2)).path, dir1.path,
      "uri2 should return dir1"); // fallback
-  isnot((yield getFile(downloadLastDir, uri2)), dir1,
+  isnot((await getFile(downloadLastDir, uri2)), dir1,
         "getFile on uri2 should not return dir1");
-  is((yield getFile(downloadLastDir, uri3)).path, dir1.path,
+  is((await getFile(downloadLastDir, uri3)).path, dir1.path,
      "uri3 should return dir1"); // fallback
-  isnot((yield getFile(downloadLastDir, uri3)), dir1,
+  isnot((await getFile(downloadLastDir, uri3)), dir1,
         "getFile on uri3 should not return dir1");
-  is((yield getFile(downloadLastDir, uri4)).path, dir1.path,
+  is((await getFile(downloadLastDir, uri4)).path, dir1.path,
      "uri4 should return dir1"); // fallback
-  isnot((yield getFile(downloadLastDir, uri4)), dir1,
+  isnot((await getFile(downloadLastDir, uri4)), dir1,
         "getFile on uri4 should not return dir1");
 
   // set uri2 to dir2, all except uri1 should now return dir2
-  yield setFile(downloadLastDir, uri2, dir2);
+  await setFile(downloadLastDir, uri2, dir2);
   is(downloadLastDir.file.path, dir2.path,
      "downloadLastDir should point to dir2");
-  is((yield getFile(downloadLastDir, uri1)).path, dir1.path,
+  is((await getFile(downloadLastDir, uri1)).path, dir1.path,
      "uri1 should return dir1"); // set in CPS
-  is((yield getFile(downloadLastDir, uri2)).path, dir2.path,
+  is((await getFile(downloadLastDir, uri2)).path, dir2.path,
      "uri2 should return dir2"); // set in CPS
-  is((yield getFile(downloadLastDir, uri3)).path, dir2.path,
+  is((await getFile(downloadLastDir, uri3)).path, dir2.path,
      "uri3 should return dir2"); // fallback
-  is((yield getFile(downloadLastDir, uri4)).path, dir2.path,
+  is((await getFile(downloadLastDir, uri4)).path, dir2.path,
      "uri4 should return dir2"); // fallback
 
   // set uri3 to dir3, all except uri1 and uri2 should now return dir3
-  yield setFile(downloadLastDir, uri3, dir3);
+  await setFile(downloadLastDir, uri3, dir3);
   is(downloadLastDir.file.path, dir3.path,
      "downloadLastDir should point to dir3");
-  is((yield getFile(downloadLastDir, uri1)).path, dir1.path,
+  is((await getFile(downloadLastDir, uri1)).path, dir1.path,
      "uri1 should return dir1"); // set in CPS
-  is((yield getFile(downloadLastDir, uri2)).path, dir2.path,
+  is((await getFile(downloadLastDir, uri2)).path, dir2.path,
      "uri2 should return dir2"); // set in CPS
-  is((yield getFile(downloadLastDir, uri3)).path, dir3.path,
+  is((await getFile(downloadLastDir, uri3)).path, dir3.path,
      "uri3 should return dir3"); // set in CPS
-  is((yield getFile(downloadLastDir, uri4)).path, dir3.path,
+  is((await getFile(downloadLastDir, uri4)).path, dir3.path,
      "uri4 should return dir4"); // fallback
 
   // set uri1 to dir2, all except uri3 should now return dir2
-  yield setFile(downloadLastDir, uri1, dir2);
+  await setFile(downloadLastDir, uri1, dir2);
   is(downloadLastDir.file.path, dir2.path,
      "downloadLastDir should point to dir2");
-  is((yield getFile(downloadLastDir, uri1)).path, dir2.path,
+  is((await getFile(downloadLastDir, uri1)).path, dir2.path,
      "uri1 should return dir2"); // set in CPS
-  is((yield getFile(downloadLastDir, uri2)).path, dir2.path,
+  is((await getFile(downloadLastDir, uri2)).path, dir2.path,
      "uri2 should return dir2"); // set in CPS
-  is((yield getFile(downloadLastDir, uri3)).path, dir3.path,
+  is((await getFile(downloadLastDir, uri3)).path, dir3.path,
      "uri3 should return dir3"); // set in CPS
-  is((yield getFile(downloadLastDir, uri4)).path, dir2.path,
+  is((await getFile(downloadLastDir, uri4)).path, dir2.path,
      "uri4 should return dir2"); // fallback
 
-  yield clearHistoryAndWait();
+  await clearHistoryAndWait();
 
   // check clearHistory removes all data
   is(downloadLastDir.file, null, "clearHistory removes all data");
   //is(Services.contentPrefs.hasPref(uri1, "browser.download.lastDir", null),
   //   false, "LastDir preference should be absent");
-  is((yield getFile(downloadLastDir, uri1)), null, "uri1 should point to null");
-  is((yield getFile(downloadLastDir, uri2)), null, "uri2 should point to null");
-  is((yield getFile(downloadLastDir, uri3)), null, "uri3 should point to null");
-  is((yield getFile(downloadLastDir, uri4)), null, "uri4 should point to null");
+  is((await getFile(downloadLastDir, uri1)), null, "uri1 should point to null");
+  is((await getFile(downloadLastDir, uri2)), null, "uri2 should point to null");
+  is((await getFile(downloadLastDir, uri3)), null, "uri3 should point to null");
+  is((await getFile(downloadLastDir, uri4)), null, "uri4 should point to null");
 
-  yield setFile(downloadLastDir, null, tmpDir);
+  await setFile(downloadLastDir, null, tmpDir);
 
   // check data set outside PB mode is remembered
-  is((yield checkDownloadLastDir(pbDownloadLastDir, tmpDir)).path, tmpDir.path, "uri1 should return the expected last directory");
-  is((yield checkDownloadLastDir(downloadLastDir, tmpDir)).path, tmpDir.path, "uri1 should return the expected last directory");
-  yield clearHistoryAndWait();
+  is((await checkDownloadLastDir(pbDownloadLastDir, tmpDir)).path, tmpDir.path, "uri1 should return the expected last directory");
+  is((await checkDownloadLastDir(downloadLastDir, tmpDir)).path, tmpDir.path, "uri1 should return the expected last directory");
+  await clearHistoryAndWait();
 
-  yield setFile(downloadLastDir, uri1, dir1);
+  await setFile(downloadLastDir, uri1, dir1);
 
   // check data set using CPS outside PB mode is remembered
-  is((yield checkDownloadLastDir(pbDownloadLastDir, dir1)).path, dir1.path, "uri1 should return the expected last directory");
-  is((yield checkDownloadLastDir(downloadLastDir, dir1)).path, dir1.path, "uri1 should return the expected last directory");
-  yield clearHistoryAndWait();
+  is((await checkDownloadLastDir(pbDownloadLastDir, dir1)).path, dir1.path, "uri1 should return the expected last directory");
+  is((await checkDownloadLastDir(downloadLastDir, dir1)).path, dir1.path, "uri1 should return the expected last directory");
+  await clearHistoryAndWait();
 
   // check data set inside PB mode is forgotten
-  yield setFile(pbDownloadLastDir, null, tmpDir);
+  await setFile(pbDownloadLastDir, null, tmpDir);
 
-  is((yield checkDownloadLastDir(pbDownloadLastDir, tmpDir)).path, tmpDir.path, "uri1 should return the expected last directory");
-  is((yield checkDownloadLastDirNull(downloadLastDir)), null, "uri1 should return the expected last directory");
+  is((await checkDownloadLastDir(pbDownloadLastDir, tmpDir)).path, tmpDir.path, "uri1 should return the expected last directory");
+  is((await checkDownloadLastDirNull(downloadLastDir)), null, "uri1 should return the expected last directory");
 
-  yield clearHistoryAndWait();
+  await clearHistoryAndWait();
 
   // check data set using CPS inside PB mode is forgotten
-  yield setFile(pbDownloadLastDir, uri1, dir1);
+  await setFile(pbDownloadLastDir, uri1, dir1);
 
-  is((yield checkDownloadLastDir(pbDownloadLastDir, dir1)).path, dir1.path, "uri1 should return the expected last directory");
-  is((yield checkDownloadLastDirNull(downloadLastDir)), null, "uri1 should return the expected last directory");
+  is((await checkDownloadLastDir(pbDownloadLastDir, dir1)).path, dir1.path, "uri1 should return the expected last directory");
+  is((await checkDownloadLastDirNull(downloadLastDir)), null, "uri1 should return the expected last directory");
 
   // check data set outside PB mode but changed inside is remembered correctly
-  yield setFile(downloadLastDir, uri1, dir1);
-  yield setFile(pbDownloadLastDir, uri1, dir2);
-  is((yield checkDownloadLastDir(pbDownloadLastDir, dir2)).path, dir2.path, "uri1 should return the expected last directory");
-  is((yield checkDownloadLastDir(downloadLastDir, dir1)).path, dir1.path, "uri1 should return the expected last directory");
+  await setFile(downloadLastDir, uri1, dir1);
+  await setFile(pbDownloadLastDir, uri1, dir2);
+  is((await checkDownloadLastDir(pbDownloadLastDir, dir2)).path, dir2.path, "uri1 should return the expected last directory");
+  is((await checkDownloadLastDir(downloadLastDir, dir1)).path, dir1.path, "uri1 should return the expected last directory");
 
   /*
    * ====================
    * Create new PB window
    * ====================
    */
 
   // check that the last dir store got cleared in a new PB window
   pbWin.close();
   // And give it time to close
-  executeSoon(moveAlong);
-  yield;
-  pbWin = yield createWindow({private: true});
+  await new Promise(resolve => executeSoon(resolve));
+
+  pbWin = await createWindow({private: true});
   pbDownloadLastDir = new DownloadLastDir(pbWin);
 
-  is((yield checkDownloadLastDir(pbDownloadLastDir, dir1)).path, dir1.path, "uri1 should return the expected last directory");
+  is((await checkDownloadLastDir(pbDownloadLastDir, dir1)).path, dir1.path, "uri1 should return the expected last directory");
 
-  yield clearHistoryAndWait();
+  await clearHistoryAndWait();
 
   // check clearHistory inside PB mode clears data outside PB mode
-  yield setFile(pbDownloadLastDir, uri1, dir2);
+  await setFile(pbDownloadLastDir, uri1, dir2);
 
-  yield clearHistoryAndWait();
+  await clearHistoryAndWait();
 
-  is((yield checkDownloadLastDirNull(downloadLastDir)), null, "uri1 should return the expected last directory");
-  is((yield checkDownloadLastDirNull(pbDownloadLastDir)), null, "uri1 should return the expected last directory");
+  is((await checkDownloadLastDirNull(downloadLastDir)), null, "uri1 should return the expected last directory");
+  is((await checkDownloadLastDirNull(pbDownloadLastDir)), null, "uri1 should return the expected last directory");
 
   // check that disabling CPS works
   Services.prefs.setBoolPref("browser.download.lastDir.savePerSite", false);
 
-  yield setFile(downloadLastDir, uri1, dir1);
+  await setFile(downloadLastDir, uri1, dir1);
   is(downloadLastDir.file.path, dir1.path, "LastDir should be set to dir1");
-  is((yield getFile(downloadLastDir, uri1)).path, dir1.path, "uri1 should return dir1");
-  is((yield getFile(downloadLastDir, uri2)).path, dir1.path, "uri2 should return dir1");
-  is((yield getFile(downloadLastDir, uri3)).path, dir1.path, "uri3 should return dir1");
-  is((yield getFile(downloadLastDir, uri4)).path, dir1.path, "uri4 should return dir1");
+  is((await getFile(downloadLastDir, uri1)).path, dir1.path, "uri1 should return dir1");
+  is((await getFile(downloadLastDir, uri2)).path, dir1.path, "uri2 should return dir1");
+  is((await getFile(downloadLastDir, uri3)).path, dir1.path, "uri3 should return dir1");
+  is((await getFile(downloadLastDir, uri4)).path, dir1.path, "uri4 should return dir1");
 
   downloadLastDir.setFile(uri2, dir2);
   is(downloadLastDir.file.path, dir2.path, "LastDir should be set to dir2");
-  is((yield getFile(downloadLastDir, uri1)).path, dir2.path, "uri1 should return dir2");
-  is((yield getFile(downloadLastDir, uri2)).path, dir2.path, "uri2 should return dir2");
-  is((yield getFile(downloadLastDir, uri3)).path, dir2.path, "uri3 should return dir2");
-  is((yield getFile(downloadLastDir, uri4)).path, dir2.path, "uri4 should return dir2");
+  is((await getFile(downloadLastDir, uri1)).path, dir2.path, "uri1 should return dir2");
+  is((await getFile(downloadLastDir, uri2)).path, dir2.path, "uri2 should return dir2");
+  is((await getFile(downloadLastDir, uri3)).path, dir2.path, "uri3 should return dir2");
+  is((await getFile(downloadLastDir, uri4)).path, dir2.path, "uri4 should return dir2");
 
   Services.prefs.clearUserPref("browser.download.lastDir.savePerSite");
 
   // check that passing null to setFile clears the stored value
-  yield setFile(downloadLastDir, uri3, dir3);
-  is((yield getFile(downloadLastDir, uri3)).path, dir3.path, "LastDir should be set to dir3");
-  yield setFile(downloadLastDir, uri3, null);
-  is((yield getFile(downloadLastDir, uri3)), null, "uri3 should return null");
+  await setFile(downloadLastDir, uri3, dir3);
+  is((await getFile(downloadLastDir, uri3)).path, dir3.path, "LastDir should be set to dir3");
+  await setFile(downloadLastDir, uri3, null);
+  is((await getFile(downloadLastDir, uri3)), null, "uri3 should return null");
 
-  yield clearHistoryAndWait();
+  await clearHistoryAndWait();
+
+  finish();
 }
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_concurrent.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_concurrent.js
@@ -12,17 +12,17 @@
 // Step 4: load a page in the tab from step 2 that checks the value of test is value and the total count in private storage is 1
 
 add_task(function* setup() {
   yield SpecialPowers.pushPrefEnv({
     set: [["dom.ipc.processCount", 1]]
   });
 });
 
-add_task(function test() {
+add_task(function* test() {
   let prefix = 'http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_concurrent_page.html';
 
   function getElts(browser) {
     return browser.contentTitle.split('|');
   };
 
   // Step 1
   let non_private_browser = gBrowser.selectedBrowser;
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_crh.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_crh.js
@@ -1,16 +1,16 @@
 /* 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 test makes sure that the Clear Recent History menu item and command 
 // is disabled inside the private browsing mode.
 
-add_task(function test() {
+add_task(function* test() {
   function checkDisableOption(aPrivateMode, aWindow) {
     let crhCommand = aWindow.document.getElementById("Tools:Sanitize");
     ok(crhCommand, "The clear recent history command should exist");
 
     is(PrivateBrowsingUtils.isWindowPrivate(aWindow), aPrivateMode,
       "PrivateBrowsingUtils should report the correct per-window private browsing status");
     is(crhCommand.hasAttribute("disabled"), aPrivateMode,
       "Clear Recent History command should be disabled according to the private browsing mode");
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_toggle.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_toggle.js
@@ -70,36 +70,34 @@ add_task(function* test_downloads_last_d
  *        expectedDir (nsIFile, expectedDir):
  *          An nsIFile for what we expect the last download directory
  *          should be. The nsIFile is not compared directly - only
  *          paths are compared. If expectedDir is not set, then the
  *          last download directory is expected to be null.
  *
  * @returns Promise
  */
-function testHelper(options) {
-  return new Task.spawn(function() {
-    let win = yield BrowserTestUtils.openNewBrowserWindow(options);
-    let gDownloadLastDir = new DownloadLastDir(win);
+async function testHelper(options) {
+  let win = await BrowserTestUtils.openNewBrowserWindow(options);
+  let gDownloadLastDir = new DownloadLastDir(win);
 
-    if (options.clearHistory) {
-      clearHistory();
-    }
+  if (options.clearHistory) {
+    clearHistory();
+  }
 
-    if (options.setDir) {
-      gDownloadLastDir.file = options.setDir;
-    }
+  if (options.setDir) {
+    gDownloadLastDir.file = options.setDir;
+  }
 
-    let expectedDir = options.expectedDir;
+  let expectedDir = options.expectedDir;
 
-    if (expectedDir) {
-      is(gDownloadLastDir.file.path, expectedDir.path,
-         "gDownloadLastDir should point to the expected last directory");
-      isnot(gDownloadLastDir.file, expectedDir,
-            "gDownloadLastDir.file should not be pointing to the last directory");
-    } else {
-      is(gDownloadLastDir.file, null, "gDownloadLastDir should be null");
-    }
+  if (expectedDir) {
+    is(gDownloadLastDir.file.path, expectedDir.path,
+       "gDownloadLastDir should point to the expected last directory");
+    isnot(gDownloadLastDir.file, expectedDir,
+          "gDownloadLastDir.file should not be pointing to the last directory");
+  } else {
+    is(gDownloadLastDir.file, null, "gDownloadLastDir should be null");
+  }
 
-    gDownloadLastDir.cleanupPrivateFile();
-    yield BrowserTestUtils.closeWindow(win);
-  });
+  gDownloadLastDir.cleanupPrivateFile();
+  await BrowserTestUtils.closeWindow(win);
 }
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage.js
@@ -1,13 +1,13 @@
 /* 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/. */
 
- add_task(function test() {
+ add_task(function* test() {
   requestLongerTimeout(2);
   const page1 = 'http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/' +
                 'browser_privatebrowsing_localStorage_page1.html'
 
   let win = yield BrowserTestUtils.openNewBrowserWindow({private: true});
 
   let tab = win.gBrowser.selectedTab = win.gBrowser.addTab(page1);
   let browser = win.gBrowser.selectedBrowser;
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_before_after.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_before_after.js
@@ -5,17 +5,17 @@
 // Ensure that a storage instance used by both private and public sessions at different times does not
 // allow any data to leak due to cached values.
 
 // Step 1: Load browser_privatebrowsing_localStorage_before_after_page.html in a private tab, causing a storage
 //   item to exist. Close the tab.
 // Step 2: Load the same page in a non-private tab, ensuring that the storage instance reports only one item
 //   existing.
 
-add_task(function test() {
+add_task(function* test() {
   let testURI = "about:blank";
   let prefix = 'http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/';
 
   // Step 1.
   let privateWin = yield BrowserTestUtils.openNewBrowserWindow({private: true});
   let privateBrowser = privateWin.gBrowser.addTab(
     prefix + 'browser_privatebrowsing_localStorage_before_after_page.html').linkedBrowser;
   yield BrowserTestUtils.browserLoaded(privateBrowser);
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_windowtitle.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_windowtitle.js
@@ -1,16 +1,16 @@
 /* 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 test makes sure that the window title changes correctly while switching
 // from and to private browsing mode.
 
-add_task(function test() {
+add_task(function* test() {
   const testPageURL = "http://mochi.test:8888/browser/" +
     "browser/components/privatebrowsing/test/browser/browser_privatebrowsing_windowtitle_page.html";
   requestLongerTimeout(2);
 
   // initialization of expected titles
   let test_title = "Test title";
   let app_name = document.documentElement.getAttribute("title");
   const isOSX = ("nsILocalFileMac" in Ci);
@@ -32,46 +32,46 @@ add_task(function test() {
     page_with_title = test_title + " - " + app_name;
     page_without_title = app_name;
     about_pb_title = "Open a private window?" + " - " + app_name;
     pb_page_with_title = test_title + " - " + app_name + " (Private Browsing)";
     pb_page_without_title = app_name + " (Private Browsing)";
     pb_about_pb_title = "Private Browsing - " + app_name + " (Private Browsing)";
   }
 
-  function* testTabTitle(aWindow, url, insidePB, expected_title) {
-    let tab = (yield BrowserTestUtils.openNewForegroundTab(aWindow.gBrowser));
-    yield BrowserTestUtils.loadURI(tab.linkedBrowser, url);
-    yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+  async function testTabTitle(aWindow, url, insidePB, expected_title) {
+    let tab = (await BrowserTestUtils.openNewForegroundTab(aWindow.gBrowser));
+    await BrowserTestUtils.loadURI(tab.linkedBrowser, url);
+    await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
 
-    yield BrowserTestUtils.waitForCondition(() => {
+    await BrowserTestUtils.waitForCondition(() => {
       return aWindow.document.title === expected_title;
     }, `Window title should be ${expected_title}, got ${aWindow.document.title}`);
 
     is(aWindow.document.title, expected_title, "The window title for " + url +
        " is correct (" + (insidePB ? "inside" : "outside") +
        " private browsing mode)");
 
     let win = aWindow.gBrowser.replaceTabWithWindow(tab);
-    yield BrowserTestUtils.waitForEvent(win, "load", false);
+    await BrowserTestUtils.waitForEvent(win, "load", false);
 
-    yield BrowserTestUtils.waitForCondition(() => {
+    await BrowserTestUtils.waitForCondition(() => {
       return win.document.title === expected_title;
     }, `Window title should be ${expected_title}, got ${aWindow.document.title}`);
 
     is(win.document.title, expected_title, "The window title for " + url +
        " detached tab is correct (" + (insidePB ? "inside" : "outside") +
        " private browsing mode)");
 
-    yield Promise.all([ BrowserTestUtils.closeWindow(win),
+    await Promise.all([ BrowserTestUtils.closeWindow(win),
                         BrowserTestUtils.closeWindow(aWindow) ]);
   }
 
   function openWin(private) {
     return BrowserTestUtils.openNewBrowserWindow({ private });
   }
-  yield Task.spawn(testTabTitle((yield openWin(false)), "about:blank", false, page_without_title));
-  yield Task.spawn(testTabTitle((yield openWin(false)), testPageURL, false, page_with_title));
-  yield Task.spawn(testTabTitle((yield openWin(false)), "about:privatebrowsing", false, about_pb_title));
-  yield Task.spawn(testTabTitle((yield openWin(true)), "about:blank", true, pb_page_without_title));
-  yield Task.spawn(testTabTitle((yield openWin(true)), testPageURL, true, pb_page_with_title));
-  yield Task.spawn(testTabTitle((yield openWin(true)), "about:privatebrowsing", true, pb_about_pb_title));
+  yield testTabTitle((yield openWin(false)), "about:blank", false, page_without_title);
+  yield testTabTitle((yield openWin(false)), testPageURL, false, page_with_title);
+  yield testTabTitle((yield openWin(false)), "about:privatebrowsing", false, about_pb_title);
+  yield testTabTitle((yield openWin(true)), "about:blank", true, pb_page_without_title);
+  yield testTabTitle((yield openWin(true)), testPageURL, true, pb_page_with_title);
+  yield testTabTitle((yield openWin(true)), "about:privatebrowsing", true, pb_about_pb_title);
 });
--- a/browser/components/sessionstore/SessionMigration.jsm
+++ b/browser/components/sessionstore/SessionMigration.jsm
@@ -61,38 +61,38 @@ var SessionMigrationInternal = {
     let url = "about:welcomeback";
     let formdata = {id: {sessionData: state}, url};
     return {windows: [{tabs: [{entries: [{url}], formdata}]}]};
   },
   /**
    * Asynchronously read session restore state (JSON) from a path
    */
   readState: function(aPath) {
-    return Task.spawn(function() {
+    return Task.spawn(function*() {
       let bytes = yield OS.File.read(aPath);
       let text = gDecoder.decode(bytes);
       let state = JSON.parse(text);
-      throw new Task.Result(state);
+      return state;
     });
   },
   /**
    * Asynchronously write session restore state as JSON to a path
    */
   writeState: function(aPath, aState) {
     let bytes = gEncoder.encode(JSON.stringify(aState));
     return OS.File.writeAtomic(aPath, bytes, {tmpPath: aPath + ".tmp"});
   }
 }
 
 var SessionMigration = {
   /**
    * Migrate a limited set of session data from one path to another.
    */
   migrate: function(aFromPath, aToPath) {
-    return Task.spawn(function() {
+    return Task.spawn(function*() {
       let inState = yield SessionMigrationInternal.readState(aFromPath);
       let outState = SessionMigrationInternal.convertState(inState);
       // Unfortunately, we can't use SessionStore's own SessionFile to
       // write out the data because it has a dependency on the profile dir
       // being known. When the migration runs, there is no guarantee that
       // that's true.
       yield SessionMigrationInternal.writeState(aToPath, outState);
     });
--- a/browser/components/sessionstore/test/browser_393716.js
+++ b/browser/components/sessionstore/test/browser_393716.js
@@ -3,17 +3,17 @@
 
 "use strict";
 
 const URL = "about:config";
 
 /**
  * Bug 393716 - Basic tests for getTabState(), setTabState(), and duplicateTab().
  */
-add_task(function test_set_tabstate() {
+add_task(function* test_set_tabstate() {
   let key = "Unique key: " + Date.now();
   let value = "Unique value: " + Math.random();
 
   // create a new tab
   let tab = gBrowser.addTab(URL);
   ss.setTabValue(tab, key, value);
   yield promiseBrowserLoaded(tab.linkedBrowser);
 
@@ -30,17 +30,17 @@ add_task(function test_set_tabstate() {
      "Got the expected state object (test URL)");
   ok(state.extData && state.extData[key] == value,
      "Got the expected state object (test manually set tab value)");
 
   // clean up
   gBrowser.removeTab(tab);
 });
 
-add_task(function test_set_tabstate_and_duplicate() {
+add_task(function* test_set_tabstate_and_duplicate() {
   let key2 = "key2";
   let value2 = "Value " + Math.random();
   let value3 = "Another value: " + Date.now();
   let state = { entries: [{ url: URL }], extData: { key2: value2 } };
 
   // create a new tab
   let tab = gBrowser.addTab();
   // set the tab's state
--- a/browser/components/sessionstore/test/browser_456342.js
+++ b/browser/components/sessionstore/test/browser_456342.js
@@ -3,17 +3,17 @@
 
 "use strict";
 
 const URL = ROOT + "browser_456342_sample.xhtml";
 
 /**
  * Bug 456342 - Restore values from non-standard input field types.
  */
-add_task(function test_restore_nonstandard_input_values() {
+add_task(function* test_restore_nonstandard_input_values() {
   // Add tab with various non-standard input field types.
   let tab = gBrowser.addTab(URL);
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
   // Fill in form values.
   let expectedValue = Math.random();
   yield setFormElementValues(browser, {value: expectedValue});
--- a/browser/components/sessionstore/test/browser_463205.js
+++ b/browser/components/sessionstore/test/browser_463205.js
@@ -5,17 +5,17 @@
 
 const URL = ROOT + "browser_463205_sample.html";
 
 /**
  * Bug 463205 - Check URLs before restoring form data to make sure a malicious
  * website can't modify frame URLs and make us inject form data into the wrong
  * web pages.
  */
-add_task(function test_check_urls_before_restoring() {
+add_task(function* test_check_urls_before_restoring() {
   // Add a blank tab.
   let tab = gBrowser.addTab("about:blank");
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
   // Restore form data with a valid URL.
   yield promiseTabState(tab, getState(URL));
 
--- a/browser/components/sessionstore/test/browser_466937.js
+++ b/browser/components/sessionstore/test/browser_466937.js
@@ -3,17 +3,17 @@
 
 "use strict";
 
 const URL = ROOT + "browser_466937_sample.html";
 
 /**
  * Bug 466937 - Prevent file stealing with sessionstore.
  */
-add_task(function test_prevent_file_stealing() {
+add_task(function* test_prevent_file_stealing() {
   // Add a tab with some file input fields.
   let tab = gBrowser.addTab(URL);
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
   // Generate a path to a 'secret' file.
   let file = Services.dirsvc.get("TmpD", Ci.nsIFile);
   file.append("466937_test.file");
--- a/browser/components/sessionstore/test/browser_467409-backslashplosion.js
+++ b/browser/components/sessionstore/test/browser_467409-backslashplosion.js
@@ -25,17 +25,17 @@ const STATE3 = createEntries(JSON.string
 
 function createEntries(sessionData) {
   return {
     entries: [{url: "about:sessionrestore"}],
     formdata: {id: {sessionData: sessionData}, url: "about:sessionrestore"}
   };
 }
 
-add_task(function test_nested_about_sessionrestore() {
+add_task(function* test_nested_about_sessionrestore() {
   // Prepare a blank tab.
   let tab = gBrowser.addTab("about:blank");
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
   // test 1
   yield promiseTabState(tab, STATE);
   yield checkState("test1", tab);
--- a/browser/components/sessionstore/test/browser_485482.js
+++ b/browser/components/sessionstore/test/browser_485482.js
@@ -4,17 +4,17 @@
 "use strict";
 
 const URL = ROOT + "browser_485482_sample.html";
 
 /**
  * Bug 485482 - Make sure that we produce valid XPath expressions even for very
  * weird HTML documents.
  */
-add_task(function test_xpath_exp_for_strange_documents() {
+add_task(function* test_xpath_exp_for_strange_documents() {
   // Load a page with weird tag names.
   let tab = gBrowser.addTab(URL);
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
   // Fill in some values.
   let uniqueValue = Math.random();
   yield setInputValue(browser, {selector: "input[type=text]", value: uniqueValue});
--- a/browser/components/sessionstore/test/browser_528776.js
+++ b/browser/components/sessionstore/test/browser_528776.js
@@ -6,16 +6,16 @@ function browserWindowsCount(expected) {
       ++count;
   }
   is(count, expected,
      "number of open browser windows according to nsIWindowMediator");
   is(JSON.parse(ss.getBrowserState()).windows.length, expected,
      "number of open browser windows according to getBrowserState");
 }
 
-add_task(function() {
+add_task(function*() {
   browserWindowsCount(1);
 
   let win = yield BrowserTestUtils.openNewBrowserWindow();
   browserWindowsCount(2);
   yield BrowserTestUtils.closeWindow(win);
   browserWindowsCount(1);
 });
--- a/browser/components/sessionstore/test/browser_broadcast.js
+++ b/browser/components/sessionstore/test/browser_broadcast.js
@@ -4,33 +4,33 @@
 "use strict";
 
 const INITIAL_VALUE = "browser_broadcast.js-initial-value-" + Date.now();
 
 /**
  * This test ensures we won't lose tab data queued in the content script when
  * closing a tab.
  */
-add_task(function flush_on_tabclose() {
+add_task(function* flush_on_tabclose() {
   let tab = yield createTabWithStorageData(["http://example.com"]);
   let browser = tab.linkedBrowser;
 
   yield modifySessionStorage(browser, {test: "on-tab-close"});
   yield promiseRemoveTab(tab);
 
   let [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window));
   is(storage["http://example.com"].test, "on-tab-close",
     "sessionStorage data has been flushed on TabClose");
 });
 
 /**
  * This test ensures we won't lose tab data queued in the content script when
  * duplicating a tab.
  */
-add_task(function flush_on_duplicate() {
+add_task(function* flush_on_duplicate() {
   let tab = yield createTabWithStorageData(["http://example.com"]);
   let browser = tab.linkedBrowser;
 
   yield modifySessionStorage(browser, {test: "on-duplicate"});
   let tab2 = ss.duplicateTab(window, tab);
   yield promiseTabRestored(tab2);
 
   yield promiseRemoveTab(tab2);
@@ -40,34 +40,34 @@ add_task(function flush_on_duplicate() {
 
   gBrowser.removeTab(tab);
 });
 
 /**
  * This test ensures we won't lose tab data queued in the content script when
  * a window is closed.
  */
-add_task(function flush_on_windowclose() {
+add_task(function* flush_on_windowclose() {
   let win = yield promiseNewWindow();
   let tab = yield createTabWithStorageData(["http://example.com"], win);
   let browser = tab.linkedBrowser;
 
   yield modifySessionStorage(browser, {test: "on-window-close"});
   yield BrowserTestUtils.closeWindow(win);
 
   let [{tabs: [_, {storage}]}] = JSON.parse(ss.getClosedWindowData());
   is(storage["http://example.com"].test, "on-window-close",
     "sessionStorage data has been flushed when closing a window");
 });
 
 /**
  * This test ensures that stale tab data is ignored when reusing a tab
  * (via e.g. setTabState) and does not overwrite the new data.
  */
-add_task(function flush_on_settabstate() {
+add_task(function* flush_on_settabstate() {
   let tab = yield createTabWithStorageData(["http://example.com"]);
   let browser = tab.linkedBrowser;
 
   // Flush to make sure our tab state is up-to-date.
   yield TabStateFlusher.flush(browser);
 
   let state = ss.getTabState(tab);
   yield modifySessionStorage(browser, {test: "on-set-tab-state"});
@@ -85,17 +85,17 @@ add_task(function flush_on_settabstate()
   gBrowser.removeTab(tab);
 });
 
 /**
  * This test ensures that we won't lose tab data that has been sent
  * asynchronously just before closing a tab. Flushing must re-send all data
  * that hasn't been received by chrome, yet.
  */
-add_task(function flush_on_tabclose_racy() {
+add_task(function* flush_on_tabclose_racy() {
   let tab = yield createTabWithStorageData(["http://example.com"]);
   let browser = tab.linkedBrowser;
 
   // Flush to make sure we start with an empty queue.
   yield TabStateFlusher.flush(browser);
 
   yield modifySessionStorage(browser, {test: "on-tab-close-racy"});
 
@@ -110,22 +110,20 @@ add_task(function flush_on_tabclose_racy
 });
 
 function promiseNewWindow() {
   let deferred = Promise.defer();
   whenNewWindowLoaded({private: false}, deferred.resolve);
   return deferred.promise;
 }
 
-function createTabWithStorageData(urls, win = window) {
-  return Task.spawn(function task() {
-    let tab = win.gBrowser.addTab();
-    let browser = tab.linkedBrowser;
+async function createTabWithStorageData(urls, win = window) {
+  let tab = win.gBrowser.addTab();
+  let browser = tab.linkedBrowser;
 
-    for (let url of urls) {
-      browser.loadURI(url);
-      yield promiseBrowserLoaded(browser);
-      yield modifySessionStorage(browser, {test: INITIAL_VALUE});
-    }
+  for (let url of urls) {
+    browser.loadURI(url);
+    await promiseBrowserLoaded(browser);
+    await modifySessionStorage(browser, {test: INITIAL_VALUE});
+  }
 
-    throw new Task.Result(tab);
-  });
+  return tab;
 }
--- a/browser/components/sessionstore/test/browser_capabilities.js
+++ b/browser/components/sessionstore/test/browser_capabilities.js
@@ -3,17 +3,17 @@
 
 "use strict";
 
 /**
  * These tests ensures that disabling features by flipping nsIDocShell.allow*
  * properties are (re)stored as disabled. Disallowed features must be
  * re-enabled when the tab is re-used by another tab restoration.
  */
-add_task(function docshell_capabilities() {
+add_task(function* docshell_capabilities() {
   let tab = yield createTab();
   let browser = tab.linkedBrowser;
   let docShell = browser.docShell;
 
   // Get the list of capabilities for docShells.
   let flags = Object.keys(docShell).filter(k => k.startsWith("allow"));
 
   // Check that everything is allowed by default for new tabs.
@@ -64,13 +64,14 @@ add_task(function docshell_capabilities(
   ok(disallow.has("Images"), "images not allowed anymore");
   ok(disallow.has("MetaRedirects"), "meta redirects not allowed anymore");
   is(disallow.size, 2, "two capabilities disallowed");
 
   // Clean up after ourselves.
   gBrowser.removeTab(tab);
 });
 
-function createTab() {
+async function createTab() {
   let tab = gBrowser.addTab("about:mozilla");
   let browser = tab.linkedBrowser;
-  return promiseBrowserLoaded(browser).then(() => tab);
+  await promiseBrowserLoaded(browser);
+  return tab;
 }
--- a/browser/components/sessionstore/test/browser_cookies.js
+++ b/browser/components/sessionstore/test/browser_cookies.js
@@ -79,17 +79,17 @@ add_task(function* test_run() {
   });
 });
 
 /**
  * Generic test function to check sessionstore's cookie collection module with
  * different cookie domains given in the Set-Cookie header. See above for some
  * usage examples.
  */
-var testCookieCollection = Task.async(function (params) {
+var testCookieCollection = async function (params) {
   let tab = gBrowser.addTab("about:blank");
   let browser = tab.linkedBrowser;
 
   let urlParams = new URLSearchParams();
   let value = Math.random();
   urlParams.append("value", value);
 
   if (params.domain) {
@@ -97,60 +97,60 @@ var testCookieCollection = Task.async(fu
   }
 
   // Construct request URI.
   let uri = `${params.host}${PATH}browser_cookies.sjs?${urlParams}`;
 
   // Wait for the browser to load and the cookie to be set.
   // These two events can probably happen in no particular order,
   // so let's wait for them in parallel.
-  yield Promise.all([
+  await Promise.all([
     waitForNewCookie(),
     replaceCurrentURI(browser, uri)
   ]);
 
   // Check all URIs for which the cookie should be collected.
   for (let uri of params.cookieURIs || []) {
-    yield replaceCurrentURI(browser, uri);
+    await replaceCurrentURI(browser, uri);
 
     // Check the cookie.
     let cookie = getCookie();
     is(cookie.host, params.cookieHost, "cookie host is correct");
     is(cookie.path, PATH, "cookie path is correct");
     is(cookie.name, "foobar", "cookie name is correct");
     is(cookie.value, value, "cookie value is correct");
   }
 
   // Check all URIs for which the cookie should NOT be collected.
   for (let uri of params.noCookieURIs || []) {
-    yield replaceCurrentURI(browser, uri);
+    await replaceCurrentURI(browser, uri);
 
     // Cookie should be ignored.
     ok(!getCookie(), "no cookie collected");
   }
 
   // Clean up.
   gBrowser.removeTab(tab);
   Services.cookies.removeAll();
-});
+};
 
 /**
  * Replace the current URI of the given browser by loading a new URI. The
  * browser's session history will be completely replaced. This function ensures
  * that the parent process has the lastest shistory data before resolving.
  */
-var replaceCurrentURI = Task.async(function* (browser, uri) {
+var replaceCurrentURI = async function(browser, uri) {
   // Replace the tab's current URI with the parent domain.
   let flags = Ci.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY;
   browser.loadURIWithFlags(uri, flags);
-  yield promiseBrowserLoaded(browser);
+  await promiseBrowserLoaded(browser);
 
   // Ensure the tab's session history is up-to-date.
-  yield TabStateFlusher.flush(browser);
-});
+  await TabStateFlusher.flush(browser);
+};
 
 /**
  * Waits for a new "*example.com" cookie to be added.
  */
 function waitForNewCookie() {
   return new Promise(resolve => {
     Services.obs.addObserver(function observer(subj, topic, data) {
       let cookie = subj.QueryInterface(Ci.nsICookie2);
--- a/browser/components/sessionstore/test/browser_crashedTabs.js
+++ b/browser/components/sessionstore/test/browser_crashedTabs.js
@@ -120,17 +120,17 @@ function promiseTabCrashedReady(browser)
     }, false, true);
   });
 }
 
 /**
  * Checks that if a tab crashes, that information about the tab crashed
  * page does not get added to the tab history.
  */
-add_task(function test_crash_page_not_in_history() {
+add_task(function* test_crash_page_not_in_history() {
   let newTab = gBrowser.addTab();
   gBrowser.selectedTab = newTab;
   let browser = newTab.linkedBrowser;
   ok(browser.isRemoteBrowser, "Should be a remote browser");
   yield promiseBrowserLoaded(browser);
 
   browser.loadURI(PAGE_1);
   yield promiseBrowserLoaded(browser);
@@ -149,17 +149,17 @@ add_task(function test_crash_page_not_in
   gBrowser.removeTab(newTab);
 });
 
 /**
  * Checks that if a tab crashes, that when we browse away from that page
  * to a non-blacklisted site (so the browser becomes remote again), that
  * we record history for that new visit.
  */
-add_task(function test_revived_history_from_remote() {
+add_task(function* test_revived_history_from_remote() {
   let newTab = gBrowser.addTab();
   gBrowser.selectedTab = newTab;
   let browser = newTab.linkedBrowser;
   ok(browser.isRemoteBrowser, "Should be a remote browser");
   yield promiseBrowserLoaded(browser);
 
   browser.loadURI(PAGE_1);
   yield promiseBrowserLoaded(browser);
@@ -188,17 +188,17 @@ add_task(function test_revived_history_f
   gBrowser.removeTab(newTab);
 });
 
 /**
  * Checks that if a tab crashes, that when we browse away from that page
  * to a blacklisted site (so the browser stays non-remote), that
  * we record history for that new visit.
  */
-add_task(function test_revived_history_from_non_remote() {
+add_task(function* test_revived_history_from_non_remote() {
   let newTab = gBrowser.addTab();
   gBrowser.selectedTab = newTab;
   let browser = newTab.linkedBrowser;
   ok(browser.isRemoteBrowser, "Should be a remote browser");
   yield promiseBrowserLoaded(browser);
 
   browser.loadURI(PAGE_1);
   yield promiseBrowserLoaded(browser);
@@ -226,17 +226,17 @@ add_task(function test_revived_history_f
 
   gBrowser.removeTab(newTab);
 });
 
 /**
  * Checks that we can revive a crashed tab back to the page that
  * it was on when it crashed.
  */
-add_task(function test_revive_tab_from_session_store() {
+add_task(function* test_revive_tab_from_session_store() {
   let newTab = gBrowser.addTab();
   gBrowser.selectedTab = newTab;
   let browser = newTab.linkedBrowser;
   ok(browser.isRemoteBrowser, "Should be a remote browser");
   yield promiseBrowserLoaded(browser);
 
   browser.loadURI(PAGE_1);
   yield promiseBrowserLoaded(browser);
@@ -279,17 +279,17 @@ add_task(function test_revive_tab_from_s
   gBrowser.removeTab(newTab);
   gBrowser.removeTab(newTab2);
 });
 
 /**
  * Checks that we can revive multiple crashed tabs back to the pages
  * that they were on when they crashed.
  */
-add_task(function test_revive_all_tabs_from_session_store() {
+add_task(function* test_revive_all_tabs_from_session_store() {
   let newTab = gBrowser.addTab();
   gBrowser.selectedTab = newTab;
   let browser = newTab.linkedBrowser;
   ok(browser.isRemoteBrowser, "Should be a remote browser");
   yield promiseBrowserLoaded(browser);
 
   browser.loadURI(PAGE_1);
   yield promiseBrowserLoaded(browser);
@@ -339,17 +339,17 @@ add_task(function test_revive_all_tabs_f
 
   yield BrowserTestUtils.closeWindow(win2);
   gBrowser.removeTab(newTab);
 });
 
 /**
  * Checks that about:tabcrashed can close the current tab
  */
-add_task(function test_close_tab_after_crash() {
+add_task(function* test_close_tab_after_crash() {
   let newTab = gBrowser.addTab();
   gBrowser.selectedTab = newTab;
   let browser = newTab.linkedBrowser;
   ok(browser.isRemoteBrowser, "Should be a remote browser");
   yield promiseBrowserLoaded(browser);
 
   browser.loadURI(PAGE_1);
   yield promiseBrowserLoaded(browser);
--- a/browser/components/sessionstore/test/browser_dynamic_frames.js
+++ b/browser/components/sessionstore/test/browser_dynamic_frames.js
@@ -2,17 +2,17 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 /**
  * Ensure that static frames of framesets are serialized but dynamically
  * inserted iframes are ignored.
  */
-add_task(function () {
+add_task(function*() {
   // This URL has the following frames:
   //  + data:text/html,A (static)
   //  + data:text/html,B (static)
   //  + data:text/html,C (dynamic iframe)
   const URL = "data:text/html;charset=utf-8," +
               "<frameset cols=50%25,50%25><frame src='data:text/html,A'>" +
               "<frame src='data:text/html,B'></frameset>" +
               "<script>var i=document.createElement('iframe');" +
@@ -40,17 +40,17 @@ add_task(function () {
   gBrowser.removeTab(tab);
 });
 
 /**
  * Ensure that iframes created by the network parser are serialized but
  * dynamically inserted iframes are ignored. Navigating a subframe should
  * create a second root entry that doesn't contain any dynamic children either.
  */
-add_task(function () {
+add_task(function*() {
   // This URL has the following frames:
   //  + data:text/html,A (static)
   //  + data:text/html,C (dynamic iframe)
   const URL = "data:text/html;charset=utf-8," +
               "<iframe name=t src='data:text/html,A'></iframe>" +
               "<a id=lnk href='data:text/html,B' target=t>clickme</a>" +
               "<script>var i=document.createElement('iframe');" +
               "i.setAttribute('src', 'data:text/html,C');" +
--- a/browser/components/sessionstore/test/browser_form_restore_events.js
+++ b/browser/components/sessionstore/test/browser_form_restore_events.js
@@ -4,17 +4,17 @@
 "use strict";
 
 const URL = ROOT + "browser_form_restore_events_sample.html";
 
 /**
  * Originally a test for Bug 476161, but then expanded to include all input
  * types in bug 640136.
  */
-add_task(function () {
+add_task(function*() {
   // Load a page with some form elements.
   let tab = gBrowser.addTab(URL);
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
   // text fields
   yield setInputValue(browser, {id: "modify01", value: Math.random()});
   yield setInputValue(browser, {id: "modify02", value: Date.now()});
--- a/browser/components/sessionstore/test/browser_formdata.js
+++ b/browser/components/sessionstore/test/browser_formdata.js
@@ -4,71 +4,69 @@
 "use strict";
 
 requestLongerTimeout(2);
 
 /**
  * This test ensures that form data collection respects the privacy level as
  * set by the user.
  */
-add_task(function test_formdata() {
+add_task(function* test_formdata() {
   const URL = "http://mochi.test:8888/browser/browser/components/" +
               "sessionstore/test/browser_formdata_sample.html";
 
   const OUTER_VALUE = "browser_formdata_" + Math.random();
   const INNER_VALUE = "browser_formdata_" + Math.random();
 
   // Creates a tab, loads a page with some form fields,
   // modifies their values and closes the tab.
-  function createAndRemoveTab() {
-    return Task.spawn(function () {
-      // Create a new tab.
-      let tab = gBrowser.addTab(URL);
-      let browser = tab.linkedBrowser;
-      yield promiseBrowserLoaded(browser);
+  function* createAndRemoveTab() {
+    // Create a new tab.
+    let tab = gBrowser.addTab(URL);
+    let browser = tab.linkedBrowser;
+    yield promiseBrowserLoaded(browser);
 
-      // Modify form data.
-      yield setInputValue(browser, {id: "txt", value: OUTER_VALUE});
-      yield setInputValue(browser, {id: "txt", value: INNER_VALUE, frame: 0});
+    // Modify form data.
+    yield setInputValue(browser, {id: "txt", value: OUTER_VALUE});
+    yield setInputValue(browser, {id: "txt", value: INNER_VALUE, frame: 0});
 
-      // Remove the tab.
-      yield promiseRemoveTab(tab);
-    });
+    // Remove the tab.
+    yield promiseRemoveTab(tab);
   }
 
-  yield createAndRemoveTab();
+  yield* createAndRemoveTab();
   let [{state: {formdata}}] = JSON.parse(ss.getClosedTabData(window));
   is(formdata.id.txt, OUTER_VALUE, "outer value is correct");
   is(formdata.children[0].id.txt, INNER_VALUE, "inner value is correct");
 
   // Disable saving data for encrypted sites.
   Services.prefs.setIntPref("browser.sessionstore.privacy_level", 1);
 
-  yield createAndRemoveTab();
+  yield* createAndRemoveTab();
   [{state: {formdata}}] = JSON.parse(ss.getClosedTabData(window));
   is(formdata.id.txt, OUTER_VALUE, "outer value is correct");
   ok(!formdata.children, "inner value was *not* stored");
 
   // Disable saving data for any site.
   Services.prefs.setIntPref("browser.sessionstore.privacy_level", 2);
 
-  yield createAndRemoveTab();
+  yield* createAndRemoveTab();
   [{state: {formdata}}] = JSON.parse(ss.getClosedTabData(window));
   ok(!formdata, "form data has *not* been stored");
 
   // Restore the default privacy level.
   Services.prefs.clearUserPref("browser.sessionstore.privacy_level");
 });
 
 /**
  * This test ensures that a malicious website can't trick us into restoring
  * form data into a wrong website and that we always check the stored URL
  * before doing so.
  */
-add_task(function test_url_check() {
+add_task(function* test_url_check() {
   const URL = "data:text/html;charset=utf-8,<input%20id=input>";
   const VALUE = "value-" + Math.random();
 
   // Create a tab with an iframe containing an input field.
   let tab = gBrowser.addTab(URL);
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
@@ -93,17 +91,17 @@ add_task(function test_url_check() {
   // Cleanup.
   gBrowser.removeTab(tab);
 });
 
 /**
  * This test ensures that collecting form data works as expected when having
  * nested frame sets.
  */
-add_task(function test_nested() {
+add_task(function* test_nested() {
   const URL = "data:text/html;charset=utf-8," +
               "<iframe src='data:text/html;charset=utf-8," +
               "<input autofocus=true>'/>";
 
   const FORM_DATA = {
     children: [{
       xpath: {"/xhtml:html/xhtml:body/xhtml:input": "M"},
       url: "data:text/html;charset=utf-8,<input%20autofocus=true>"
@@ -138,17 +136,17 @@ add_task(function test_nested() {
   // Cleanup.
   gBrowser.removeTab(tab);
 });
 
 /**
  * This test ensures that collecting form data for documents with
  * designMode=on works as expected.
  */
-add_task(function test_design_mode() {
+add_task(function* test_design_mode() {
   const URL = "data:text/html;charset=utf-8,<h1>mozilla</h1>" +
               "<script>document.designMode='on'</script>";
 
   // Load a tab with an editable document.
   let tab = gBrowser.selectedTab = gBrowser.addTab(URL);
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
--- a/browser/components/sessionstore/test/browser_formdata_format.js
+++ b/browser/components/sessionstore/test/browser_formdata_format.js
@@ -48,66 +48,57 @@ function test() {
     [ "", "value16" ],
     [ "value18", "" ],
     [ "value20", "value21" ],
     [ "", "value23" ],
     [ "value26", "" ],
     [ "value29", "value30" ],
     [ "", "value33" ]
   ];
-  let testTabCount = 0;
-  let callback = function() {
-    testTabCount--;
-    if (testTabCount == 0) {
-      finish();
-    }
-  };
 
+  let promises = [];
   for (let i = 0; i < formData.length; i++) {
-    testTabCount++;
-    testTabRestoreData(formData[i], expectedValues[i], callback);
+    promises.push(testTabRestoreData(formData[i], expectedValues[i]));
   }
+
+  Promise.all(promises).then(() => finish(), ex => ok(false, ex));
 }
 
-function testTabRestoreData(aFormData, aExpectedValue, aCallback) {
+async function testTabRestoreData(aFormData, aExpectedValue) {
   let URL = ROOT + "browser_formdata_format_sample.html";
   let tab = gBrowser.addTab("about:blank");
   let browser = tab.linkedBrowser;
 
   aFormData.url = URL;
   let tabState = { entries: [{ url: URL }], formdata: aFormData };
 
-  Task.spawn(function () {
-    yield promiseBrowserLoaded(tab.linkedBrowser);
-    yield promiseTabState(tab, tabState);
+  await promiseBrowserLoaded(tab.linkedBrowser);
+  await promiseTabState(tab, tabState);
 
-    yield TabStateFlusher.flush(tab.linkedBrowser);
-    let restoredTabState = JSON.parse(ss.getTabState(tab));
-    let restoredFormData = restoredTabState.formdata;
+  await TabStateFlusher.flush(tab.linkedBrowser);
+  let restoredTabState = JSON.parse(ss.getTabState(tab));
+  let restoredFormData = restoredTabState.formdata;
 
-    if (restoredFormData) {
-      let doc = tab.linkedBrowser.contentDocument;
-      let input1 = doc.getElementById("input1");
-      let input2 = doc.querySelector("input[name=input2]");
+  if (restoredFormData) {
+    let doc = tab.linkedBrowser.contentDocument;
+    let input1 = doc.getElementById("input1");
+    let input2 = doc.querySelector("input[name=input2]");
 
-      // test format
-      ok("id" in restoredFormData || "xpath" in restoredFormData,
-        "FormData format is valid: " + restoredFormData);
-      // validate that there are no old keys
-      for (let key of Object.keys(restoredFormData)) {
-        if (["id", "xpath", "url"].indexOf(key) === -1) {
-          ok(false, "FormData format is invalid.");
-        }
+    // test format
+    ok("id" in restoredFormData || "xpath" in restoredFormData,
+       "FormData format is valid: " + restoredFormData);
+    // validate that there are no old keys
+    for (let key of Object.keys(restoredFormData)) {
+      if (["id", "xpath", "url"].indexOf(key) === -1) {
+        ok(false, "FormData format is invalid.");
       }
-      // test id
-      is(input1.value, aExpectedValue[0],
-        "FormData by 'id' has been restored correctly");
-      // test xpath
-      is(input2.value, aExpectedValue[1],
-        "FormData by 'xpath' has been restored correctly");
     }
-
-    // clean up
-    gBrowser.removeTab(tab);
+    // test id
+    is(input1.value, aExpectedValue[0],
+       "FormData by 'id' has been restored correctly");
+    // test xpath
+    is(input2.value, aExpectedValue[1],
+       "FormData by 'xpath' has been restored correctly");
+  }
 
-  // This test might time out if the task fails.
-  }).then(aCallback);
+  // clean up
+  gBrowser.removeTab(tab);
 }
--- a/browser/components/sessionstore/test/browser_formdata_xpath.js
+++ b/browser/components/sessionstore/test/browser_formdata_xpath.js
@@ -33,17 +33,17 @@ const FIELDS = {
   "//select[@multiple]":        [1, 3],
   "//textarea[1]":              "",
   "//textarea[2]":              "Some text... " + Math.random(),
   "//textarea[3]":              "Some more text\n" + new Date(),
   "//input[@type='file'][1]":   [FILE1],
   "//input[@type='file'][2]":   [FILE1, FILE2]
 };
 
-add_task(function test_form_data_restoration() {
+add_task(function* test_form_data_restoration() {
   // Load page with some input fields.
   let tab = gBrowser.addTab(URL);
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
   // Fill in some values.
   for (let xpath of Object.keys(FIELDS)) {
     yield setFormValue(browser, xpath);
--- a/browser/components/sessionstore/test/browser_frame_history.js
+++ b/browser/components/sessionstore/test/browser_frame_history.js
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /**
  Ensure that frameset history works properly when restoring a tab,
  provided that the frameset is static.
  */
 
 // Loading a toplevel frameset
-add_task(function() {
+add_task(function*() {
   let testURL = getRootDirectory(gTestPath) + "browser_frame_history_index.html";
   let tab = gBrowser.addTab(testURL);
   gBrowser.selectedTab = tab;
 
   info("Opening a page with three frames, 4 loads should take place");
   yield waitForLoadsInBrowser(tab.linkedBrowser, 4);
 
   let browser_b = tab.linkedBrowser.contentDocument.getElementsByTagName("frame")[1];
@@ -46,17 +46,17 @@ add_task(function() {
     is(frames[i].contentDocument.location,
        getRootDirectory(gTestPath) + "browser_frame_history_" + expectedURLEnds[i],
        "frame " + i + " has the right url");
   }
   gBrowser.removeTab(newTab);
 });
 
 // Loading the frameset inside an iframe
-add_task(function() {
+add_task(function*() {
   let testURL = getRootDirectory(gTestPath) + "browser_frame_history_index2.html";
   let tab = gBrowser.addTab(testURL);
   gBrowser.selectedTab = tab;
 
   info("iframe: Opening a page with an iframe containing three frames, 5 loads should take place");
   yield waitForLoadsInBrowser(tab.linkedBrowser, 5);
 
   let browser_b = tab.linkedBrowser.contentDocument.
@@ -93,17 +93,17 @@ add_task(function() {
     is(frames[i].contentDocument.location,
        getRootDirectory(gTestPath) + "browser_frame_history_" + expectedURLEnds[i],
        "frame " + i + " has the right url");
   }
   gBrowser.removeTab(newTab);
 });
 
 // Now, test that we don't record history if the iframe is added dynamically
-add_task(function() {
+add_task(function*() {
   // Start with an empty history
     let blankState = JSON.stringify({
       windows: [{
         tabs: [{ entries: [{ url: "about:blank" }] }],
         _closedTabs: []
       }],
       _closedWindows: []
     });
--- a/browser/components/sessionstore/test/browser_frametree.js
+++ b/browser/components/sessionstore/test/browser_frametree.js
@@ -8,17 +8,17 @@ const URL_FRAMESET = HTTPROOT + "browser
 
 /**
  * This ensures that loading a page normally, aborting a page load, reloading
  * a page, navigating using the bfcache, and ignoring frames that were
  * created dynamically work as expect. We expect the frame tree to be reset
  * when a page starts loading and we also expect a valid frame tree to exist
  * when it has stopped loading.
  */
-add_task(function test_frametree() {
+add_task(function* test_frametree() {
   const FRAME_TREE_SINGLE = { href: URL };
   const FRAME_TREE_FRAMESET = {
     href: URL_FRAMESET,
     children: [{href: URL}, {href: URL}, {href: URL}]
   };
 
   // Create a tab with a single frame.
   let tab = gBrowser.addTab(URL);
@@ -60,17 +60,17 @@ add_task(function test_frametree() {
   gBrowser.removeTab(tab);
 });
 
 /**
  * This test ensures that we ignore frames that were created dynamically at or
  * after the load event. SessionStore can't handle these and will not restore
  * or collect any data for them.
  */
-add_task(function test_frametree_dynamic() {
+add_task(function* test_frametree_dynamic() {
   // The frame tree as expected. The first two frames are static
   // and the third one was created on DOMContentLoaded.
   const FRAME_TREE = {
     href: URL_FRAMESET,
     children: [{href: URL}, {href: URL}, {href: URL}]
   };
   const FRAME_TREE_REMOVED = {
     href: URL_FRAMESET,
--- a/browser/components/sessionstore/test/browser_history_persist.js
+++ b/browser/components/sessionstore/test/browser_history_persist.js
@@ -2,17 +2,17 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 /**
  * Ensure that history entries that should not be persisted are restored in the
  * same state.
  */
-add_task(function check_history_not_persisted() {
+add_task(function* check_history_not_persisted() {
   // Create an about:blank tab
   let tab = gBrowser.addTab("about:blank");
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
   // Retrieve the tab state.
   yield TabStateFlusher.flush(browser);
   let state = JSON.parse(ss.getTabState(tab));
@@ -39,17 +39,17 @@ add_task(function check_history_not_pers
   // Cleanup.
   gBrowser.removeTab(tab);
 });
 
 /**
  * Check that entries default to being persisted when the attribute doesn't
  * exist
  */
-add_task(function check_history_default_persisted() {
+add_task(function* check_history_default_persisted() {
   // Create an about:blank tab
   let tab = gBrowser.addTab("about:blank");
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
   // Retrieve the tab state.
   yield TabStateFlusher.flush(browser);
   let state = JSON.parse(ss.getTabState(tab));
--- a/browser/components/sessionstore/test/browser_label_and_icon.js
+++ b/browser/components/sessionstore/test/browser_label_and_icon.js
@@ -15,17 +15,17 @@ add_task(function setup() {
   registerCleanupFunction(() => {
     Services.prefs.clearUserPref("browser.sessionstore.restore_on_demand");
   });
 });
 
 /**
  * Ensure that a pending tab has label and icon correctly set.
  */
-add_task(function test_label_and_icon() {
+add_task(function* test_label_and_icon() {
   // Create a new tab.
   let tab = gBrowser.addTab("about:robots");
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
   // Retrieve the tab state.
   yield TabStateFlusher.flush(browser);
   let state = ss.getTabState(tab);
--- a/browser/components/sessionstore/test/browser_merge_closed_tabs.js
+++ b/browser/components/sessionstore/test/browser_merge_closed_tabs.js
@@ -1,16 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * This test ensures that closed tabs are merged when restoring
  * a window state without overwriting tabs.
  */
-add_task(function () {
+add_task(function* () {
   const initialState = {
     windows: [{
       tabs: [
         { entries: [{ url: "about:blank" }] }
       ],
       _closedTabs: [
         { state: { entries: [{ ID: 1000, url: "about:blank" }]} },
         { state: { entries: [{ ID: 1001, url: "about:blank" }]} }
--- a/browser/components/sessionstore/test/browser_pageStyle.js
+++ b/browser/components/sessionstore/test/browser_pageStyle.js
@@ -4,17 +4,17 @@
 "use strict";
 
 const URL = getRootDirectory(gTestPath) + "browser_pageStyle_sample.html";
 const URL_NESTED = getRootDirectory(gTestPath) + "browser_pageStyle_sample_nested.html";
 
 /**
  * This test ensures that page style information is correctly persisted.
  */
-add_task(function page_style() {
+add_task(function* page_style() {
   let tab = gBrowser.addTab(URL);
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
   let sheets = yield getStyleSheets(browser);
 
   // Enable all style sheets one by one.
   for (let [title, disabled] of sheets) {
     yield enableStyleSheetsForSet(browser, title);
@@ -48,17 +48,17 @@ add_task(function page_style() {
   gBrowser.removeTab(tab);
   gBrowser.removeTab(tab2);
 });
 
 /**
  * This test ensures that page style notification from nested documents are
  * received and the page style is persisted correctly.
  */
-add_task(function nested_page_style() {
+add_task(function* nested_page_style() {
   let tab = gBrowser.addTab(URL_NESTED);
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
   yield enableSubDocumentStyleSheetsForSet(browser, "alternate");
   yield promiseRemoveTab(tab);
 
   let [{state: {pageStyle}}] = JSON.parse(ss.getClosedTabData(window));
--- a/browser/components/sessionstore/test/browser_privatetabs.js
+++ b/browser/components/sessionstore/test/browser_privatetabs.js
@@ -3,17 +3,17 @@
 
 add_task(function cleanup() {
   info("Forgetting closed tabs");
   while (ss.getClosedTabCount(window)) {
     ss.forgetClosedTab(window, 0);
   }
 });
 
-add_task(function() {
+add_task(function*() {
   let URL_PUBLIC = "http://example.com/public/" + Math.random();
   let URL_PRIVATE = "http://example.com/private/" + Math.random();
   let tab1, tab2;
   try {
     // Setup a public tab and a private tab
     info("Setting up public tab");
     tab1 = gBrowser.addTab(URL_PUBLIC);
     yield promiseBrowserLoaded(tab1.linkedBrowser);
@@ -54,17 +54,17 @@ add_task(function() {
       gBrowser.removeTab(tab1);
     }
     if (tab2) {
       gBrowser.removeTab(tab2);
     }
   }
 });
 
-add_task(function () {
+add_task(function* () {
   const FRAME_SCRIPT = "data:," +
     "docShell.QueryInterface%28Components.interfaces.nsILoadContext%29.usePrivateBrowsing%3Dtrue";
 
   // Clear the list of closed windows.
   forgetClosedWindows();
 
   // Create a new window to attach our frame script to.
   let win = yield promiseNewWindowLoaded();
@@ -96,17 +96,17 @@ add_task(function () {
   ok(state.isPrivate, "tab considered private");
 
   // Check that all private tabs are removed when the non-private
   // window is closed and we don't save windows without any tabs.
   yield BrowserTestUtils.closeWindow(win);
   is(ss.getClosedWindowCount(), 0, "no windows to restore");
 });
 
-add_task(function () {
+add_task(function* () {
   // Clear the list of closed windows.
   forgetClosedWindows();
 
   // Create a new window to attach our frame script to.
   let win = yield promiseNewWindowLoaded({private: true});
 
   // Create a new tab in the new window that will load the frame script.
   let tab = win.gBrowser.addTab("about:mozilla");
--- a/browser/components/sessionstore/test/browser_restore_redirect.js
+++ b/browser/components/sessionstore/test/browser_restore_redirect.js
@@ -1,17 +1,17 @@
 "use strict";
 
 const BASE = "http://example.com/browser/browser/components/sessionstore/test/";
 const TARGET = BASE + "restore_redirect_target.html";
 
 /**
  * Ensure that a http redirect leaves a working tab.
  */
-add_task(function check_http_redirect() {
+add_task(function* check_http_redirect() {
   let state = {
     entries: [{ url: BASE + "restore_redirect_http.html" }]
   };
 
   // Open a new tab to restore into.
   let tab = gBrowser.addTab("about:blank");
   let browser = tab.linkedBrowser;
   yield promiseTabState(tab, state);
@@ -27,17 +27,17 @@ add_task(function check_http_redirect() 
 
   // Cleanup.
   yield promiseRemoveTab(tab);
 });
 
 /**
  * Ensure that a js redirect leaves a working tab.
  */
-add_task(function check_js_redirect() {
+add_task(function* check_js_redirect() {
   let state = {
     entries: [{ url: BASE + "restore_redirect_js.html" }]
   };
 
   let loadPromise = new Promise(resolve => {
     function listener(msg) {
       if (msg.data.url.endsWith("restore_redirect_target.html")) {
         window.messageManager.removeMessageListener("ss-test:loadEvent", listener);
--- a/browser/components/sessionstore/test/browser_scrollPositions.js
+++ b/browser/components/sessionstore/test/browser_scrollPositions.js
@@ -17,17 +17,17 @@ const SCROLL2_Y = Math.round(400 * (1 + 
 const SCROLL2_STR = SCROLL2_X + "," + SCROLL2_Y;
 
 requestLongerTimeout(2);
 
 /**
  * This test ensures that we properly serialize and restore scroll positions
  * for an average page without any frames.
  */
-add_task(function test_scroll() {
+add_task(function* test_scroll() {
   let tab = gBrowser.addTab(URL);
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
   // Scroll down a little.
   yield sendMessage(browser, "ss-test:setScrollPosition", {x: SCROLL_X, y: SCROLL_Y});
   yield checkScroll(tab, {scroll: SCROLL_STR}, "scroll is fine");
 
@@ -60,17 +60,17 @@ add_task(function test_scroll() {
   yield promiseRemoveTab(tab);
   yield promiseRemoveTab(tab2);
 });
 
 /**
  * This tests ensures that we properly serialize and restore scroll positions
  * for multiple frames of pages with framesets.
  */
-add_task(function test_scroll_nested() {
+add_task(function* test_scroll_nested() {
   let tab = gBrowser.addTab(URL_FRAMESET);
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
   // Scroll the first child frame down a little.
   yield sendMessage(browser, "ss-test:setScrollPosition", {x: SCROLL_X, y: SCROLL_Y, frame: 0});
   yield checkScroll(tab, {children: [{scroll: SCROLL_STR}]}, "scroll is fine");
 
@@ -104,17 +104,17 @@ add_task(function test_scroll_nested() {
   yield promiseRemoveTab(tab);
   yield promiseRemoveTab(tab2);
 });
 
 /**
  * Test that scroll positions persist after restoring background tabs in
  * a restored window (bug 1228518).
  */
-add_task(function test_scroll_background_tabs() {
+add_task(function* test_scroll_background_tabs() {
   pushPrefs(["browser.sessionstore.restore_on_demand", true]);
 
   let newWin = yield BrowserTestUtils.openNewBrowserWindow();
   let tab = newWin.gBrowser.addTab(URL);
   let browser = tab.linkedBrowser;
   yield BrowserTestUtils.browserLoaded(browser);
 
   // Scroll down a little.
--- a/browser/components/sessionstore/test/browser_scrollPositionsReaderMode.js
+++ b/browser/components/sessionstore/test/browser_scrollPositionsReaderMode.js
@@ -12,17 +12,17 @@ const SCROLL_READER_MODE_Y = Math.round(
 const SCROLL_READER_MODE_STR = "0," + SCROLL_READER_MODE_Y;
 
 requestLongerTimeout(2);
 
 /**
  * Test that scroll positions of about reader page after restoring background
  * tabs in a restored window (bug 1153393).
  */
-add_task(function test_scroll_background_about_reader_tabs() {
+add_task(function* test_scroll_background_about_reader_tabs() {
   pushPrefs(["browser.sessionstore.restore_on_demand", true]);
 
   let newWin = yield BrowserTestUtils.openNewBrowserWindow();
   let tab = newWin.gBrowser.addTab(READER_MODE_URL);
   let browser = tab.linkedBrowser;
   yield Promise.all([
     BrowserTestUtils.browserLoaded(browser),
     BrowserTestUtils.waitForContentEvent(browser, "AboutReaderContentReady")
--- a/browser/components/sessionstore/test/browser_sessionHistory.js
+++ b/browser/components/sessionstore/test/browser_sessionHistory.js
@@ -3,17 +3,17 @@
 
 "use strict";
 
 requestLongerTimeout(2);
 
 /**
  * Ensure that starting a load invalidates shistory.
  */
-add_task(function test_load_start() {
+add_task(function* test_load_start() {
   // Create a new tab.
   let tab = gBrowser.addTab("about:blank");
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
   // Load a new URI.
   yield BrowserTestUtils.loadURI(browser, "about:mozilla");
 
@@ -31,17 +31,17 @@ add_task(function test_load_start() {
 
   // Cleanup.
   gBrowser.removeTab(tab);
 });
 
 /**
  * Ensure that anchor navigation invalidates shistory.
  */
-add_task(function test_hashchange() {
+add_task(function* test_hashchange() {
   const URL = "data:text/html;charset=utf-8,<a id=a href=%23>clickme</a>";
 
   // Create a new tab.
   let tab = gBrowser.addTab(URL);
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
   // Check that we start with a single shistory entry.
@@ -60,17 +60,17 @@ add_task(function test_hashchange() {
 
   // Cleanup.
   gBrowser.removeTab(tab);
 });
 
 /**
  * Ensure that loading pages from the bfcache invalidates shistory.
  */
-add_task(function test_pageshow() {
+add_task(function* test_pageshow() {
   const URL = "data:text/html;charset=utf-8,<h1>first</h1>";
   const URL2 = "data:text/html;charset=utf-8,<h1>second</h1>";
 
   // Create a new tab.
   let tab = gBrowser.addTab(URL);
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
@@ -90,17 +90,17 @@ add_task(function test_pageshow() {
 
   // Cleanup.
   gBrowser.removeTab(tab);
 });
 
 /**
  * Ensure that subframe navigation invalidates shistory.
  */
-add_task(function test_subframes() {
+add_task(function* test_subframes() {
   const URL = "data:text/html;charset=utf-8," +
               "<iframe src=http%3A//example.com/ name=t></iframe>" +
               "<a id=a1 href=http%3A//example.com/1 target=t>clickme</a>" +
               "<a id=a2 href=http%3A//example.com/%23 target=t>clickme</a>";
 
   // Create a new tab.
   let tab = gBrowser.addTab(URL);
   let browser = tab.linkedBrowser;
@@ -138,17 +138,17 @@ add_task(function test_subframes() {
 
   // Cleanup.
   gBrowser.removeTab(tab);
 });
 
 /**
  * Ensure that navigating from an about page invalidates shistory.
  */
-add_task(function test_about_page_navigate() {
+add_task(function* test_about_page_navigate() {
   // Create a new tab.
   let tab = gBrowser.addTab("about:blank");
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
   // Check that we have a single shistory entry.
   yield TabStateFlusher.flush(browser);
   let {entries} = JSON.parse(ss.getTabState(tab));
@@ -166,17 +166,17 @@ add_task(function test_about_page_naviga
 
   // Cleanup.
   gBrowser.removeTab(tab);
 });
 
 /**
  * Ensure that history.pushState and history.replaceState invalidate shistory.
  */
-add_task(function test_pushstate_replacestate() {
+add_task(function* test_pushstate_replacestate() {
   // Create a new tab.
   let tab = gBrowser.addTab("http://example.com/1");
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
   // Check that we have a single shistory entry.
   yield TabStateFlusher.flush(browser);
   let {entries} = JSON.parse(ss.getTabState(tab));
@@ -205,17 +205,17 @@ add_task(function test_pushstate_replace
 
   // Cleanup.
   gBrowser.removeTab(tab);
 });
 
 /**
  * Ensure that slow loading subframes will invalidate shistory.
  */
-add_task(function test_slow_subframe_load() {
+add_task(function* test_slow_subframe_load() {
   const SLOW_URL = "http://mochi.test:8888/browser/browser/components/" +
                    "sessionstore/test/browser_sessionHistory_slow.sjs";
 
   const URL = "data:text/html;charset=utf-8," +
               "<frameset cols=50%25,50%25>" +
               "<frame src='" + SLOW_URL + "'>" +
               "</frameset>";
 
--- a/browser/components/sessionstore/test/browser_sessionStorage.js
+++ b/browser/components/sessionstore/test/browser_sessionStorage.js
@@ -10,17 +10,17 @@ const URL = "http://mochi.test:8888/brow
 
 const OUTER_VALUE = "outer-value-" + RAND;
 const INNER_VALUE = "inner-value-" + RAND;
 
 /**
  * This test ensures that setting, modifying and restoring sessionStorage data
  * works as expected.
  */
-add_task(function session_storage() {
+add_task(function* session_storage() {
   let tab = gBrowser.addTab(URL);
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
   // Flush to make sure chrome received all data.
   yield TabStateFlusher.flush(browser);
 
   let {storage} = JSON.parse(ss.getTabState(tab));
@@ -97,17 +97,17 @@ add_task(function session_storage() {
   yield promiseRemoveTab(tab);
   yield promiseRemoveTab(tab2);
 });
 
 /**
  * This test ensures that purging domain data also purges data from the
  * sessionStorage data collected for tabs.
  */
-add_task(function purge_domain() {
+add_task(function* purge_domain() {
   let tab = gBrowser.addTab(URL);
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
   // Purge data for "mochi.test".
   yield purgeDomainData(browser, "mochi.test");
 
   // Flush to make sure chrome received all data.
@@ -121,17 +121,17 @@ add_task(function purge_domain() {
 
   yield promiseRemoveTab(tab);
 });
 
 /**
  * This test ensures that collecting sessionStorage data respects the privacy
  * levels as set by the user.
  */
-add_task(function respect_privacy_level() {
+add_task(function* respect_privacy_level() {
   let tab = gBrowser.addTab(URL + "&secure");
   yield promiseBrowserLoaded(tab.linkedBrowser);
   yield promiseRemoveTab(tab);
 
   let [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window));
   is(storage["http://mochi.test:8888"].test, OUTER_VALUE,
     "http sessionStorage data has been saved");
   is(storage["https://example.com"].test, INNER_VALUE,
--- a/browser/locales/en-US/chrome/overrides/netError.dtd
+++ b/browser/locales/en-US/chrome/overrides/netError.dtd
@@ -192,20 +192,20 @@ was trying to connect. -->
 <!ENTITY weakCryptoUsed.title "Your connection is not secure">
 <!-- LOCALIZATION NOTE (weakCryptoUsed.longDesc2) - Do not translate
      "SSL_ERROR_NO_CYPHER_OVERLAP". -->
 <!ENTITY weakCryptoUsed.longDesc2 "Advanced info: SSL_ERROR_NO_CYPHER_OVERLAP">
 <!ENTITY weakCryptoAdvanced.title "Advanced">
 <!ENTITY weakCryptoAdvanced.longDesc "<span class='hostname'></span> uses security technology that is outdated and vulnerable to attack. An attacker could easily reveal information which you thought to be safe.">
 <!ENTITY weakCryptoAdvanced.override "(Not secure) Try loading <span class='hostname'></span> using outdated security">
 
-<!-- LOCALIZATION NOTE (certerror.wrongSystemTime,
+<!-- LOCALIZATION NOTE (certerror.wrongSystemTime2,
                         certerror.wrongSystemTimeWithoutReference) - The <span id='..' />
      tags will be injected with actual values, please leave them unchanged. -->
-<!ENTITY certerror.wrongSystemTime "<p> &brandShortName; did not connect to <span id='wrongSystemTime_URL'/> because your computer’s clock appears to show the wrong time and this is preventing a secure connection.</p> <p>Your computer is set to <span id='wrongSystemTime_systemDate'/>, when it should be <span id='wrongSystemTime_actualDate'/>. To fix this problem, change your date and time settings to match the correct time.</p>">
+<!ENTITY certerror.wrongSystemTime2 "<p> &brandShortName; did not connect to <span id='wrongSystemTime_URL'/> because your computer’s clock appears to show the wrong time and this is preventing a secure connection.</p> <p>Your computer is set to <span id='wrongSystemTime_systemDate'/>, when it should be <span id='wrongSystemTime_actualDate'/>. To fix this problem, change your date and time settings to match the correct time.</p>">
 <!ENTITY certerror.wrongSystemTimeWithoutReference "<p>&brandShortName; did not connect to <span id='wrongSystemTimeWithoutReference_URL'/> because your computer’s clock appears to show the wrong time and this is preventing a secure connection.</p> <p>Your computer is set to <span id='wrongSystemTimeWithoutReference_systemDate'/>. To fix this problem, change your date and time settings to match the correct time.</p>">
 
 <!ENTITY certerror.pagetitle1  "Insecure Connection">
 <!ENTITY certerror.whatShouldIDo.badStsCertExplanation "This site uses HTTP
 Strict Transport Security (HSTS) to specify that &brandShortName; may only connect
 to it securely. As a result, it is not possible to add an exception for this
 certificate.">
 <!ENTITY certerror.copyToClipboard.label "Copy text to clipboard">
--- a/browser/modules/ExtensionsUI.jsm
+++ b/browser/modules/ExtensionsUI.jsm
@@ -248,29 +248,23 @@ this.ExtensionsUI = {
       }
 
       format(wildcards, "webextPerms.hostDescription.wildcard",
              "webextPerms.hostDescription.tooManyWildcards");
       format(sites, "webextPerms.hostDescription.oneSite",
              "webextPerms.hostDescription.tooManySites");
     }
 
-    let rendered = false;
     let popupOptions = {
       hideClose: true,
       popupIconURL: info.icon,
       persistent: true,
 
       eventCallback(topic) {
         if (topic == "showing") {
-          // This check can be removed when bug 1325223 is resolved.
-          if (rendered) {
-            return false;
-          }
-
           let doc = this.browser.ownerDocument;
           doc.getElementById("addon-webext-perm-header").innerHTML = header;
 
           if (text) {
             doc.getElementById("addon-webext-perm-text").innerHTML = text;
           }
 
           let listIntroEl = doc.getElementById("addon-webext-perm-intro");
@@ -282,21 +276,17 @@ this.ExtensionsUI = {
             list.firstChild.remove();
           }
 
           for (let msg of msgs) {
             let item = doc.createElementNS(HTML_NS, "li");
             item.textContent = msg;
             list.appendChild(item);
           }
-          rendered = true;
-        } else if (topic == "dismissed") {
-          rendered = false;
         } else if (topic == "swapping") {
-          rendered = false;
           return true;
         }
         return false;
       },
     };
 
     return new Promise(resolve => {
       win.PopupNotifications.show(target, "addon-webext-permissions", "",
--- a/browser/tools/mozscreenshots/head.js
+++ b/browser/tools/mozscreenshots/head.js
@@ -29,27 +29,36 @@ function* setup() {
       isnot(aAddon, null, "The mozscreenshots extension should be installed");
       AddonWatcher.ignoreAddonPermanently(aAddon.id);
       TestRunner = Cu.import("chrome://mozscreenshots/content/TestRunner.jsm", {}).TestRunner;
       resolve();
     });
   });
 }
 
+/**
+ * Used by pre-defined sets of configurations to decide whether to run for a build.
+ * @note This is not used by browser_screenshots.js which handles when MOZSCREENSHOTS_SETS is set.
+ * @return {bool} whether to capture screenshots.
+ */
 function shouldCapture() {
-  // Try pushes only capture in browser_screenshots.js with MOZSCREENSHOTS_SETS.
   if (env.get("MOZSCREENSHOTS_SETS")) {
     ok(true, "MOZSCREENSHOTS_SETS was specified so only capture what was " +
        "requested (in browser_screenshots.js)");
     return false;
   }
 
-  // Automation isn't able to schedule test jobs to only run on nightlies so we handle it here
-  // (see also: bug 1116275).
-  let capture = AppConstants.MOZ_UPDATE_CHANNEL == "nightly" ||
-                AppConstants.SOURCE_REVISION_URL == "";
+  if (AppConstants.MOZ_UPDATE_CHANNEL == "nightly") {
+    ok(true, "Screenshots aren't captured on Nightlies");
+    return false;
+  }
+
+  // Don't run pre-defined sets (e.g. primaryUI) on try, require MOZSCREENSHOTS_SETS.
+  // The job is only scheduled on specific repos:
+  // https://dxr.mozilla.org/build-central/search?q=MOCHITEST_BC_SCREENSHOTS
+  let capture = !AppConstants.SOURCE_REVISION_URL.includes("/try/rev/");
   if (!capture) {
-    ok(true, "Capturing is disabled for this MOZ_UPDATE_CHANNEL or REPO");
+    ok(true, "Capturing is disabled for this REPO. You may need to use MOZSCREENSHOTS_SETS");
   }
   return capture;
 }
 
 add_task(setup);
--- a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/LightweightThemes.jsm
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/LightweightThemes.jsm
@@ -66,22 +66,10 @@ this.LightweightThemes = {
         // Wait for LWT listener
         return new Promise(resolve => {
           setTimeout(() => {
             resolve("lightLWT");
           }, 500);
         });
       },
     },
-
-    compactLight: {
-      applyConfig: Task.async(() => {
-        LightweightThemeManager.currentTheme = LightweightThemeManager.getUsedTheme("firefox-compact-light@mozilla.org");
-      }),
-    },
-
-    compactDark: {
-      applyConfig: Task.async(() => {
-        LightweightThemeManager.currentTheme = LightweightThemeManager.getUsedTheme("firefox-compact-dark@mozilla.org");
-      }),
-    },
   },
 };
--- a/devtools/client/debugger/new/debugger.css
+++ b/devtools/client/debugger/new/debugger.css
@@ -15,167 +15,201 @@ body {
   width: 100%;
 }
 
 #mount {
   display: flex;
   height: 100%;
 }
 
-
 ::-webkit-scrollbar {
   width: 8px;
   height: 8px;
   background: transparent;
 }
 
 ::-webkit-scrollbar-track {
   border-radius: 8px;
   background: transparent;
 }
 
 ::-webkit-scrollbar-thumb {
   border-radius: 8px;
-  background: rgba(113,113,113,0.5);
+  background: rgba(113, 113, 113, 0.5);
 }
 
 :root.theme-dark .CodeMirror-scrollbar-filler {
   background: transparent;
 }
 .landing-page {
   flex: 1;
   display: flex;
-  width: 100%;
-  height: 100%;
+  width: 100vw;
+  height: 100vh;
   flex-direction: row;
+  align-items: stretch;
+  /* Customs properties */
+  --title-font-size: 24px;
+  --ui-element-font-size: 16px;
+  --primary-line-height: 30px;
+  --secondary-line-height: 25px;
+  --base-spacing: 20px;
+  --base-transition: all 0.25s ease;
 }
 
 .landing-page .sidebar {
   display: flex;
   background-color: var(--theme-tab-toolbar-background);
   width: 200px;
-  height: 100%;
   flex-direction: column;
+  border-right: 1px solid var(--theme-splitter-color);
 }
 
 .landing-page .sidebar h1 {
   color: var(--theme-body-color);
-  font-size: 24px;
+  font-size: var(--title-font-size);
   margin: 0;
-  line-height: 30px;
+  line-height: var(--primary-line-height);
   font-weight: normal;
-  padding: 40px 20px;
+  padding: calc(2 * var(--base-spacing)) var(--base-spacing);
 }
 
 .landing-page .sidebar ul {
   list-style: none;
   padding: 0;
-  line-height: 30px;
-  font-size: 18px;
+  line-height: var(--primary-line-height);
+  font-size: var(--ui-element-font-size);
 }
 
 .landing-page .sidebar li {
-  padding: 5px 20px;
-}
-
-.landing-page .sidebar li.selected {
-  background: var(--theme-search-overlays-semitransparent);
-  transition: all 0.25s ease;
-}
-
-.landing-page .sidebar li:hover {
-  background: var(--theme-selection-background);
-  cursor: pointer;
+  padding: calc(var(--base-spacing) / 4) var(--base-spacing);
 }
 
 .landing-page .sidebar li a {
   color: var(--theme-body-color);
 }
 
-.landing-page .sidebar li:hover a {
+.landing-page .sidebar li.selected {
+  background: var(--theme-highlight-bluegrey);
   color: var(--theme-selection-color);
+  transition: var(--base-transition);
+}
+
+.landing-page .sidebar li.selected a {
+  color: inherit;
+}
+
+.landing-page .sidebar li:hover,
+.landing-page .sidebar li:focus {
+  background: var(--theme-selection-background);
+  color: var(--theme-selection-color);
+  cursor: pointer;
+}
+
+.landing-page .sidebar li:hover a,
+.landing-page .sidebar li:focus a {
+  color: inherit;
 }
 
 .landing-page .panel {
   display: flex;
   flex: 1;
-  height: 100%;
-  overflow: auto;
   flex-direction: column;
+  justify-content: space-between;
 }
 
-.landing-page .panel .title {
-  margin: 20px 40px;
-  width: calc(100% - 80px);
-  font-size: 16px;
-  border-bottom: 1px solid var(--theme-splitter-color);
-  height: 54px;
+.landing-page .panel header {
+  display: flex;
+  align-items: baseline;
+  margin: calc(2 * var(--base-spacing)) 0 0;
+  padding-bottom: var(--base-spacing);
 }
 
-.landing-page .panel h2 {
-  color: var(--theme-body-color);
-  font-weight: normal;
+.landing-page .panel header input {
+  flex: 1;
+  background-color: var(--theme-tab-toolbar-background);
+  color: var(--theme-comment);
+  font-size: var(--ui-element-font-size);
+  border: 1px solid var(--theme-splitter-color);
+  padding: calc(var(--base-spacing) / 2);
+  margin: 0 var(--base-spacing);
+  transition: var(--base-transition);
 }
 
-.landing-page .panel .center {
-  flex: 1;
-  display: flex;
-  flex-direction: column;
+.landing-page .panel header input::placeholder {
+  color: var(--theme-body-color-inactive);
 }
 
-.landing-page .panel .center .center-message {
-  margin: 40px;
-  font-size: 16px;
-  line-height: 25px;
-  padding: 10px;
+.landing-page .panel header input:focus {
+  border: 1px solid var(--theme-selection-background);
+}
+
+.landing-page .panel .center-message {
+  font-size: var(--ui-element-font-size);
+  line-height: var(--secondary-line-height);
+  padding: calc(var(--base-spacing) / 2);
 }
 
 .landing-page .center a {
   color: var(--theme-highlight-bluegrey);
   text-decoration: none;
 }
 
 .landing-page .tab-group {
-  margin: 40px;
+  flex: 1;
+  overflow-y: auto;
 }
 
 .landing-page .tab-list {
   list-style: none;
-  padding: 0px;
-  margin: 0px;
+  padding: 0;
+  margin: 0;
 }
 
 .landing-page .tab {
   border-bottom: 1px solid var(--theme-splitter-color);
-  padding: 10px;
+  padding: calc(var(--base-spacing) / 2) var(--base-spacing);
   font-family: sans-serif;
 }
 
-.landing-page .tab:hover {
-  background-color: var(--theme-toolbar-background);
-  cursor: pointer;
-}
-
 .landing-page .tab-title {
-  line-height: 25px;
-  font-size: 16px;
+  line-height: var(--secondary-line-height);
+  font-size: var(--ui-element-font-size);
   color: var(--theme-highlight-bluegrey);
+  word-break: break-all;
 }
 
 .landing-page .tab-url {
   color: var(--theme-comment);
+  word-break: break-all;
+}
+
+.landing-page .tab:focus,
+.landing-page .tab.active {
+  background: var(--theme-selection-background);
+  color: var(--theme-selection-color);
+  cursor: pointer;
+  transition: var(--base-transition);
 }
 
-.landing-page .panel .center .footer-note {
-  flex: 1;
-  padding: 50px;
+.landing-page .tab:focus .tab-title,
+.landing-page .tab.active .tab-title {
+  color: inherit;
+}
+
+.landing-page .tab:focus .tab-url,
+.landing-page .tab.active .tab-url {
+  color: var(--theme-highlight-gray);
+}
+
+.landing-page .panel .footer-note {
+  padding: var(--base-spacing) 0;
+  text-align: center;
   font-size: 14px;
   color: var(--theme-comment);
-  bottom: 0;
-  position: absolute;
 }
 /* vim:set ts=2 sw=2 sts=2 et: */
 
 /* 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/. */
 
 :root.theme-light,
@@ -207,21 +241,22 @@ body {
 }
 
 .debugger {
   display: flex;
   flex: 1;
   height: 100%;
 }
 
-.center-pane {
+.editor-pane {
   display: flex;
   position: relative;
   flex: 1;
   background-color: var(--theme-tab-toolbar-background);
+  height: calc(100% - 1px);
   overflow: hidden;
 }
 
 .editor-container {
   display: flex;
   flex: 1;
 }
 
@@ -244,33 +279,16 @@ body {
   flex: 1;
 }
 
 .search-container .close-button {
   width: 16px;
   margin-top: 25px;
   margin-right: 20px;
 }
-
-.welcomebox {
-  width: calc(100% - 1px);
-
-  /* Offsetting it by 30px for the sources-header area */
-  height: calc(100% - 30px);
-  position: absolute;
-  top: 30px;
-  left: 0;
-  padding: 50px 0;
-  text-align: center;
-  font-size: 1.25em;
-  color: var(--theme-comment-alt);
-  background-color: var(--theme-tab-toolbar-background);
-  font-weight: lighter;
-  z-index: 100;
-}
 menupopup {
   position: fixed;
   z-index: 10000;
   background: white;
   border: 1px solid #cccccc;
   padding: 5px 0;
   background: #f2f2f2;
   border-radius: 5px;
@@ -280,24 +298,35 @@ menupopup {
 }
 
 menuitem {
   display: block;
   padding: 0 20px;
   line-height: 20px;
   font-weight: 500;
   font-size: 13px;
+  -moz-user-select: none;
+  user-select: none;
 }
 
 menuitem:hover {
   background: #3780fb;
   color: white;
   cursor: pointer;
 }
 
+menuitem[disabled=true] {
+  color: #cccccc;
+}
+
+menuitem[disabled=true]:hover {
+  background-color: transparent;
+  cursor: default;
+}
+
 menuseparator {
   border-bottom: 1px solid #cacdd3;
   width: 100%;
   height: 5px;
   display: block;
   margin-bottom: 5px;
 }
 
@@ -602,117 +631,85 @@ menuseparator {
 .searchinput-container {
   display: flex;
 }
 
 .searchinput-container .close-btn-big {
   border-bottom: 1px solid var(--theme-splitter-color);
 }
 
-.autocomplete {
-  width: 100%;
-}
-
-.autocomplete .results * {
-  -moz-user-select: none;
-  user-select: none;
+.arrow,
+.folder,
+.domain,
+.file,
+.worker,
+.refresh,
+.add-button {
+  fill: var(--theme-splitter-color);
 }
 
-.autocomplete .results-summary {
-  margin: 10px;
-}
-
-.autocomplete ul {
-  list-style: none;
-  width: 100%;
-  max-height: calc(100% - 32px);
-  margin: 0px;
-  padding: 0px;
-  overflow: auto;
+.worker,
+.folder {
+  position: relative;
+  top: 2px;
 }
 
-.autocomplete li {
-  border: 2px solid var(--theme-splitter-color);
-  background-color: var(--theme-tab-toolbar-background);
-  padding: 10px;
-  margin: 10px;
-}
-
-.autocomplete li:hover {
-  background: var(--theme-tab-toolbar-background);
-  cursor: pointer;
+.domain,
+.file,
+.worker,
+.refresh,
+.add-button {
+  position: relative;
+  top: 1px;
 }
 
-.autocomplete li.selected {
-  border: 2px solid var(--theme-selection-background);
-}
-
-.autocomplete li .title {
-  line-height: 1.5em;
-  word-break: break-all;
-}
-
-.autocomplete li .subtitle {
-  line-height: 1.5em;
-  color: grey;
-  word-break: break-all;
+.domain svg,
+.folder svg,
+.worker svg,
+.refresh svg,
+.add-button svg {
+  width: 15px;
 }
 
-.autocomplete input {
-  width: 100%;
-  border: none;
-  background-color: var(--theme-body-background);
-  color: var(--theme-comment);
-  border-bottom: 1px solid var(--theme-splitter-color);
-  outline: none;
-  line-height: 30px;
-  font-size: 14px;
-  height: 40px;
-  padding-left: 30px;
+.file svg {
+  width: 13px;
 }
 
-.autocomplete input::placeholder {
-  color: var(--theme-body-color-inactive);
-}
-
-.autocomplete .magnifying-glass svg {
-  width: 16px;
-  position: absolute;
-  top: 12px;
-  left: 10px;
+.file svg,
+.domain svg,
+.folder svg,
+.refresh svg,
+.worker svg {
+  margin-inline-end: 5px;
 }
 
-.autocomplete.focused .magnifying-glass path,
-.autocomplete.focused .magnifying-glass ellipse {
-  stroke: var(--theme-highlight-blue);
+.arrow svg {
+  fill: var(--theme-splitter-color);
+  margin-top: 3px;
+  transition: transform 0.25s ease;
+  width: 10px;
 }
 
-.autocomplete .magnifying-glass path,
-.autocomplete .magnifying-glass ellipse {
-  stroke: var(--theme-splitter-color);
+html:not([dir="rtl"]) .arrow svg {
+  margin-right: 5px;
+  transform: rotate(-90deg);
 }
 
-.autocomplete .no-result-msg {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  width: 100%;
-  height: 100%;
-  color: var(--theme-graphs-full-red);
-  font-size: 24px;
+html[dir="rtl"] .arrow svg {
+  margin-left: 5px;
+  transform: rotate(90deg);
 }
 
-.autocomplete .no-result-msg .sad-face {
-  width: 24px;
-  margin-right: 4px;
-  line-height: 0;
+/* TODO (Amit): html is just for specificity. keep it like this? */
+html .arrow.expanded svg {
+  transform: rotate(0deg);
 }
 
-.autocomplete .no-result-msg .sad-face svg {
-  fill: var(--theme-graphs-full-red);
+.arrow.hidden {
+  visibility: hidden;
 }
 .close-btn path {
   fill: var(--theme-body-color);
 }
 
 .close-btn .close {
   cursor: pointer;
   width: 12px;
@@ -766,16 +763,123 @@ menuseparator {
 .close-btn-big .close:hover {
   background: var(--theme-selection-background);
   border-radius: 2px;
 }
 
 .close-btn-big .close:hover path {
   fill: white;
 }
+
+.autocomplete {
+  width: 100%;
+}
+
+.autocomplete .results * {
+  -moz-user-select: none;
+  user-select: none;
+}
+
+.autocomplete .results-summary {
+  margin: 10px;
+  text-align: start;
+}
+
+.autocomplete ul {
+  list-style: none;
+  width: 100%;
+  max-height: calc(100% - 32px);
+  margin: 0px;
+  padding: 0px;
+  overflow: auto;
+}
+
+.autocomplete li {
+  border: 2px solid var(--theme-splitter-color);
+  background-color: var(--theme-tab-toolbar-background);
+  padding: 10px;
+  margin: 10px;
+}
+
+.autocomplete li:hover {
+  background: var(--theme-tab-toolbar-background);
+  cursor: pointer;
+}
+
+.autocomplete li.selected {
+  border: 2px solid var(--theme-selection-background);
+}
+
+.autocomplete li .title {
+  line-height: 1.5em;
+  word-break: break-all;
+}
+
+.autocomplete li .subtitle {
+  line-height: 1.5em;
+  color: grey;
+  word-break: break-all;
+}
+
+.autocomplete input {
+  width: 100%;
+  border: none;
+  background-color: var(--theme-body-background);
+  color: var(--theme-comment);
+  border-bottom: 1px solid var(--theme-splitter-color);
+  outline: none;
+  line-height: 30px;
+  font-size: 14px;
+  height: 40px;
+  padding-inline-start: 30px;
+}
+
+.autocomplete input::placeholder {
+  color: var(--theme-body-color-inactive);
+}
+
+.autocomplete .magnifying-glass svg {
+  width: 16px;
+  position: absolute;
+  top: 12px;
+  offset-inline-start: 10px;
+}
+
+.autocomplete.focused .magnifying-glass path,
+.autocomplete.focused .magnifying-glass ellipse {
+  stroke: var(--theme-highlight-blue);
+}
+
+.autocomplete .magnifying-glass path,
+.autocomplete .magnifying-glass ellipse {
+  stroke: var(--theme-splitter-color);
+}
+
+.autocomplete .no-result-msg {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+  height: 100%;
+  color: var(--theme-graphs-full-red);
+  font-size: 24px;
+  padding: 4px;
+  word-break: break-all;
+}
+
+.autocomplete .no-result-msg .sad-face {
+  width: 24px;
+  margin: 0 4px;
+  line-height: 0;
+  flex-shrink: 0;
+}
+
+.autocomplete .no-result-msg .sad-face svg {
+  fill: var(--theme-graphs-full-red);
+}
 .tree {
   -webkit-user-select: none;
   -moz-user-select: none;
   -ms-user-select: none;
   -o-user-select: none;
   user-select: none;
 
   flex: 1;
@@ -828,97 +932,40 @@ html[dir="rtl"] .tree .node > div {
   height: 30px;
   border-bottom: 1px solid var(--theme-splitter-color);
   padding-top: 0px;
   padding-bottom: 0px;
   line-height: 30px;
   font-size: 1.2em;
   display: flex;
   align-items: baseline;
-  justify-content: space-between;
   -moz-user-select: none;
   user-select: none;
+  justify-content: flex-end;
 }
 
-html:not([dir="rtl"]) .sources-header {
-  padding-left: 10px;
-}
-
-html[dir="rtl"] .sources-header {
-  padding-right: 10px;
+.sources-header {
+  padding-inline-start: 10px;
 }
 
 .sources-header-info {
   font-size: 12px;
   color: var(--theme-comment-alt);
   font-weight: lighter;
   white-space: nowrap;
-}
-
-html:not([dir="rtl"]) .sources-header-info {
-  padding-right: 10px;
-  float: right;
-}
-
-html[dir="rtl"] .sources-header-info {
-  padding-left: 10px;
-  float: left;
+  padding-inline-end: 10px;
+  cursor: pointer;
 }
 
 .sources-list {
   flex: 1;
   display: flex;
   overflow: hidden;
 }
 
-.arrow,
-.folder,
-.domain,
-.file,
-.worker {
-  fill: var(--theme-splitter-color);
-}
-
-.domain,
-.file,
-.worker {
-  position: relative;
-  top: 1px;
-}
-
-.worker,
-.folder {
-  position: relative;
-  top: 2px;
-}
-
-.domain svg,
-.folder svg,
-.worker svg {
-  width: 15px;
-}
-
-.file svg {
-  width: 13px;
-}
-
-html:not([dir="rtl"]) .file svg,
-html:not([dir="rtl"]) .domain svg,
-html:not([dir="rtl"]) .folder svg,
-html:not([dir="rtl"]) .worker svg {
-  margin-right: 5px;
-}
-
-html[dir="rtl"] .file svg,
-html[dir="rtl"] .domain svg,
-html[dir="rtl"] .folder svg,
-html[dir="rtl"] .worker svg {
-  margin-left: 5px;
-}
-
 .tree {
   -webkit-user-select: none;
   -moz-user-select: none;
   -ms-user-select: none;
   -o-user-select: none;
   user-select: none;
 
   flex: 1;
@@ -931,17 +978,17 @@ html[dir="rtl"] .worker svg {
 }
 
 .tree .node {
   padding: 2px 5px;
   position: relative;
   cursor: pointer;
 }
 
-.tree .node:hover {
+.tree-node:hover {
   background: var(--theme-tab-toolbar-background);
 }
 
 .tree .node.focused {
   color: white;
   background-color: var(--theme-selection-background);
 }
 
@@ -951,88 +998,137 @@ html[dir="rtl"] .worker svg {
 
 .tree .node.focused svg {
   fill: white;
 }
 
 .sources-list .tree-node button {
   position: fixed;
 }
+.toggle-button-start,
+.toggle-button-end {
+  position: absolute;
+  width: 16px;
+  height: 16px;
+  transition: transform 0.25s ease-in-out;
+  margin: 0 4px;
+}
+
+.toggle-button-start svg,
+.toggle-button-end svg {
+  fill: var(--theme-comment);
+}
+
+.toggle-button-end svg {
+  transform: rotate(180deg);
+}
+
+.toggle-button-start.vertical svg {
+  transform: rotate(-90deg);
+}
+
+.toggle-button-end.vertical svg {
+  transform: rotate(90deg);
+}
+
+.toggle-button-start {
+  top: 7px;
+  left: 0;
+}
+
+.toggle-button-end {
+  top: 7px;
+  right: 0;
+}
+
+.toggle-button-start.collapsed,
+.toggle-button-end.collapsed {
+  transform: rotate(180deg);
+}
 
 .source-footer {
   background: var(--theme-body-background);
   border-top: 1px solid var(--theme-splitter-color);
   position: absolute;
   bottom: 0;
   left: 0;
   right: 1px;
   opacity: 1;
   z-index: 100;
   -moz-user-select: none;
   user-select: none;
 }
 
-html:not([dir="rtl"]) .source-footer .command-bar {
-  float: right;
+.source-footer .commands {
+  display: flex;
+  padding: 8px 0.7em;
 }
 
-html[dir="rtl"] .source-footer .command-bar {
-  float: left;
-}
-
-.source-footer .command-bar * {
+.source-footer .commands * {
   -moz-user-select: none;
   user-select: none;
 }
 
-.command-bar > span {
+.source-footer > .commands > .action {
   cursor: pointer;
-  width: 1em;
-  height: 1.1em;
-  display: inline-block;
-  text-align: center;
+  display: flex;
+  justify-content: center;
+  align-items: center;
   transition: opacity 200ms;
+  border: none;
+  background: transparent;
 }
 
-html:not([dir="rtl"]) .command-bar > span {
-  margin-right: 0.7em;
+:root.theme-dark .source-footer > .commands > .action {
+  fill: var(--theme-body-color);
 }
 
-html[dir="rtl"] .command-bar > span {
-  margin-left: 0.7em;
+:root.theme-dark .source-footer > .commands > .action:hover {
+  fill: var(--theme-selection-color);
+}
+
+.source-footer > .commands > .action svg {
+  height: 1em;
+  width: 1em;
 }
 
-.source-footer .prettyPrint.pretty {
-  stroke: var(--theme-highlight-blue);
+.source-footer .commands .coverage {
+  border: none;
+  outline: none;
+  background: transparent;
+  color: var(--theme-content-color3);
+  font-weight: 600;
+  padding: 1px;
+  width: 16px;
+  height: 16px;
 }
 
-.source-footer input:focus {
-  border-color: var(--theme-highlight-blue);
-  outline: none;
+.source-footer .commands .coverage:hover {
+  border: 1px solid var(--theme-body-color-inactive);
+  border-radius: 2px;
+  padding: 0px;
+  cursor: pointer;
 }
 
-.source-footer input {
-  line-height: 16px;
-  margin: 7px;
+.coverage-on .source-footer .commands .coverage {
+  color: var(--theme-highlight-blue);
+  border: 1px solid var(--theme-body-color-inactive);
   border-radius: 2px;
-  border: 1px solid var(--theme-splitter-color);
-  padding-left: 4px;
-  font-size: 10px;
 }
 .search-bar {
   width: calc(100% - 1px);
   height: 40px;
-  background: white;
+  background-color: var(--theme-body-background);
   border-bottom: 1px solid var(--theme-splitter-color);
   display: flex;
 }
 
 .search-bar i {
   display: block;
-  padding: 13px 0 0 13px;
+  padding: 13px;
   width: 40px;
 }
 
 .search-bar i svg {
   width: 16px;
 }
 
 .search-bar input {
@@ -1042,17 +1138,16 @@ html[dir="rtl"] .command-bar > span {
   background-color: var(--theme-body-background);
   color: var(--theme-comment);
   width: calc(100% - 38px);
   flex: 1;
 }
 
 .search-bar .magnifying-glass {
   background-color: var(--theme-body-background);
-  width: 40px;
 }
 
 .search-bar .magnifying-glass path,
 .search-bar .magnifying-glass ellipse {
   stroke: var(--theme-splitter-color);
 }
 
 .search-bar input::placeholder {
@@ -1095,16 +1190,25 @@ html[dir="rtl"] .editor-mount {
 }
 
 .editor-wrapper .breakpoints {
   position: absolute;
   top: 0;
   left: 0;
 }
 
+.editor.hit-marker {
+  height: 14px;
+}
+
+.coverage-on .CodeMirror-code :not(.hit-marker) .CodeMirror-line,
+.coverage-on .CodeMirror-code :not(.hit-marker) .CodeMirror-gutter-wrapper {
+  opacity: 0.5;
+}
+
 .editor.new-breakpoint svg {
   fill: var(--theme-selection-background);
   width: 60px;
   height: 14px;
   position: absolute;
   top: 0px;
   right: -4px;
 }
@@ -1207,36 +1311,67 @@ html[dir="rtl"] .editor-mount {
   font-size: 14px;
   color: var(--theme-comment);
   line-height: 30px;
 }
 
 .conditional-breakpoint-panel input:focus {
   outline-width: 0;
 }
+
+.why-paused {
+  background-color: var(--breakpoint-active-color);
+  border: 1.7px solid var(--breakpoint-active-color);
+  color: var(--theme-highlight-blue);
+  padding: 10px 10px 10px 20px;
+  white-space: normal;
+  opacity: 0.9;
+  font-size: 12px;
+  text-align: center;
+  font-weight: bold;
+}
+
+.theme-dark .secondary-panes .why-paused {
+  color: white;
+}
 .breakpoints-list * {
   -moz-user-select: none;
   user-select: none;
 }
 
 .breakpoints-list .breakpoint {
   font-size: 12px;
   color: var(--theme-content-color1);
   padding: 0.5em 1px;
   line-height: 1em;
   position: relative;
+  transition: all 0.25s ease;
+}
+
+html[dir="rtl"] .breakpoints-list .breakpoint {
+  border-right: 4px solid transparent;
+}
+
+html:not([dir="rtl"]) .breakpoints-list .breakpoint {
   border-left: 4px solid transparent;
-  transition: all 0.25s ease;
 }
 
 .breakpoints-list .breakpoint:last-of-type {
   padding-bottom: 0.45em;
 }
 
-.breakpoints-list .breakpoint.paused {
+html:not([dir="rtl"]) .breakpoints-list .breakpoint.is-conditional {
+  border-left-color: var(--theme-graphs-yellow);
+}
+
+html[dir="rtl"] .breakpoints-list .breakpoint.is-conditional {
+  border-right-color: var(--theme-graphs-yellow);
+}
+
+html .breakpoints-list .breakpoint.paused {
   background-color: var(--theme-toolbar-background-alt);
   border-color: var(--breakpoint-active-color);
 }
 
 .breakpoints-list .breakpoint.disabled .breakpoint-label {
   color: var(--theme-content-color3);
   transition: color 0.5s linear;
 }
@@ -1246,117 +1381,134 @@ html[dir="rtl"] .editor-mount {
   background-color: var(--theme-search-overlays-semitransparent);
 }
 
 .breakpoints-list .breakpoint.paused:hover {
   border-color: var(--breakpoint-active-color-hover);
 }
 
 .breakpoints-list .breakpoint-checkbox {
-  margin-left: 0;
+  margin-inline-start: 0;
 }
 
 .breakpoints-list .breakpoint-label {
   display: inline-block;
-  padding-left: 2px;
+  padding-inline-start: 2px;
   padding-bottom: 4px;
 }
 
 .breakpoints-list .pause-indicator {
   flex: 0 1 content;
   order: 3;
 }
 
-.breakpoint-snippet {
+:root.theme-light .breakpoint-snippet,
+:root.theme-firebug .breakpoint-snippet {
   color: var(--theme-comment);
-  padding-left: 18px;
+}
+
+:root.theme-dark .breakpoint-snippet {
+  color: var(--theme-body-color);
+  opacity: 0.6;
+}
+
+.breakpoint-snippet {
+  padding-inline-start: 18px;
 }
 
 .breakpoint .close-btn {
   position: absolute;
-  right: 6px;
+  offset-inline-end: 6px;
   top: 12px;
 }
 
 .breakpoint .close {
   display: none;
 }
 
 .breakpoint:hover .close {
   display: block;
 }
 .input-expression {
   width: 100%;
-  padding: 5px;
+  padding: 8px 10px;
   margin: 0px;
-  border: none;
-  cursor: hand;
+  border: 1px;
+  cursor: pointer;
+  color: var(--theme-body-color);
+  background-color: var(--theme-body-background);
+  line-height: 12px;
+}
+
+.input-expression::-webkit-input-placeholder {
+  text-align: center;
+  font-style: italic;
+}
+
+.input-expression:focus {
+  outline-color: var(--theme-selection-background-semitransparent);
+  outline-width: 2px;
+  cursor: text;
 }
 
 .expression-container {
   border: 1px;
-  padding: 5px 2px 5px 5px;
-  margin: 1px;
+  padding: 8px 5px 0px 10px;
   width: 100%;
-  color: var(--theme-body-color) !important;
+  color: var(--theme-body-color);
+  background-color: var(--theme-body-background);
+  display: flex;
+}
+
+.expression-container .tree {
+  overflow: hidden;
+}
+
+:root.theme-light .expression-container:hover {
   background-color: var(--theme-tab-toolbar-background);
 }
 
-.expression-container:hover {
-  background-color: var(--theme-selection-background);
-  color: var(--theme-body-background) !important;
+:root.theme-dark .expression-container:hover {
+  background-color: var(--theme-search-overlays-semitransparent);
 }
 
-.expression-output-container .close-btn {
-  width: 6px;
-  height: 6px;
-  float: right;
-  margin-right: 6px;
+.expression-container .close-btn {
+  display: none;
+}
+
+.expression-container:hover .close-btn {
+  width: 8px;
+  height: 8px;
+  margin-left: auto;
+  margin-right: 8px;
   display: block;
   cursor: pointer;
 }
 
 .expression-input {
   cursor: pointer;
   max-width: 50%;
 }
 
+.expression-separator {
+  padding: 0px 5px;
+}
+
 .expression-value {
   overflow-x: scroll;
   color: var(--theme-content-color2);
   max-width: 50% !important;
 }
 
 .expression-error {
   color: var(--theme-highlight-red);
 }
-.arrow svg {
-  fill: var(--theme-splitter-color);
-  margin-top: 3px;
-  transition: transform 0.25s ease;
-  width: 10px;
-}
 
-html:not([dir="rtl"]) .arrow svg {
-  margin-right: 5px;
-  transform: rotate(-90deg);
-}
-
-html[dir="rtl"] .arrow svg {
-  margin-left: 5px;
-  transform: rotate(90deg);
-}
-
-/* TODO (Amit): html is just for specificity. keep it like this? */
-html .arrow.expanded svg {
-  transform: rotate(0deg);
-}
-
-.arrow.hidden {
-  visibility: hidden;
+.object-node.not-enumerable {
+  opacity: 0.6;
 }
 
 .object-label {
   color: var(--theme-highlight-blue);
 }
 
 .objectBox-object,
 .objectBox-string,
@@ -1380,18 +1532,19 @@ html .arrow.expanded svg {
   list-style: none;
   margin: 0;
   padding: 0;
 }
 
 .frames ul li {
   cursor: pointer;
   padding: 7px 10px 7px 21px;
-  clear: both;
   overflow: hidden;
+  display: flex;
+  justify-content: space-between;
 }
 
 /* Style the focused call frame like so:
 .frames ul li:focus {
   border: 3px solid red;
 }
 */
 
@@ -1400,23 +1553,30 @@ html .arrow.expanded svg {
   user-select: none;
 }
 
 .frames ul li:nth-of-type(2n) {
   background-color: var(--theme-tab-toolbar-background);
 }
 
 .frames .location {
-  float: right;
-  color: var(--theme-comment);
   font-weight: lighter;
 }
 
+:root.theme-light .frames .location,
+:root.theme-firebug .frames .location {
+  color: var(--theme-comment);
+}
+
+:root.theme-dark .frames .location {
+  color: var(--theme-body-color);
+  opacity: 0.6;
+}
+
 .frames .title {
-  float: left;
   text-overflow: ellipsis;
   overflow: hidden;
   margin-right: 1em;
 }
 
 .frames ul li.selected,
 .frames ul li.selected .location {
   background-color: var(--theme-selection-background);
@@ -1429,16 +1589,62 @@ html .arrow.expanded svg {
   padding: 8px 0px;
   border-top: 1px solid var(--theme-splitter-color);
   background-color: var(--theme-tab-toolbar-background);
 }
 
 .show-more:hover {
   background-color: var(--theme-search-overlays-semitransparent);
 }
+.event-listeners {
+  list-style: none;
+  margin: 0;
+  padding: 0;
+}
+
+.event-listeners .listener {
+  cursor: pointer;
+  padding: 7px 10px 7px 21px;
+  clear: both;
+  overflow: hidden;
+}
+
+.event-listeners .listener * {
+  -moz-user-select: none;
+  user-select: none;
+}
+
+.event-listeners .listener:nth-of-type(2n) {
+  background-color: var(--theme-tab-toolbar-background);
+}
+
+.event-listeners .listener .type {
+  color: var(--theme-highlight-bluegrey);
+  padding-right: 5px;
+}
+
+.event-listeners .listener .selector {
+  color: var(--theme-content-color2);
+}
+
+.event-listeners .listener-checkbox {
+  margin-left: 0;
+}
+
+.event-listeners .listener .close-btn {
+  float: right;
+}
+
+.event-listeners .listener .close {
+  display: none;
+}
+
+.event-listeners .listener:hover .close {
+  display: block;
+}
 .accordion {
   background-color: var(--theme-body-background);
   width: 100%;
 }
 
 .accordion ._header {
   background-color: var(--theme-toolbar-background);
   border-bottom: 1px solid var(--theme-splitter-color);
@@ -1450,59 +1656,63 @@ html .arrow.expanded svg {
 
   -webkit-user-select: none;
   -moz-user-select: none;
   -ms-user-select: none;
   -o-user-select: none;
   user-select: none;
 }
 
+.accordion ._header {
+  display: flex;
+}
+
 .accordion ._header:hover {
   background-color: var(--theme-search-overlays-semitransparent);
 }
 
-.accordion ._header:hover svg {
-  fill: var(--theme-comment-alt);
+.accordion ._header button svg,
+.accordion ._header:hover button svg {
+  fill: currentColor;
 }
 
 .accordion ._content {
   border-bottom: 1px solid var(--theme-splitter-color);
   font-size: 12px;
 }
-.right-sidebar {
+
+.accordion ._header .header-buttons {
   display: flex;
-  flex-direction: column;
-  flex: 1;
-  white-space: nowrap;
+  margin-left: auto;
+  padding-right: 5px;
 }
 
-.right-siderbar * {
-  -moz-user-select: none;
-  user-select: none;
+.accordion .header-buttons .add-button {
+  font-size: 180%;
+  text-align: center;
+  line-height: 16px;
 }
 
-.right-sidebar .accordion {
-  overflow-y: auto;
-  overflow-x: hidden;
-}
-
-.right-sidebar .command-bar {
-  border-bottom: 1px solid var(--theme-splitter-color);
+.accordion .header-buttons button {
+  color: var(--theme-body-color);
+  border: none;
+  background: none;
+  outline: 0;
+  padding: 0;
+  width: 16px;
+  height: 16px;
 }
 
+.accordion .header-buttons button::-moz-focus-inner {
+  border: none;
+}
 .command-bar {
   height: 30px;
-}
-
-html:not([dir="rtl"]) .command-bar {
-  padding: 8px 5px 10px 1px;
-}
-
-html[dir="rtl"] .command-bar {
-  padding: 8px 1px 10px 5px;
+  padding: 8px 5px;
+  border-bottom: 1px solid var(--theme-splitter-color);
 }
 
 .command-bar > span {
   cursor: pointer;
   width: 16px;
   height: 17px;
   display: inline-block;
   text-align: center;
@@ -1512,187 +1722,269 @@ html[dir="rtl"] .command-bar {
 :root.theme-dark .command-bar > span {
   fill: var(--theme-body-color);
 }
 
 :root.theme-dark .command-bar > span:hover {
   fill: var(--theme-selection-color);
 }
 
-html:not([dir="rtl"]) .command-bar > span {
-  margin-right: 0.7em;
-}
-
-html[dir="rtl"] .command-bar > span {
-  margin-left: 0.7em;
+.command-bar > span {
+  margin-inline-end: 0.7em;
 }
 
 .command-bar > span.disabled {
   opacity: 0.3;
   cursor: default;
 }
 
-html:not([dir="rtl"]) .command-bar .stepOut {
-  margin-right: 2em;
-}
-
-html[dir="rtl"] .command-bar .stepOut {
-  margin-left: 2em;
+.command-bar .stepOut {
+  margin-inline-end: 2em;
 }
 
 .command-bar .subSettings {
   float: right;
 }
 
+.command-bar .toggleBreakpoints.breakpoints-disabled path {
+  fill: var(--theme-highlight-blue);
+}
+
+.command-bar span.pause-exceptions.uncaught {
+  fill: var(--theme-highlight-purple);
+}
+
+.command-bar span.pause-exceptions.all {
+  fill: var(--theme-highlight-blue);
+}
+.secondary-panes {
+  display: flex;
+  flex-direction: column;
+  flex: 1;
+  white-space: nowrap;
+}
+
+.secondary-panes * {
+  -moz-user-select: none;
+  user-select: none;
+}
+
+.secondary-panes .accordion {
+  overflow-y: auto;
+  overflow-x: hidden;
+}
+
 .pane {
   color: var(--theme-body-color);
 }
 
 .pane .pane-info {
   font-style: italic;
   text-align: center;
   padding: 0.5em;
   -moz-user-select: none;
   user-select: none;
 }
+.welcomebox {
+  width: calc(100% - 1px);
 
-.toggleBreakpoints.breakpoints-disabled path {
-  stroke: var(--theme-highlight-blue);
+  /* Offsetting it by 30px for the sources-header area */
+  height: calc(100% - 30px);
+  position: absolute;
+  top: 30px;
+  left: 0;
+  padding: 50px 0 0 0;
+  text-align: center;
+  font-size: 1.25em;
+  color: var(--theme-comment-alt);
+  background-color: var(--theme-tab-toolbar-background);
+  font-weight: lighter;
+  z-index: 100;
 }
 
-span.pause-exceptions.uncaught {
-  stroke: var(--theme-highlight-purple);
-}
-
-span.pause-exceptions.all {
-  stroke: var(--theme-highlight-blue);
+.welcomebox .toggle-button-end {
+  bottom: 11px;
+  position: absolute;
+  top: auto;
 }
 .source-header {
   border-bottom: 1px solid var(--theme-splitter-color);
   height: 30px;
+  display: flex;
   flex: 1;
+  flex-flow: row wrap;
+  -webkit-align-items: stretch;
+  align-items: stretch;
 }
 
 .source-header * {
   -moz-user-select: none;
   user-select: none;
 }
 
 .source-tabs {
-  min-width: 50px;
-  max-width: calc(100% - 60px);
-  overflow: hidden;
+  max-width: calc(100% - 80px);
   float: left;
+  margin-inline-start: 21px;
 }
 
 .source-header .new-tab-btn {
-  width: 16px;
+  width: 14px;
+  height: 14px;
   display: inline-block;
   position: relative;
-  top: 4px;
+  top: 5px;
   margin: 4px;
+  margin-inline-start: 8px;
   line-height: 0;
-}
-
-.source-header .new-tab-btn path {
-  fill: var(--theme-splitter-color);
-}
-
-.source-header .new-tab-btn:hover path {
+  cursor: pointer;
   fill: var(--theme-comment);
+  transition: 0.1s ease;
 }
 
 .source-tab {
-  background-color: var(--theme-toolbar-background-alt);
   color: var(--theme-faded-tab-color);
-  border: 1px solid var(--theme-splitter-color);
+  border: 1px solid transparent;
   border-top-left-radius: 2px;
   border-top-right-radius: 2px;
-  height: 23px;
+  height: 24px;
   line-height: 20px;
   display: inline-block;
-  border-bottom: none;
   position: relative;
   transition: all 0.25s ease;
   min-width: 40px;
   overflow: hidden;
 }
 
-html:not([dir="rtl"]) .source-tab {
-  padding: 2px 20px 2px 12px;
-  margin: 6px 0 0 8px;
-}
-
-html[dir="rtl"] .source-tab {
-  padding: 2px 12px 2px 20px;
-  margin: 6px 8px 0 0;
+.source-tab {
+  padding-top: 2px;
+  padding-bottom: 2px;
+  padding-inline-start: 12px;
+  padding-inline-end: 20px;
+  margin-top: 6px;
+  margin-inline-start: 8px;
 }
 
 .source-tab:hover {
-  background: var(--theme-toolbar-background);
+  background-color: var(--theme-toolbar-background-alt);
+  border-color: var(--theme-splitter-color);
   cursor: pointer;
 }
 
 .source-tab.active {
   color: var(--theme-body-color);
   background-color: var(--theme-body-background);
+  border-color: var(--theme-splitter-color);
+  border-bottom-color: transparent;
 }
 
 .source-tab path {
   fill: var(--theme-faded-tab-color);
 }
 
 .source-tab.active path {
   fill: var(--theme-body-color);
 }
 
+.source-tab .prettyPrint {
+  display: block;
+  position: absolute;
+  top: 3px;
+  left: 6px;
+}
+
+.source-tab .prettyPrint svg {
+  height: 1em;
+  width: 1em;
+}
+
+.source-tab .prettyPrint path {
+  fill: var(--theme-textbox-box-shadow);
+}
+
 .source-tab .close-btn {
   position: absolute;
   top: 3px;
 }
 
 .source-tab .filename {
   text-overflow: ellipsis;
   overflow: hidden;
 }
 
-html:not([dir="rtl"]) .source-tab .close-btn {
-  right: 4px;
+.source-tab.pretty .filename {
+  padding-left: 12px;
 }
 
-html[dir="rtl"] .source-tab .close-btn {
-  left: 4px;
+.source-tab .close-btn {
+  offset-inline-end: 4px;
 }
 
 .source-tab .close {
   display: none;
 }
 
 .source-tab:hover .close {
   display: block;
 }
+
+.toggle-button-start,
+.toggle-button-end {
+  position: absolute;
+  width: 16px;
+  height: 16px;
+  margin: 0 4px;
+  cursor: pointer;
+}
+
+.toggle-button-start svg,
+.toggle-button-end svg {
+  fill: var(--theme-comment);
+}
+
+.toggle-button-end svg {
+  transform: rotate(180deg);
+}
+
+.toggle-button-start {
+  top: 8px;
+  left: 0;
+}
+
+.toggle-button-end {
+  top: 8px;
+  right: 0;
+}
+
+.toggle-button-start.collapsed,
+.toggle-button-end.collapsed {
+  transform: rotate(180deg);
+  flex: 1;
+}
 .dropdown {
   background: var(--theme-body-background);
   border: 1px solid var(--theme-splitter-color);
   box-shadow: 0 4px 4px 0 var(--theme-search-overlays-semitransparent);
   max-height: 300px;
   position: absolute;
   right: 8px;
   top: 35px;
   width: 150px;
   z-index: 1000;
 }
 
 .dropdown-button {
   position: absolute;
-  right: 12px;
-  top: 5px;
-  font-size: 16px;
+  right: 18px;
+  top: 4px;
+  font-size: 18px;
   color: var(--theme-body-color);
   cursor: pointer;
+  background: none;
+  border: none;
 }
 
 .dropdown li {
   transition: all 0.25s ease;
   padding: 2px 10px 10px 5px;
   overflow: hidden;
   height: 30px;
   text-overflow: ellipsis;
@@ -1716,9 +2008,9 @@ html[dir="rtl"] .source-tab .close-btn {
   width: 100%;
   height: 100%;
   background: transparent;
   z-index: 999;
   left: 0;
   top: 0;
 }
 
-/*# sourceMappingURL=styles.css.map*/
\ No newline at end of file
+/*# sourceMappingURL=debugger.css.map*/
\ No newline at end of file
--- a/devtools/client/debugger/new/debugger.js
+++ b/devtools/client/debugger/new/debugger.js
@@ -1,17 +1,39 @@
-// Generated from: 8175aacaec380ecf859183ad62bee2a9aef180d2 Disable searching test because it's timing out on try on certain platforms for some reason
-
 var Debugger =
 /******/ (function(modules) { // webpackBootstrap
 /******/ 	// The module cache
 /******/ 	var installedModules = {};
 /******/
 /******/ 	// The require function
 /******/ 	function __webpack_require__(moduleId) {
+/******/ 		// SingleModulePlugin
+/******/ 		const smpCache = this.smpCache = this.smpCache || {};
+/******/ 		const smpMap = this.smpMap = this.smpMap || new Map();
+/******/ 		function sanitizeString(text) {
+/******/ 		   return text.replace(/__webpack_require__\(\d+\)/g,"");
+/******/ 		}
+/******/ 		function getModuleBody(id) {
+/******/ 		  if (smpCache.hasOwnProperty(id)) {
+/******/ 		    return smpCache[id];
+/******/ 		  }
+/******/
+/******/ 		  const body = sanitizeString(String(modules[id]));
+/******/ 		  smpCache[id] = body;
+/******/ 		  return body;
+/******/ 		}
+/******/ 		if (!installedModules[moduleId]) {
+/******/ 			const body = getModuleBody(moduleId);
+/******/ 			if (smpMap.has(body)) {
+/******/ 				installedModules[moduleId] = installedModules[smpMap.get(body)];
+/******/ 			}
+/******/ 			else {
+/******/ 				smpMap.set(body, moduleId)
+/******/ 			}
+/******/ 		}
 /******/
 /******/ 		// Check if module is in cache
 /******/ 		if(installedModules[moduleId])
 /******/ 			return installedModules[moduleId].exports;
 /******/
 /******/ 		// Create a new module (and put it into the cache)
 /******/ 		var module = installedModules[moduleId] = {
 /******/ 			exports: {},
@@ -32,17 +54,17 @@ var Debugger =
 /******/
 /******/ 	// expose the modules object (__webpack_modules__)
 /******/ 	__webpack_require__.m = modules;
 /******/
 /******/ 	// expose the module cache
 /******/ 	__webpack_require__.c = installedModules;
 /******/
 /******/ 	// __webpack_public_path__
-/******/ 	__webpack_require__.p = "/public/build";
+/******/ 	__webpack_require__.p = "/assets/build";
 /******/
 /******/ 	// Load entry module and return exports
 /******/ 	return __webpack_require__(0);
 /******/ })
 /************************************************************************/
 /******/ ([
 /* 0 */
 /***/ function(module, exports, __webpack_require__) {
@@ -50,200 +72,211 @@ var Debugger =
 	module.exports = __webpack_require__(1);
 
 
 /***/ },
 /* 1 */
 /***/ function(module, exports, __webpack_require__) {
 
 	var React = __webpack_require__(2);
-	
-	var _require = __webpack_require__(3);
-	
-	var bindActionCreators = _require.bindActionCreators;
-	var combineReducers = _require.combineReducers;
-	
-	var ReactDOM = __webpack_require__(16);
-	
-	var _require2 = __webpack_require__(18);
-	
-	var _require2$client = _require2.client;
-	var getClient = _require2$client.getClient;
-	var firefox = _require2$client.firefox;
-	var renderRoot = _require2.renderRoot;
-	var bootstrap = _require2.bootstrap;
-	
-	var _require3 = __webpack_require__(89);
-	
-	var getValue = _require3.getValue;
-	var isFirefoxPanel = _require3.isFirefoxPanel;
-	
-	
-	var configureStore = __webpack_require__(238);
-	
-	var reducers = __webpack_require__(249);
-	var selectors = __webpack_require__(259);
-	
-	var App = __webpack_require__(260);
-	
+
+	var _require = __webpack_require__(3),
+	    bindActionCreators = _require.bindActionCreators,
+	    combineReducers = _require.combineReducers;
+
+	var ReactDOM = __webpack_require__(22);
+
+	var _require2 = __webpack_require__(23),
+	    getClient = _require2.getClient,
+	    firefox = _require2.firefox;
+
+	var _require3 = __webpack_require__(178),
+	    renderRoot = _require3.renderRoot,
+	    bootstrap = _require3.bootstrap,
+	    L10N = _require3.L10N;
+
+	var _require4 = __webpack_require__(65),
+	    getValue = _require4.getValue,
+	    isFirefoxPanel = _require4.isFirefoxPanel;
+
+	var configureStore = __webpack_require__(227);
+
+	var _require5 = __webpack_require__(237),
+	    onConnect = _require5.onConnect,
+	    onFirefoxConnect = _require5.onFirefoxConnect;
+
+	var reducers = __webpack_require__(238);
+	var selectors = __webpack_require__(253);
+
+	var App = __webpack_require__(254);
+
 	var createStore = configureStore({
 	  log: getValue("logging.actions"),
 	  makeThunkArgs: (args, state) => {
 	    return Object.assign({}, args, { client: getClient(state) });
 	  }
 	});
-	
+
 	var store = createStore(combineReducers(reducers));
-	var actions = bindActionCreators(__webpack_require__(262), store.dispatch);
-	
+	var actions = bindActionCreators(__webpack_require__(255), store.dispatch);
+
 	if (!isFirefoxPanel()) {
-	  L10N.setBundle(__webpack_require__(458));
-	}
-	
+	  window.L10N = L10N;
+	  window.L10N.setBundle(__webpack_require__(500));
+	}
+
 	window.appStore = store;
-	
+
 	// Expose the bound actions so external things can do things like
 	// selecting a source.
 	window.actions = {
 	  selectSource: actions.selectSource,
 	  selectSourceURL: actions.selectSourceURL
 	};
-	
+
+	// Globals needed for mocha integration tests
+	window.getGlobalsForTesting = () => {
+	  return {
+	    debuggerStore: store,
+	    launchpadStore: window.launchpadStore,
+	    selectors,
+	    actions
+	  };
+	};
+
 	function unmountRoot() {
-	  var mount = document.querySelector("#mount");
+	  var mount = document.querySelector("#mount div");
 	  ReactDOM.unmountComponentAtNode(mount);
 	}
-	
+
 	if (isFirefoxPanel()) {
 	  (function () {
-	    var sourceMap = __webpack_require__(264);
-	    var prettyPrint = __webpack_require__(276);
-	
+	    var sourceMap = __webpack_require__(257);
+	    var prettyPrint = __webpack_require__(268);
+
 	    module.exports = {
 	      bootstrap: (_ref) => {
-	        var threadClient = _ref.threadClient;
-	        var tabTarget = _ref.tabTarget;
-	        var toolbox = _ref.toolbox;
-	        var L10N = _ref.L10N;
-	
-	        // TODO (jlast) remove when the panel has L10N
-	        if (L10N) {
+	        var threadClient = _ref.threadClient,
+	            tabTarget = _ref.tabTarget,
+	            toolbox = _ref.toolbox;
+
+	        // jlast: remove when docker updates
+	        if (!window.L10N) {
 	          window.L10N = L10N;
-	        } else {
-	          window.L10N = __webpack_require__(459);
-	          window.L10N.setBundle(__webpack_require__(458));
-	        }
-	
+	          window.L10N.setBundle(__webpack_require__(500));
+	        }
+
 	        firefox.setThreadClient(threadClient);
 	        firefox.setTabTarget(tabTarget);
 	        renderRoot(React, ReactDOM, App, store);
-	        return firefox.initPage(actions);
+	        firefox.initPage(actions);
+	        return onFirefoxConnect(actions, firefox);
 	      },
 	      destroy: () => {
 	        unmountRoot();
 	        sourceMap.destroyWorker();
 	        prettyPrint.destroyWorker();
 	      },
 	      store: store,
 	      actions: actions,
 	      selectors: selectors,
 	      client: firefox.clientCommands
 	    };
 	  })();
 	} else {
-	  bootstrap(React, ReactDOM, App, actions, store);
+	  bootstrap(React, ReactDOM, App, actions, store).then(conn => onConnect(conn, actions));
 	}
 
 /***/ },
 /* 2 */
 /***/ function(module, exports) {
 
 	module.exports = devtoolsRequire("devtools/client/shared/vendor/react");
 
 /***/ },
 /* 3 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
-	
+
 	exports.__esModule = true;
 	exports.compose = exports.applyMiddleware = exports.bindActionCreators = exports.combineReducers = exports.createStore = undefined;
-	
+
 	var _createStore = __webpack_require__(4);
-	
+
 	var _createStore2 = _interopRequireDefault(_createStore);
-	
-	var _combineReducers = __webpack_require__(11);
-	
+
+	var _combineReducers = __webpack_require__(17);
+
 	var _combineReducers2 = _interopRequireDefault(_combineReducers);
-	
-	var _bindActionCreators = __webpack_require__(13);
-	
+
+	var _bindActionCreators = __webpack_require__(19);
+
 	var _bindActionCreators2 = _interopRequireDefault(_bindActionCreators);
-	
-	var _applyMiddleware = __webpack_require__(14);
-	
+
+	var _applyMiddleware = __webpack_require__(20);
+
 	var _applyMiddleware2 = _interopRequireDefault(_applyMiddleware);
-	
-	var _compose = __webpack_require__(15);
-	
+
+	var _compose = __webpack_require__(21);
+
 	var _compose2 = _interopRequireDefault(_compose);
-	
-	var _warning = __webpack_require__(12);
-	
+
+	var _warning = __webpack_require__(18);
+
 	var _warning2 = _interopRequireDefault(_warning);
-	
+
 	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-	
+
 	/*
 	* This is a dummy function to check if the function name has been altered by minification.
 	* If the function has been minified and NODE_ENV !== 'production', warn the user.
 	*/
 	function isCrushed() {}
-	
+
 	if (false) {
 	  (0, _warning2["default"])('You are currently using minified code outside of NODE_ENV === \'production\'. ' + 'This means that you are running a slower development build of Redux. ' + 'You can use loose-envify (https://github.com/zertosh/loose-envify) for browserify ' + 'or DefinePlugin for webpack (http://stackoverflow.com/questions/30030031) ' + 'to ensure you have the correct code for your production build.');
 	}
-	
+
 	exports.createStore = _createStore2["default"];
 	exports.combineReducers = _combineReducers2["default"];
 	exports.bindActionCreators = _bindActionCreators2["default"];
 	exports.applyMiddleware = _applyMiddleware2["default"];
 	exports.compose = _compose2["default"];
 
 /***/ },
 /* 4 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
-	
+
 	exports.__esModule = true;
 	exports.ActionTypes = undefined;
 	exports["default"] = createStore;
-	
+
 	var _isPlainObject = __webpack_require__(5);
-	
+
 	var _isPlainObject2 = _interopRequireDefault(_isPlainObject);
-	
-	var _symbolObservable = __webpack_require__(9);
-	
+
+	var _symbolObservable = __webpack_require__(15);
+
 	var _symbolObservable2 = _interopRequireDefault(_symbolObservable);
-	
+
 	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-	
+
 	/**
 	 * These are private action types reserved by Redux.
 	 * For any unknown actions, you must return the current state.
 	 * If the current state is undefined, you must return the initial state.
 	 * Do not reference these action types directly in your code.
 	 */
 	var ActionTypes = exports.ActionTypes = {
 	  INIT: '@@redux/INIT'
 	};
-	
+
 	/**
 	 * Creates a Redux store that holds the state tree.
 	 * The only way to change the data in the store is to call `dispatch()` on it.
 	 *
 	 * There should only be a single store in your app. To specify how different
 	 * parts of the state tree respond to actions, you may combine several reducers
 	 * into a single reducer function by using `combineReducers`.
 	 *
@@ -261,55 +294,55 @@ var Debugger =
 	 * time travel, persistence, etc. The only store enhancer that ships with Redux
 	 * is `applyMiddleware()`.
 	 *
 	 * @returns {Store} A Redux store that lets you read the state, dispatch actions
 	 * and subscribe to changes.
 	 */
 	function createStore(reducer, initialState, enhancer) {
 	  var _ref2;
-	
+
 	  if (typeof initialState === 'function' && typeof enhancer === 'undefined') {
 	    enhancer = initialState;
 	    initialState = undefined;
 	  }
-	
+
 	  if (typeof enhancer !== 'undefined') {
 	    if (typeof enhancer !== 'function') {
 	      throw new Error('Expected the enhancer to be a function.');
 	    }
-	
+
 	    return enhancer(createStore)(reducer, initialState);
 	  }
-	
+
 	  if (typeof reducer !== 'function') {
 	    throw new Error('Expected the reducer to be a function.');
 	  }
-	
+
 	  var currentReducer = reducer;
 	  var currentState = initialState;
 	  var currentListeners = [];
 	  var nextListeners = currentListeners;
 	  var isDispatching = false;
-	
+
 	  function ensureCanMutateNextListeners() {
 	    if (nextListeners === currentListeners) {
 	      nextListeners = currentListeners.slice();
 	    }
 	  }
-	
+
 	  /**
 	   * Reads the state tree managed by the store.
 	   *
 	   * @returns {any} The current state tree of your application.
 	   */
 	  function getState() {
 	    return currentState;
 	  }
-	
+
 	  /**
 	   * Adds a change listener. It will be called any time an action is dispatched,
 	   * and some part of the state tree may potentially have changed. You may then
 	   * call `getState()` to read the current state tree inside the callback.
 	   *
 	   * You may call `dispatch()` from a change listener, with the following
 	   * caveats:
 	   *
@@ -327,35 +360,35 @@ var Debugger =
 	   *
 	   * @param {Function} listener A callback to be invoked on every dispatch.
 	   * @returns {Function} A function to remove this change listener.
 	   */
 	  function subscribe(listener) {
 	    if (typeof listener !== 'function') {
 	      throw new Error('Expected listener to be a function.');
 	    }
-	
+
 	    var isSubscribed = true;
-	
+
 	    ensureCanMutateNextListeners();
 	    nextListeners.push(listener);
-	
+
 	    return function unsubscribe() {
 	      if (!isSubscribed) {
 	        return;
 	      }
-	
+
 	      isSubscribed = false;
-	
+
 	      ensureCanMutateNextListeners();
 	      var index = nextListeners.indexOf(listener);
 	      nextListeners.splice(index, 1);
 	    };
 	  }
-	
+
 	  /**
 	   * Dispatches an action. It is the only way to trigger a state change.
 	   *
 	   * The `reducer` function, used to create the store, will be called with the
 	   * current state tree and the given `action`. Its return value will
 	   * be considered the **next** state of the tree, and the change listeners
 	   * will be notified.
 	   *
@@ -375,142 +408,136 @@ var Debugger =
 	   *
 	   * Note that, if you use a custom middleware, it may wrap `dispatch()` to
 	   * return something else (for example, a Promise you can await).
 	   */
 	  function dispatch(action) {
 	    if (!(0, _isPlainObject2["default"])(action)) {
 	      throw new Error('Actions must be plain objects. ' + 'Use custom middleware for async actions.');
 	    }
-	
+
 	    if (typeof action.type === 'undefined') {
 	      throw new Error('Actions may not have an undefined "type" property. ' + 'Have you misspelled a constant?');
 	    }
-	
+
 	    if (isDispatching) {
 	      throw new Error('Reducers may not dispatch actions.');
 	    }
-	
+
 	    try {
 	      isDispatching = true;
 	      currentState = currentReducer(currentState, action);
 	    } finally {
 	      isDispatching = false;
 	    }
-	
+
 	    var listeners = currentListeners = nextListeners;
 	    for (var i = 0; i < listeners.length; i++) {
 	      listeners[i]();
 	    }
-	
+
 	    return action;
 	  }
-	
+
 	  /**
 	   * Replaces the reducer currently used by the store to calculate the state.
 	   *
 	   * You might need this if your app implements code splitting and you want to
 	   * load some of the reducers dynamically. You might also need this if you
 	   * implement a hot reloading mechanism for Redux.
 	   *
 	   * @param {Function} nextReducer The reducer for the store to use instead.
 	   * @returns {void}
 	   */
 	  function replaceReducer(nextReducer) {
 	    if (typeof nextReducer !== 'function') {
 	      throw new Error('Expected the nextReducer to be a function.');
 	    }
-	
+
 	    currentReducer = nextReducer;
 	    dispatch({ type: ActionTypes.INIT });
 	  }
-	
+
 	  /**
 	   * Interoperability point for observable/reactive libraries.
 	   * @returns {observable} A minimal observable of state changes.
 	   * For more information, see the observable proposal:
 	   * https://github.com/zenparsing/es-observable
 	   */
 	  function observable() {
 	    var _ref;
-	
+
 	    var outerSubscribe = subscribe;
 	    return _ref = {
 	      /**
 	       * The minimal observable subscription method.
 	       * @param {Object} observer Any object that can be used as an observer.
 	       * The observer object should have a `next` method.
 	       * @returns {subscription} An object with an `unsubscribe` method that can
 	       * be used to unsubscribe the observable from the store, and prevent further
 	       * emission of values from the observable.
 	       */
-	
+
 	      subscribe: function subscribe(observer) {
 	        if (typeof observer !== 'object') {
 	          throw new TypeError('Expected the observer to be an object.');
 	        }
-	
+
 	        function observeState() {
 	          if (observer.next) {
 	            observer.next(getState());
 	          }
 	        }
-	
+
 	        observeState();
 	        var unsubscribe = outerSubscribe(observeState);
 	        return { unsubscribe: unsubscribe };
 	      }
 	    }, _ref[_symbolObservable2["default"]] = function () {
 	      return this;
 	    }, _ref;
 	  }
-	
+
 	  // When a store is created, an "INIT" action is dispatched so that every
 	  // reducer returns their initial state. This effectively populates
 	  // the initial state tree.
 	  dispatch({ type: ActionTypes.INIT });
-	
+
 	  return _ref2 = {
 	    dispatch: dispatch,
 	    subscribe: subscribe,
 	    getState: getState,
 	    replaceReducer: replaceReducer
 	  }, _ref2[_symbolObservable2["default"]] = observable, _ref2;
 	}
 
 /***/ },
 /* 5 */
 /***/ function(module, exports, __webpack_require__) {
 
-	var getPrototype = __webpack_require__(6),
-	    isObjectLike = __webpack_require__(8);
-	
+	var baseGetTag = __webpack_require__(6),
+	    getPrototype = __webpack_require__(12),
+	    isObjectLike = __webpack_require__(14);
+
 	/** `Object#toString` result references. */
 	var objectTag = '[object Object]';
-	
+
 	/** Used for built-in method references. */
 	var funcProto = Function.prototype,
 	    objectProto = Object.prototype;
-	
+
 	/** Used to resolve the decompiled source of functions. */
 	var funcToString = funcProto.toString;
-	
+
 	/** Used to check objects for own properties. */
 	var hasOwnProperty = objectProto.hasOwnProperty;
-	
+
 	/** Used to infer the `Object` constructor. */
 	var objectCtorString = funcToString.call(Object);
-	
-	/**
-	 * Used to resolve the
-	 * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
-	 * of values.
-	 */
-	var objectToString = objectProto.toString;
-	
+
 	/**
 	 * Checks if `value` is a plain object, that is, an object created by the
 	 * `Object` constructor or one with a `[[Prototype]]` of `null`.
 	 *
 	 * @static
 	 * @memberOf _
 	 * @since 0.8.0
 	 * @category Lang
@@ -530,66 +557,218 @@ var Debugger =
 	 *
 	 * _.isPlainObject({ 'x': 0, 'y': 0 });
 	 * // => true
 	 *
 	 * _.isPlainObject(Object.create(null));
 	 * // => true
 	 */
 	function isPlainObject(value) {
-	  if (!isObjectLike(value) || objectToString.call(value) != objectTag) {
+	  if (!isObjectLike(value) || baseGetTag(value) != objectTag) {
 	    return false;
 	  }
 	  var proto = getPrototype(value);
 	  if (proto === null) {
 	    return true;
 	  }
 	  var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;
-	  return (typeof Ctor == 'function' &&
-	    Ctor instanceof Ctor && funcToString.call(Ctor) == objectCtorString);
-	}
-	
+	  return typeof Ctor == 'function' && Ctor instanceof Ctor &&
+	    funcToString.call(Ctor) == objectCtorString;
+	}
+
 	module.exports = isPlainObject;
 
 
 /***/ },
 /* 6 */
 /***/ function(module, exports, __webpack_require__) {
 
-	var overArg = __webpack_require__(7);
-	
+	var Symbol = __webpack_require__(7),
+	    getRawTag = __webpack_require__(10),
+	    objectToString = __webpack_require__(11);
+
+	/** `Object#toString` result references. */
+	var nullTag = '[object Null]',
+	    undefinedTag = '[object Undefined]';
+
 	/** Built-in value references. */
-	var getPrototype = overArg(Object.getPrototypeOf, Object);
-	
-	module.exports = getPrototype;
+	var symToStringTag = Symbol ? Symbol.toStringTag : undefined;
+
+	/**
+	 * The base implementation of `getTag` without fallbacks for buggy environments.
+	 *
+	 * @private
+	 * @param {*} value The value to query.
+	 * @returns {string} Returns the `toStringTag`.
+	 */
+	function baseGetTag(value) {
+	  if (value == null) {
+	    return value === undefined ? undefinedTag : nullTag;
+	  }
+	  return (symToStringTag && symToStringTag in Object(value))
+	    ? getRawTag(value)
+	    : objectToString(value);
+	}
+
+	module.exports = baseGetTag;
 
 
 /***/ },
 /* 7 */
+/***/ function(module, exports, __webpack_require__) {
+
+	var root = __webpack_require__(8);
+
+	/** Built-in value references. */
+	var Symbol = root.Symbol;
+
+	module.exports = Symbol;
+
+
+/***/ },
+/* 8 */
+/***/ function(module, exports, __webpack_require__) {
+
+	var freeGlobal = __webpack_require__(9);
+
+	/** Detect free variable `self`. */
+	var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
+
+	/** Used as a reference to the global object. */
+	var root = freeGlobal || freeSelf || Function('return this')();
+
+	module.exports = root;
+
+
+/***/ },
+/* 9 */
+/***/ function(module, exports) {
+
+	/* WEBPACK VAR INJECTION */(function(global) {/** Detect free variable `global` from Node.js. */
+	var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
+
+	module.exports = freeGlobal;
+
+	/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
+
+/***/ },
+/* 10 */
+/***/ function(module, exports, __webpack_require__) {
+
+	var Symbol = __webpack_require__(7);
+
+	/** Used for built-in method references. */
+	var objectProto = Object.prototype;
+
+	/** Used to check objects for own properties. */
+	var hasOwnProperty = objectProto.hasOwnProperty;
+
+	/**
+	 * Used to resolve the
+	 * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
+	 * of values.
+	 */
+	var nativeObjectToString = objectProto.toString;
+
+	/** Built-in value references. */
+	var symToStringTag = Symbol ? Symbol.toStringTag : undefined;
+
+	/**
+	 * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
+	 *
+	 * @private
+	 * @param {*} value The value to query.
+	 * @returns {string} Returns the raw `toStringTag`.
+	 */
+	function getRawTag(value) {
+	  var isOwn = hasOwnProperty.call(value, symToStringTag),
+	      tag = value[symToStringTag];
+
+	  try {
+	    value[symToStringTag] = undefined;
+	    var unmasked = true;
+	  } catch (e) {}
+
+	  var result = nativeObjectToString.call(value);
+	  if (unmasked) {
+	    if (isOwn) {
+	      value[symToStringTag] = tag;
+	    } else {
+	      delete value[symToStringTag];
+	    }
+	  }
+	  return result;
+	}
+
+	module.exports = getRawTag;
+
+
+/***/ },
+/* 11 */
+/***/ function(module, exports) {
+
+	/** Used for built-in method references. */
+	var objectProto = Object.prototype;
+
+	/**
+	 * Used to resolve the
+	 * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
+	 * of values.
+	 */
+	var nativeObjectToString = objectProto.toString;
+
+	/**
+	 * Converts `value` to a string using `Object.prototype.toString`.
+	 *
+	 * @private
+	 * @param {*} value The value to convert.
+	 * @returns {string} Returns the converted string.
+	 */
+	function objectToString(value) {
+	  return nativeObjectToString.call(value);
+	}
+
+	module.exports = objectToString;
+
+
+/***/ },
+/* 12 */
+/***/ function(module, exports, __webpack_require__) {
+
+	var overArg = __webpack_require__(13);
+
+	/** Built-in value references. */
+	var getPrototype = overArg(Object.getPrototypeOf, Object);
+
+	module.exports = getPrototype;
+
+
+/***/ },
+/* 13 */
 /***/ function(module, exports) {
 
 	/**
 	 * Creates a unary function that invokes `func` with its argument transformed.
 	 *
 	 * @private
 	 * @param {Function} func The function to wrap.
 	 * @param {Function} transform The argument transform.
 	 * @returns {Function} Returns the new function.
 	 */
 	function overArg(func, transform) {
 	  return function(arg) {
 	    return func(transform(arg));
 	  };
 	}
-	
+
 	module.exports = overArg;
 
 
 /***/ },
-/* 8 */
+/* 14 */
 /***/ function(module, exports) {
 
 	/**
 	 * Checks if `value` is object-like. A value is object-like if it's not `null`
 	 * and has a `typeof` result of "object".
 	 *
 	 * @static
 	 * @memberOf _
@@ -609,121 +788,121 @@ var Debugger =
 	 * // => false
 	 *
 	 * _.isObjectLike(null);
 	 * // => false
 	 */
 	function isObjectLike(value) {
 	  return value != null && typeof value == 'object';
 	}
-	
+
 	module.exports = isObjectLike;
 
 
 /***/ },
-/* 9 */
+/* 15 */
 /***/ function(module, exports, __webpack_require__) {
 
 	/* WEBPACK VAR INJECTION */(function(global) {/* global window */
 	'use strict';
-	
-	module.exports = __webpack_require__(10)(global || window || this);
-	
+
+	module.exports = __webpack_require__(16)(global || window || this);
+
 	/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
 
 /***/ },
-/* 10 */
+/* 16 */
 /***/ function(module, exports) {
 
 	'use strict';
-	
+
 	module.exports = function symbolObservablePonyfill(root) {
 		var result;
 		var Symbol = root.Symbol;
-	
+
 		if (typeof Symbol === 'function') {
 			if (Symbol.observable) {
 				result = Symbol.observable;
 			} else {
 				result = Symbol('observable');
 				Symbol.observable = result;
 			}
 		} else {
 			result = '@@observable';
 		}
-	
+
 		return result;
 	};
 
 
 /***/ },
-/* 11 */
+/* 17 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
-	
+
 	exports.__esModule = true;
 	exports["default"] = combineReducers;
-	
+
 	var _createStore = __webpack_require__(4);
-	
+
 	var _isPlainObject = __webpack_require__(5);
-	
+
 	var _isPlainObject2 = _interopRequireDefault(_isPlainObject);
-	
-	var _warning = __webpack_require__(12);
-	
+
+	var _warning = __webpack_require__(18);
+
 	var _warning2 = _interopRequireDefault(_warning);
-	
+
 	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-	
+
 	function getUndefinedStateErrorMessage(key, action) {
 	  var actionType = action && action.type;
 	  var actionName = actionType && '"' + actionType.toString() + '"' || 'an action';
-	
+
 	  return 'Given action ' + actionName + ', reducer "' + key + '" returned undefined. ' + 'To ignore an action, you must explicitly return the previous state.';
 	}
-	
+
 	function getUnexpectedStateShapeWarningMessage(inputState, reducers, action) {
 	  var reducerKeys = Object.keys(reducers);
 	  var argumentName = action && action.type === _createStore.ActionTypes.INIT ? 'initialState argument passed to createStore' : 'previous state received by the reducer';
-	
+
 	  if (reducerKeys.length === 0) {
 	    return 'Store does not have a valid reducer. Make sure the argument passed ' + 'to combineReducers is an object whose values are reducers.';
 	  }
-	
+
 	  if (!(0, _isPlainObject2["default"])(inputState)) {
 	    return 'The ' + argumentName + ' has unexpected type of "' + {}.toString.call(inputState).match(/\s([a-z|A-Z]+)/)[1] + '". Expected argument to be an object with the following ' + ('keys: "' + reducerKeys.join('", "') + '"');
 	  }
-	
+
 	  var unexpectedKeys = Object.keys(inputState).filter(function (key) {
 	    return !reducers.hasOwnProperty(key);
 	  });
-	
+
 	  if (unexpectedKeys.length > 0) {
 	    return 'Unexpected ' + (unexpectedKeys.length > 1 ? 'keys' : 'key') + ' ' + ('"' + unexpectedKeys.join('", "') + '" found in ' + argumentName + '. ') + 'Expected to find one of the known reducer keys instead: ' + ('"' + reducerKeys.join('", "') + '". Unexpected keys will be ignored.');
 	  }
 	}
-	
+
 	function assertReducerSanity(reducers) {
 	  Object.keys(reducers).forEach(function (key) {
 	    var reducer = reducers[key];
 	    var initialState = reducer(undefined, { type: _createStore.ActionTypes.INIT });
-	
+
 	    if (typeof initialState === 'undefined') {
 	      throw new Error('Reducer "' + key + '" returned undefined during initialization. ' + 'If the state passed to the reducer is undefined, you must ' + 'explicitly return the initial state. The initial state may ' + 'not be undefined.');
 	    }
-	
+
 	    var type = '@@redux/PROBE_UNKNOWN_ACTION_' + Math.random().toString(36).substring(7).split('').join('.');
 	    if (typeof reducer(undefined, { type: type }) === 'undefined') {
 	      throw new Error('Reducer "' + key + '" returned undefined when probed with a random type. ' + ('Don\'t try to handle ' + _createStore.ActionTypes.INIT + ' or other actions in "redux/*" ') + 'namespace. They are considered private. Instead, you must return the ' + 'current state for any unknown actions, unless it is undefined, ' + 'in which case you must return the initial state, regardless of the ' + 'action type. The initial state may not be undefined.');
 	    }
 	  });
 	}
-	
+
 	/**
 	 * Turns an object whose values are different reducer functions, into a single
 	 * reducer function. It will call every child reducer, and gather their results
 	 * into a single state object, whose keys correspond to the keys of the passed
 	 * reducer functions.
 	 *
 	 * @param {Object} reducers An object whose values correspond to different
 	 * reducer functions that need to be combined into one. One handy way to obtain
@@ -740,39 +919,39 @@ var Debugger =
 	  var finalReducers = {};
 	  for (var i = 0; i < reducerKeys.length; i++) {
 	    var key = reducerKeys[i];
 	    if (typeof reducers[key] === 'function') {
 	      finalReducers[key] = reducers[key];
 	    }
 	  }
 	  var finalReducerKeys = Object.keys(finalReducers);
-	
+
 	  var sanityError;
 	  try {
 	    assertReducerSanity(finalReducers);
 	  } catch (e) {
 	    sanityError = e;
 	  }
-	
+
 	  return function combination() {
 	    var state = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
 	    var action = arguments[1];
-	
+
 	    if (sanityError) {
 	      throw sanityError;
 	    }
-	
+
 	    if (false) {
 	      var warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action);
 	      if (warningMessage) {
 	        (0, _warning2["default"])(warningMessage);
 	      }
 	    }
-	
+
 	    var hasChanged = false;
 	    var nextState = {};
 	    for (var i = 0; i < finalReducerKeys.length; i++) {
 	      var key = finalReducerKeys[i];
 	      var reducer = finalReducers[key];
 	      var previousStateForKey = state[key];
 	      var nextStateForKey = reducer(previousStateForKey, action);
 	      if (typeof nextStateForKey === 'undefined') {
@@ -782,21 +961,21 @@ var Debugger =
 	      nextState[key] = nextStateForKey;
 	      hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
 	    }
 	    return hasChanged ? nextState : state;
 	  };
 	}
 
 /***/ },
-/* 12 */
+/* 18 */
 /***/ function(module, exports) {
 
 	'use strict';
-	
+
 	exports.__esModule = true;
 	exports["default"] = warning;
 	/**
 	 * Prints a warning in the console if it exists.
 	 *
 	 * @param {String} message The warning message.
 	 * @returns {void}
 	 */
@@ -812,29 +991,29 @@ var Debugger =
 	    // it would pause the execution at this line.
 	    throw new Error(message);
 	    /* eslint-disable no-empty */
 	  } catch (e) {}
 	  /* eslint-enable no-empty */
 	}
 
 /***/ },
-/* 13 */
+/* 19 */
 /***/ function(module, exports) {
 
 	'use strict';
-	
+
 	exports.__esModule = true;
 	exports["default"] = bindActionCreators;
 	function bindActionCreator(actionCreator, dispatch) {
 	  return function () {
 	    return dispatch(actionCreator.apply(undefined, arguments));
 	  };
 	}
-	
+
 	/**
 	 * Turns an object whose values are action creators, into an object with the
 	 * same keys, but with every function wrapped into a `dispatch` call so they
 	 * may be invoked directly. This is just a convenience method, as you can call
 	 * `store.dispatch(MyActionCreators.doSomething())` yourself just fine.
 	 *
 	 * For convenience, you can also pass a single function as the first argument,
 	 * and get a function in return.
@@ -850,51 +1029,51 @@ var Debugger =
 	 * every action creator wrapped into the `dispatch` call. If you passed a
 	 * function as `actionCreators`, the return value will also be a single
 	 * function.
 	 */
 	function bindActionCreators(actionCreators, dispatch) {
 	  if (typeof actionCreators === 'function') {
 	    return bindActionCreator(actionCreators, dispatch);
 	  }
-	
+
 	  if (typeof actionCreators !== 'object' || actionCreators === null) {
 	    throw new Error('bindActionCreators expected an object or a function, instead received ' + (actionCreators === null ? 'null' : typeof actionCreators) + '. ' + 'Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?');
 	  }
-	
+
 	  var keys = Object.keys(actionCreators);
 	  var boundActionCreators = {};
 	  for (var i = 0; i < keys.length; i++) {
 	    var key = keys[i];
 	    var actionCreator = actionCreators[key];
 	    if (typeof actionCreator === 'function') {
 	      boundActionCreators[key] = bindActionCreator(actionCreator, dispatch);
 	    }
 	  }
 	  return boundActionCreators;
 	}
 
 /***/ },
-/* 14 */
+/* 20 */
 /***/ function(module, exports, __webpack_require__) {
 
 	'use strict';
-	
+
 	exports.__esModule = true;
-	
+
 	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; };
-	
+
 	exports["default"] = applyMiddleware;
-	
-	var _compose = __webpack_require__(15);
-	
+
+	var _compose = __webpack_require__(21);
+
 	var _compose2 = _interopRequireDefault(_compose);
-	
+
 	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-	
+
 	/**
 	 * Creates a store enhancer that applies middleware to the dispatch method
 	 * of the Redux store. This is handy for a variety of tasks, such as expressing
 	 * asynchronous actions in a concise manner, or logging every action payload.
 	 *
 	 * See `redux-thunk` package as an example of the Redux middleware.
 	 *
 	 * Because middleware is potentially asynchronous, this should be the first
@@ -905,1016 +1084,434 @@ var Debugger =
 	 *
 	 * @param {...Function} middlewares The middleware chain to be applied.
 	 * @returns {Function} A store enhancer applying the middleware.
 	 */
 	function applyMiddleware() {
 	  for (var _len = arguments.length, middlewares = Array(_len), _key = 0; _key < _len; _key++) {
 	    middlewares[_key] = arguments[_key];
 	  }
-	
+
 	  return function (createStore) {
 	    return function (reducer, initialState, enhancer) {
 	      var store = createStore(reducer, initialState, enhancer);
 	      var _dispatch = store.dispatch;
 	      var chain = [];
-	
+
 	      var middlewareAPI = {
 	        getState: store.getState,
 	        dispatch: function dispatch(action) {
 	          return _dispatch(action);
 	        }
 	      };
 	      chain = middlewares.map(function (middleware) {
 	        return middleware(middlewareAPI);
 	      });
 	      _dispatch = _compose2["default"].apply(undefined, chain)(store.dispatch);
-	
+
 	      return _extends({}, store, {
 	        dispatch: _dispatch
 	      });
 	    };
 	  };
 	}
 
 /***/ },
-/* 15 */
+/* 21 */
 /***/ function(module, exports) {
 
 	"use strict";
-	
+
 	exports.__esModule = true;
 	exports["default"] = compose;
 	/**
 	 * Composes single-argument functions from right to left. The rightmost
 	 * function can take multiple arguments as it provides the signature for
 	 * the resulting composite function.
 	 *
 	 * @param {...Function} funcs The functions to compose.
 	 * @returns {Function} A function obtained by composing the argument functions
 	 * from right to left. For example, compose(f, g, h) is identical to doing
 	 * (...args) => f(g(h(...args))).
 	 */
-	
+
 	function compose() {
 	  for (var _len = arguments.length, funcs = Array(_len), _key = 0; _key < _len; _key++) {
 	    funcs[_key] = arguments[_key];
 	  }
-	
+
 	  if (funcs.length === 0) {
 	    return function (arg) {
 	      return arg;
 	    };
 	  } else {
 	    var _ret = function () {
 	      var last = funcs[funcs.length - 1];
 	      var rest = funcs.slice(0, -1);
 	      return {
 	        v: function v() {
 	          return rest.reduceRight(function (composed, f) {
 	            return f(composed);
 	          }, last.apply(undefined, arguments));
 	        }
 	      };
 	    }();
-	
+
 	    if (typeof _ret === "object") return _ret.v;
 	  }
 	}
 
 /***/ },
-/* 16 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-	
-	module.exports = __webpack_require__(17);
-
-
-/***/ },
-/* 17 */
-/***/ function(module, exports) {
-
-	module.exports = devtoolsRequire("devtools/client/shared/vendor/react-dom");
-
-/***/ },
-/* 18 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* global window, document, DebuggerConfig */
-	
-	var _require = __webpack_require__(3);
-	
-	var bindActionCreators = _require.bindActionCreators;
-	var combineReducers = _require.combineReducers;
-	
-	var _require2 = __webpack_require__(19);
-	
-	var Provider = _require2.Provider;
-	
-	var _require3 = __webpack_require__(28);
-	
-	var DevToolsUtils = _require3.DevToolsUtils;
-	var AppConstants = _require3.AppConstants;
-	
-	var _require4 = __webpack_require__(88);
-	
-	var injectGlobals = _require4.injectGlobals;
-	var debugGlobal = _require4.debugGlobal;
-	
-	var _require5 = __webpack_require__(89);
-	
-	var setConfig = _require5.setConfig;
-	var isEnabled = _require5.isEnabled;
-	var getValue = _require5.getValue;
-	var isDevelopment = _require5.isDevelopment;
-	
-	
-	setConfig(({"environment":"firefox-panel","baseWorkerURL":"resource://devtools/client/debugger/new/","logging":false,"clientLogging":false,"features":{"tabs":true,"sourceMaps":true,"prettyPrint":true}}));
-	
-	// Set various flags before requiring app code.
-	if (isEnabled("logging.client")) {
-	  DevToolsUtils.dumpn.wantLogging = true;
-	}
-	
-	var client = __webpack_require__(141);
-	var getClient = client.getClient;
-	var connectClients = client.connectClients;
-	var startDebugging = client.startDebugging;
-	
-	
-	var Root = __webpack_require__(210);
-	
-	// Using this static variable allows webpack to know at compile-time
-	// to avoid this require and not include it at all in the output.
-	if (false) {
-	  var theme = getValue("theme");
-	  switch (theme) {
-	    case "dark":
-	      require("./lib/themes/dark-theme.css");break;
-	    case "light":
-	      require("./lib/themes/light-theme.css");break;
-	    case "firebug":
-	      require("./lib/themes/firebug-theme.css");break;
-	  }
-	  document.body.parentNode.classList.add(`theme-${ theme }`);
-	
-	  window.L10N = require("./utils/L10N");
-	}
-	
-	function initApp() {
-	  var configureStore = __webpack_require__(216);
-	  var reducers = __webpack_require__(226);
-	  var LandingPage = __webpack_require__(231);
-	
-	  var createStore = configureStore({
-	    log: getValue("logging.actions"),
-	    makeThunkArgs: (args, state) => {
-	      return Object.assign({}, args, { client: getClient(state) });
-	    }
-	  });
-	
-	  var store = createStore(combineReducers(reducers));
-	  var actions = bindActionCreators(__webpack_require__(236), store.dispatch);
-	
-	  if (isDevelopment()) {
-	    AppConstants.DEBUG_JS_MODULES = true;
-	    injectGlobals({ store });
-	  }
-	
-	  return { store, actions, LandingPage };
-	}
-	
-	function renderRoot(_React, _ReactDOM, component, _store) {
-	  var mount = document.querySelector("#mount");
-	
-	  // bail in test environments that do not have a mount
-	  if (!mount) {
-	    return;
-	  }
-	
-	  _ReactDOM.render(_React.createElement(Provider, { store: _store }, Root(component)), mount);
-	}
-	
-	function getTargetFromQuery() {
-	  var href = window.location.href;
-	  var nodeMatch = href.match(/ws=([^&#]*)/);
-	  var firefoxMatch = href.match(/firefox-tab=([^&#]*)/);
-	  var chromeMatch = href.match(/chrome-tab=([^&#]*)/);
-	
-	  if (nodeMatch) {
-	    return { type: "node", param: nodeMatch[1] };
-	  } else if (firefoxMatch) {
-	    return { type: "firefox", param: firefoxMatch[1] };
-	  } else if (chromeMatch) {
-	    return { type: "chrome", param: chromeMatch[1] };
-	  }
-	
-	  return null;
-	}
-	
-	function bootstrap(React, ReactDOM, App, appActions, appStore) {
-	  var connTarget = getTargetFromQuery();
-	  if (connTarget) {
-	    startDebugging(connTarget, appActions).then(tabs => {
-	      renderRoot(React, ReactDOM, App, appStore);
-	    });
-	  } else {
-	    (function () {
-	      var _initApp = initApp();
-	
-	      var store = _initApp.store;
-	      var actions = _initApp.actions;
-	      var LandingPage = _initApp.LandingPage;
-	
-	      renderRoot(React, ReactDOM, LandingPage, store);
-	      connectClients(tabs => actions.newTabs(tabs));
-	    })();
-	  }
-	}
-	
-	module.exports = {
-	  bootstrap,
-	  renderRoot,
-	  debugGlobal,
-	  client
-	};
-
-/***/ },
-/* 19 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-	
-	exports.__esModule = true;
-	exports.connect = exports.Provider = undefined;
-	
-	var _Provider = __webpack_require__(20);
-	
-	var _Provider2 = _interopRequireDefault(_Provider);
-	
-	var _connect = __webpack_require__(23);
-	
-	var _connect2 = _interopRequireDefault(_connect);
-	
-	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-	
-	exports.Provider = _Provider2["default"];
-	exports.connect = _connect2["default"];
-
-/***/ },
-/* 20 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-	
-	exports.__esModule = true;
-	exports["default"] = undefined;
-	
-	var _react = __webpack_require__(2);
-	
-	var _storeShape = __webpack_require__(21);
-	
-	var _storeShape2 = _interopRequireDefault(_storeShape);
-	
-	var _warning = __webpack_require__(22);
-	
-	var _warning2 = _interopRequireDefault(_warning);
-	
-	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-	
-	function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-	
-	function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
-	
-	function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
-	
-	var didWarnAboutReceivingStore = false;
-	function warnAboutReceivingStore() {
-	  if (didWarnAboutReceivingStore) {
-	    return;
-	  }
-	  didWarnAboutReceivingStore = true;
-	
-	  (0, _warning2["default"])('<Provider> does not support changing `store` on the fly. ' + 'It is most likely that you see this error because you updated to ' + 'Redux 2.x and React Redux 2.x which no longer hot reload reducers ' + 'automatically. See https://github.com/reactjs/react-redux/releases/' + 'tag/v2.0.0 for the migration instructions.');
-	}
-	
-	var Provider = function (_Component) {
-	  _inherits(Provider, _Component);
-	
-	  Provider.prototype.getChildContext = function getChildContext() {
-	    return { store: this.store };
-	  };
-	
-	  function Provider(props, context) {
-	    _classCallCheck(this, Provider);
-	
-	    var _this = _possibleConstructorReturn(this, _Component.call(this, props, context));
-	
-	    _this.store = props.store;
-	    return _this;
-	  }
-	
-	  Provider.prototype.render = function render() {
-	    var children = this.props.children;
-	
-	    return _react.Children.only(children);
-	  };
-	
-	  return Provider;
-	}(_react.Component);
-	
-	exports["default"] = Provider;
-	
-	if (false) {
-	  Provider.prototype.componentWillReceiveProps = function (nextProps) {
-	    var store = this.store;
-	    var nextStore = nextProps.store;
-	
-	    if (store !== nextStore) {
-	      warnAboutReceivingStore();
-	    }
-	  };
-	}
-	
-	Provider.propTypes = {
-	  store: _storeShape2["default"].isRequired,
-	  children: _react.PropTypes.element.isRequired
-	};
-	Provider.childContextTypes = {
-	  store: _storeShape2["default"].isRequired
-	};
-
-/***/ },
-/* 21 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-	
-	exports.__esModule = true;
-	
-	var _react = __webpack_require__(2);
-	
-	exports["default"] = _react.PropTypes.shape({
-	  subscribe: _react.PropTypes.func.isRequired,
-	  dispatch: _react.PropTypes.func.isRequired,
-	  getState: _react.PropTypes.func.isRequired
-	});
-
-/***/ },
 /* 22 */
-/***/ function(module, exports) {
-
-	'use strict';
-	
-	exports.__esModule = true;
-	exports["default"] = warning;
-	/**
-	 * Prints a warning in the console if it exists.
-	 *
-	 * @param {String} message The warning message.
-	 * @returns {void}
-	 */
-	function warning(message) {
-	  /* eslint-disable no-console */
-	  if (typeof console !== 'undefined' && typeof console.error === 'function') {
-	    console.error(message);
-	  }
-	  /* eslint-enable no-console */
-	  try {
-	    // This error was thrown as a convenience so that you can use this stack
-	    // to find the callsite that caused this warning to fire.
-	    throw new Error(message);
-	    /* eslint-disable no-empty */
-	  } catch (e) {}
-	  /* eslint-enable no-empty */
-	}
-
-/***/ },
-/* 23 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-	
-	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; };
-	
-	exports.__esModule = true;
-	exports["default"] = connect;
-	
-	var _react = __webpack_require__(2);
-	
-	var _storeShape = __webpack_require__(21);
-	
-	var _storeShape2 = _interopRequireDefault(_storeShape);
-	
-	var _shallowEqual = __webpack_require__(24);
-	
-	var _shallowEqual2 = _interopRequireDefault(_shallowEqual);
-	
-	var _wrapActionCreators = __webpack_require__(25);
-	
-	var _wrapActionCreators2 = _interopRequireDefault(_wrapActionCreators);
-	
-	var _warning = __webpack_require__(22);
-	
-	var _warning2 = _interopRequireDefault(_warning);
-	
-	var _isPlainObject = __webpack_require__(5);
-	
-	var _isPlainObject2 = _interopRequireDefault(_isPlainObject);
-	
-	var _hoistNonReactStatics = __webpack_require__(26);
-	
-	var _hoistNonReactStatics2 = _interopRequireDefault(_hoistNonReactStatics);
-	
-	var _invariant = __webpack_require__(27);
-	
-	var _invariant2 = _interopRequireDefault(_invariant);
-	
-	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-	
-	function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-	
-	function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
-	
-	function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
-	
-	var defaultMapStateToProps = function defaultMapStateToProps(state) {
-	  return {};
-	}; // eslint-disable-line no-unused-vars
-	var defaultMapDispatchToProps = function defaultMapDispatchToProps(dispatch) {
-	  return { dispatch: dispatch };
-	};
-	var defaultMergeProps = function defaultMergeProps(stateProps, dispatchProps, parentProps) {
-	  return _extends({}, parentProps, stateProps, dispatchProps);
-	};
-	
-	function getDisplayName(WrappedComponent) {
-	  return WrappedComponent.displayName || WrappedComponent.name || 'Component';
-	}
-	
-	var errorObject = { value: null };
-	function tryCatch(fn, ctx) {
-	  try {
-	    return fn.apply(ctx);
-	  } catch (e) {
-	    errorObject.value = e;
-	    return errorObject;
-	  }
-	}
-	
-	// Helps track hot reloading.
-	var nextVersion = 0;
-	
-	function connect(mapStateToProps, mapDispatchToProps, mergeProps) {
-	  var options = arguments.length <= 3 || arguments[3] === undefined ? {} : arguments[3];
-	
-	  var shouldSubscribe = Boolean(mapStateToProps);
-	  var mapState = mapStateToProps || defaultMapStateToProps;
-	
-	  var mapDispatch = undefined;
-	  if (typeof mapDispatchToProps === 'function') {
-	    mapDispatch = mapDispatchToProps;
-	  } else if (!mapDispatchToProps) {
-	    mapDispatch = defaultMapDispatchToProps;
-	  } else {
-	    mapDispatch = (0, _wrapActionCreators2["default"])(mapDispatchToProps);
-	  }
-	
-	  var finalMergeProps = mergeProps || defaultMergeProps;
-	  var _options$pure = options.pure;
-	  var pure = _options$pure === undefined ? true : _options$pure;
-	  var _options$withRef = options.withRef;
-	  var withRef = _options$withRef === undefined ? false : _options$withRef;
-	
-	  var checkMergedEquals = pure && finalMergeProps !== defaultMergeProps;
-	
-	  // Helps track hot reloading.
-	  var version = nextVersion++;
-	
-	  return function wrapWithConnect(WrappedComponent) {
-	    var connectDisplayName = 'Connect(' + getDisplayName(WrappedComponent) + ')';
-	
-	    function checkStateShape(props, methodName) {
-	      if (!(0, _isPlainObject2["default"])(props)) {
-	        (0, _warning2["default"])(methodName + '() in ' + connectDisplayName + ' must return a plain object. ' + ('Instead received ' + props + '.'));
-	      }
-	    }
-	
-	    function computeMergedProps(stateProps, dispatchProps, parentProps) {
-	      var mergedProps = finalMergeProps(stateProps, dispatchProps, parentProps);
-	      if (false) {
-	        checkStateShape(mergedProps, 'mergeProps');
-	      }
-	      return mergedProps;
-	    }
-	
-	    var Connect = function (_Component) {
-	      _inherits(Connect, _Component);
-	
-	      Connect.prototype.shouldComponentUpdate = function shouldComponentUpdate() {
-	        return !pure || this.haveOwnPropsChanged || this.hasStoreStateChanged;
-	      };
-	
-	      function Connect(props, context) {
-	        _classCallCheck(this, Connect);
-	
-	        var _this = _possibleConstructorReturn(this, _Component.call(this, props, context));
-	
-	        _this.version = version;
-	        _this.store = props.store || context.store;
-	
-	        (0, _invariant2["default"])(_this.store, 'Could not find "store" in either the context or ' + ('props of "' + connectDisplayName + '". ') + 'Either wrap the root component in a <Provider>, ' + ('or explicitly pass "store" as a prop to "' + connectDisplayName + '".'));
-	
-	        var storeState = _this.store.getState();
-	        _this.state = { storeState: storeState };
-	        _this.clearCache();
-	        return _this;
-	      }
-	
-	      Connect.prototype.computeStateProps = function computeStateProps(store, props) {
-	        if (!this.finalMapStateToProps) {
-	          return this.configureFinalMapState(store, props);
-	        }
-	
-	        var state = store.getState();
-	        var stateProps = this.doStatePropsDependOnOwnProps ? this.finalMapStateToProps(state, props) : this.finalMapStateToProps(state);
-	
-	        if (false) {
-	          checkStateShape(stateProps, 'mapStateToProps');
-	        }
-	        return stateProps;
-	      };
-	
-	      Connect.prototype.configureFinalMapState = function configureFinalMapState(store, props) {
-	        var mappedState = mapState(store.getState(), props);
-	        var isFactory = typeof mappedState === 'function';
-	
-	        this.finalMapStateToProps = isFactory ? mappedState : mapState;
-	        this.doStatePropsDependOnOwnProps = this.finalMapStateToProps.length !== 1;
-	
-	        if (isFactory) {
-	          return this.computeStateProps(store, props);
-	        }
-	
-	        if (false) {
-	          checkStateShape(mappedState, 'mapStateToProps');
-	        }
-	        return mappedState;
-	      };
-	
-	      Connect.prototype.computeDispatchProps = function computeDispatchProps(store, props) {
-	        if (!this.finalMapDispatchToProps) {
-	          return this.configureFinalMapDispatch(store, props);
-	        }
-	
-	        var dispatch = store.dispatch;
-	
-	        var dispatchProps = this.doDispatchPropsDependOnOwnProps ? this.finalMapDispatchToProps(dispatch, props) : this.finalMapDispatchToProps(dispatch);
-	
-	        if (false) {
-	          checkStateShape(dispatchProps, 'mapDispatchToProps');
-	        }
-	        return dispatchProps;
-	      };
-	
-	      Connect.prototype.configureFinalMapDispatch = function configureFinalMapDispatch(store, props) {
-	        var mappedDispatch = mapDispatch(store.dispatch, props);
-	        var isFactory = typeof mappedDispatch === 'function';
-	
-	        this.finalMapDispatchToProps = isFactory ? mappedDispatch : mapDispatch;
-	        this.doDispatchPropsDependOnOwnProps = this.finalMapDispatchToProps.length !== 1;
-	
-	        if (isFactory) {
-	          return this.computeDispatchProps(store, props);
-	        }
-	
-	        if (false) {
-	          checkStateShape(mappedDispatch, 'mapDispatchToProps');
-	        }
-	        return mappedDispatch;
-	      };
-	
-	      Connect.prototype.updateStatePropsIfNeeded = function updateStatePropsIfNeeded() {
-	        var nextStateProps = this.computeStateProps(this.store, this.props);
-	        if (this.stateProps && (0, _shallowEqual2["default"])(nextStateProps, this.stateProps)) {
-	          return false;
-	        }
-	
-	        this.stateProps = nextStateProps;
-	        return true;
-	      };
-	
-	      Connect.prototype.updateDispatchPropsIfNeeded = function updateDispatchPropsIfNeeded() {
-	        var nextDispatchProps = this.computeDispatchProps(this.store, this.props);
-	        if (this.dispatchProps && (0, _shallowEqual2["default"])(nextDispatchProps, this.dispatchProps)) {
-	          return false;
-	        }
-	
-	        this.dispatchProps = nextDispatchProps;
-	        return true;
-	      };
-	
-	      Connect.prototype.updateMergedPropsIfNeeded = function updateMergedPropsIfNeeded() {
-	        var nextMergedProps = computeMergedProps(this.stateProps, this.dispatchProps, this.props);
-	        if (this.mergedProps && checkMergedEquals && (0, _shallowEqual2["default"])(nextMergedProps, this.mergedProps)) {
-	          return false;
-	        }
-	
-	        this.mergedProps = nextMergedProps;
-	        return true;
-	      };
-	
-	      Connect.prototype.isSubscribed = function isSubscribed() {
-	        return typeof this.unsubscribe === 'function';
-	      };
-	
-	      Connect.prototype.trySubscribe = function trySubscribe() {
-	        if (shouldSubscribe && !this.unsubscribe) {
-	          this.unsubscribe = this.store.subscribe(this.handleChange.bind(this));
-	          this.handleChange();
-	        }
-	      };
-	
-	      Connect.prototype.tryUnsubscribe = function tryUnsubscribe() {
-	        if (this.unsubscribe) {
-	          this.unsubscribe();
-	          this.unsubscribe = null;
-	        }
-	      };
-	
-	      Connect.prototype.componentDidMount = function componentDidMount() {
-	        this.trySubscribe();
-	      };
-	
-	      Connect.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) {
-	        if (!pure || !(0, _shallowEqual2["default"])(nextProps, this.props)) {
-	          this.haveOwnPropsChanged = true;
-	        }
-	      };
-	
-	      Connect.prototype.componentWillUnmount = function componentWillUnmount() {
-	        this.tryUnsubscribe();
-	        this.clearCache();
-	      };
-	
-	      Connect.prototype.clearCache = function clearCache() {
-	        this.dispatchProps = null;
-	        this.stateProps = null;
-	        this.mergedProps = null;
-	        this.haveOwnPropsChanged = true;
-	        this.hasStoreStateChanged = true;
-	        this.haveStatePropsBeenPrecalculated = false;
-	        this.statePropsPrecalculationError = null;
-	        this.renderedElement = null;
-	        this.finalMapDispatchToProps = null;
-	        this.finalMapStateToProps = null;
-	      };
-	
-	      Connect.prototype.handleChange = function handleChange() {
-	        if (!this.unsubscribe) {
-	          return;
-	        }
-	
-	        var storeState = this.store.getState();
-	        var prevStoreState = this.state.storeState;
-	        if (pure && prevStoreState === storeState) {
-	          return;
-	        }
-	
-	        if (pure && !this.doStatePropsDependOnOwnProps) {
-	          var haveStatePropsChanged = tryCatch(this.updateStatePropsIfNeeded, this);
-	          if (!haveStatePropsChanged) {
-	            return;
-	          }
-	          if (haveStatePropsChanged === errorObject) {
-	            this.statePropsPrecalculationError = errorObject.value;
-	          }
-	          this.haveStatePropsBeenPrecalculated = true;
-	        }
-	
-	        this.hasStoreStateChanged = true;
-	        this.setState({ storeState: storeState });
-	      };
-	
-	      Connect.prototype.getWrappedInstance = function getWrappedInstance() {
-	        (0, _invariant2["default"])(withRef, 'To access the wrapped instance, you need to specify ' + '{ withRef: true } as the fourth argument of the connect() call.');
-	
-	        return this.refs.wrappedInstance;
-	      };
-	
-	      Connect.prototype.render = function render() {
-	        var haveOwnPropsChanged = this.haveOwnPropsChanged;
-	        var hasStoreStateChanged = this.hasStoreStateChanged;
-	        var haveStatePropsBeenPrecalculated = this.haveStatePropsBeenPrecalculated;
-	        var statePropsPrecalculationError = this.statePropsPrecalculationError;
-	        var renderedElement = this.renderedElement;
-	
-	        this.haveOwnPropsChanged = false;
-	        this.hasStoreStateChanged = false;
-	        this.haveStatePropsBeenPrecalculated = false;
-	        this.statePropsPrecalculationError = null;
-	
-	        if (statePropsPrecalculationError) {
-	          throw statePropsPrecalculationError;
-	        }
-	
-	        var shouldUpdateStateProps = true;
-	        var shouldUpdateDispatchProps = true;
-	        if (pure && renderedElement) {
-	          shouldUpdateStateProps = hasStoreStateChanged || haveOwnPropsChanged && this.doStatePropsDependOnOwnProps;
-	          shouldUpdateDispatchProps = haveOwnPropsChanged && this.doDispatchPropsDependOnOwnProps;
-	        }
-	
-	        var haveStatePropsChanged = false;
-	        var haveDispatchPropsChanged = false;
-	        if (haveStatePropsBeenPrecalculated) {
-	          haveStatePropsChanged = true;
-	        } else if (shouldUpdateStateProps) {
-	          haveStatePropsChanged = this.updateStatePropsIfNeeded();
-	        }
-	        if (shouldUpdateDispatchProps) {
-	          haveDispatchPropsChanged = this.updateDispatchPropsIfNeeded();
-	        }
-	
-	        var haveMergedPropsChanged = true;
-	        if (haveStatePropsChanged || haveDispatchPropsChanged || haveOwnPropsChanged) {
-	          haveMergedPropsChanged = this.updateMergedPropsIfNeeded();
-	        } else {
-	          haveMergedPropsChanged = false;
-	        }
-	
-	        if (!haveMergedPropsChanged && renderedElement) {
-	          return renderedElement;
-	        }
-	
-	        if (withRef) {
-	          this.renderedElement = (0, _react.createElement)(WrappedComponent, _extends({}, this.mergedProps, {
-	            ref: 'wrappedInstance'
-	          }));
-	        } else {
-	          this.renderedElement = (0, _react.createElement)(WrappedComponent, this.mergedProps);
-	        }
-	
-	        return this.renderedElement;
-	      };
-	
-	      return Connect;
-	    }(_react.Component);
-	
-	    Connect.displayName = connectDisplayName;
-	    Connect.WrappedComponent = WrappedComponent;
-	    Connect.contextTypes = {
-	      store: _storeShape2["default"]
-	    };
-	    Connect.propTypes = {
-	      store: _storeShape2["default"]
-	    };
-	
-	    if (false) {
-	      Connect.prototype.componentWillUpdate = function componentWillUpdate() {
-	        if (this.version === version) {
-	          return;
-	        }
-	
-	        // We are hot reloading!
-	        this.version = version;
-	        this.trySubscribe();
-	        this.clearCache();
-	      };
-	    }
-	
-	    return (0, _hoistNonReactStatics2["default"])(Connect, WrappedComponent);
-	  };
-	}
-
-/***/ },
-/* 24 */
-/***/ function(module, exports) {
-
-	"use strict";
-	
-	exports.__esModule = true;
-	exports["default"] = shallowEqual;
-	function shallowEqual(objA, objB) {
-	  if (objA === objB) {
-	    return true;
-	  }
-	
-	  var keysA = Object.keys(objA);
-	  var keysB = Object.keys(objB);
-	
-	  if (keysA.length !== keysB.length) {
-	    return false;
-	  }
-	
-	  // Test for A's keys different from B.
-	  var hasOwn = Object.prototype.hasOwnProperty;
-	  for (var i = 0; i < keysA.length; i++) {
-	    if (!hasOwn.call(objB, keysA[i]) || objA[keysA[i]] !== objB[keysA[i]]) {
-	      return false;
-	    }
-	  }
-	
-	  return true;
-	}
-
-/***/ },
-/* 25 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-	
-	exports.__esModule = true;
-	exports["default"] = wrapActionCreators;
-	
-	var _redux = __webpack_require__(3);
-	
-	function wrapActionCreators(actionCreators) {
-	  return function (dispatch) {
-	    return (0, _redux.bindActionCreators)(actionCreators, dispatch);
-	  };
-	}
-
-/***/ },
-/* 26 */
-/***/ function(module, exports) {
-
-	/**
-	 * Copyright 2015, Yahoo! Inc.
-	 * Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
-	 */
-	'use strict';
-	
-	var REACT_STATICS = {
-	    childContextTypes: true,
-	    contextTypes: true,
-	    defaultProps: true,
-	    displayName: true,
-	    getDefaultProps: true,
-	    mixins: true,
-	    propTypes: true,
-	    type: true
-	};
-	
-	var KNOWN_STATICS = {
-	    name: true,
-	    length: true,
-	    prototype: true,
-	    caller: true,
-	    arguments: true,
-	    arity: true
-	};
-	
-	var isGetOwnPropertySymbolsAvailable = typeof Object.getOwnPropertySymbols === 'function';
-	
-	module.exports = function hoistNonReactStatics(targetComponent, sourceComponent, customStatics) {
-	    if (typeof sourceComponent !== 'string') { // don't hoist over string (html) components
-	        var keys = Object.getOwnPropertyNames(sourceComponent);
-	
-	        /* istanbul ignore else */
-	        if (isGetOwnPropertySymbolsAvailable) {
-	            keys = keys.concat(Object.getOwnPropertySymbols(sourceComponent));
-	        }
-	
-	        for (var i = 0; i < keys.length; ++i) {
-	            if (!REACT_STATICS[keys[i]] && !KNOWN_STATICS[keys[i]] && (!customStatics || !customStatics[keys[i]])) {
-	                try {
-	                    targetComponent[keys[i]] = sourceComponent[keys[i]];
-	                } catch (error) {
-	
-	                }
-	            }
-	        }
-	    }
-	
-	    return targetComponent;
-	};
-
-
-/***/ },
-/* 27 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/**
-	 * Copyright 2013-2015, Facebook, Inc.
+/***/ function(module, exports, __webpack_require__) {
+
+	/**
+	 * ReactDOM v15.3.1
+	 *
+	 * Copyright 2013-present, Facebook, Inc.
 	 * All rights reserved.
 	 *
 	 * This source code is licensed under the BSD-style license found in the
 	 * LICENSE file in the root directory of this source tree. An additional grant
 	 * of patent rights can be found in the PATENTS file in the same directory.
-	 */
-	
-	'use strict';
-	
-	/**
-	 * Use invariant() to assert state which your program assumes to be true.
-	 *
-	 * Provide sprintf-style format (only %s is supported) and arguments
-	 * to provide information about what broke and what you were
-	 * expecting.
-	 *
-	 * The invariant message will be stripped in production, but the invariant
-	 * will remain to ensure logic does not differ in production.
-	 */
-	
-	var invariant = function(condition, format, a, b, c, d, e, f) {
-	  if (false) {
-	    if (format === undefined) {
-	      throw new Error('invariant requires an error message argument');
-	    }
-	  }
-	
-	  if (!condition) {
-	    var error;
-	    if (format === undefined) {
-	      error = new Error(
-	        'Minified exception occurred; use the non-minified dev environment ' +
-	        'for the full error message and additional helpful warnings.'
-	      );
-	    } else {
-	      var args = [a, b, c, d, e, f];
-	      var argIndex = 0;
-	      error = new Error(
-	        format.replace(/%s/g, function() { return args[argIndex++]; })
-	      );
-	      error.name = 'Invariant Violation';
-	    }
-	
-	    error.framesToPop = 1; // we don't care about invariant's own frame
-	    throw error;
-	  }
-	};
-	
-	module.exports = invariant;
-
-
-/***/ },
-/* 28 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var _require = __webpack_require__(29);
-	
-	var KeyShortcuts = _require.KeyShortcuts;
-	
-	var _require2 = __webpack_require__(67);
-	
-	var DebuggerTransport = _require2.DebuggerTransport;
-	
-	var _require3 = __webpack_require__(79);
-	
-	var DebuggerClient = _require3.DebuggerClient;
-	
-	var PrefsHelper = __webpack_require__(83).PrefsHelper;
-	
-	var _require4 = __webpack_require__(84);
-	
-	var TargetFactory = _require4.TargetFactory;
-	
-	var DevToolsUtils = __webpack_require__(68);
-	var AppConstants = __webpack_require__(70);
-	var EventEmitter = __webpack_require__(60);
-	var WebsocketTransport = __webpack_require__(85);
-	var Menu = __webpack_require__(86);
-	var MenuItem = __webpack_require__(87);
-	
+	 *
+	 */
+	// Based off https://github.com/ForbesLindesay/umd/blob/master/template.js
+	;(function(f) {
+	  // CommonJS
+	  if (true) {
+	    module.exports = f(__webpack_require__(2));
+
+	  // RequireJS
+	  } else if (typeof define === "function" && define.amd) {
+	    define(['react'], f);
+
+	  // <script>
+	  } else {
+	    var g;
+	    if (typeof window !== "undefined") {
+	      g = window;
+	    } else if (typeof global !== "undefined") {
+	      g = global;
+	    } else if (typeof self !== "undefined") {
+	      g = self;
+	    } else {
+	      // works providing we're not in "use strict";
+	      // needed for Java 8 Nashorn
+	      // see https://github.com/facebook/react/issues/3037
+	      g = this;
+	    }
+	    g.ReactDOM = f(g.React);
+	  }
+
+	})(function(React) {
+	  return React.__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
+	});
+
+
+/***/ },
+/* 23 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const { Task } = __webpack_require__(24);
+	const firefox = __webpack_require__(25);
+	const chrome = __webpack_require__(116);
+	const { createSource } = __webpack_require__(115);
+
+	let clientType = null;
+	function getClient() {
+	  if (clientType === "chrome" || clientType === "node") {
+	    return chrome.clientCommands;
+	  }
+
+	  return firefox.clientCommands;
+	}
+
+	function startDebugging(connTarget, actions) {
+	  if (connTarget.type === "node") {
+	    return startDebuggingNode(connTarget.param, actions);
+	  }
+
+	  const target = connTarget.type === "chrome" ? chrome : firefox;
+	  return startDebuggingTab(target, connTarget.param, actions);
+	}
+
+	function startDebuggingNode(tabId, actions) {
+	  return Task.spawn(function* () {
+	    clientType = "node";
+
+	    const tabs = yield chrome.connectNodeClient();
+	    const tab = tabs.find(t => t.id.indexOf(tabId) !== -1);
+
+	    yield chrome.connectNode(tab.tab);
+	    chrome.initPage(actions, { clientType });
+
+	    return { tabs, tab, client: chrome };
+	  });
+	}
+
+	function startDebuggingTab(targetEnv, tabId, actions) {
+	  return Task.spawn(function* () {
+	    const tabs = yield targetEnv.connectClient();
+	    const tab = tabs.find(t => t.id.indexOf(tabId) !== -1);
+	    yield targetEnv.connectTab(tab.tab);
+
+	    clientType = targetEnv === firefox ? "firefox" : "chrome";
+	    targetEnv.initPage(actions, { clientType });
+
+	    return { tabs, tab, client: targetEnv };
+	  });
+	}
+
+	module.exports = {
+	  getClient,
+	  startDebugging,
+	  firefox,
+	  chrome,
+	  createSource
+	};
+
+
+/***/ },
+/* 24 */
+/***/ function(module, exports) {
+
+	/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+	/* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */
+	/* 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 object provides the public module functions.
+	 */
+	var Task = {
+	  // XXX: Not sure if this works in all cases...
+	  async: function (task) {
+	    return function () {
+	      return Task.spawn(task, this, arguments);
+	    };
+	  },
+
+	  /**
+	   * Creates and starts a new task.
+	   * @param task A generator function
+	   * @return A promise, resolved when the task terminates
+	   */
+	  spawn: function (task, scope, args) {
+	    return new Promise(function (resolve, reject) {
+	      var iterator = task.apply(scope, args);
+
+	      var callNext = lastValue => {
+	        var iteration = iterator.next(lastValue);
+	        Promise.resolve(iteration.value).then(value => {
+	          if (iteration.done) {
+	            resolve(value);
+	          } else {
+	            callNext(value);
+	          }
+	        }).catch(error => {
+	          reject(error);
+	          iterator.throw(error);
+	        });
+	      };
+
+	      callNext(undefined);
+	    });
+	  }
+	};
+
+	module.exports = { Task };
+
+/***/ },
+/* 25 */
+/***/ function(module, exports, __webpack_require__) {
+
+	var _require = __webpack_require__(26),
+	    DebuggerClient = _require.DebuggerClient,
+	    DebuggerTransport = _require.DebuggerTransport,
+	    TargetFactory = _require.TargetFactory,
+	    WebsocketTransport = _require.WebsocketTransport;
+
+	var _require2 = __webpack_require__(65),
+	    getValue = _require2.getValue;
+
+	var _require3 = __webpack_require__(113),
+	    setupCommands = _require3.setupCommands,
+	    clientCommands = _require3.clientCommands;
+
+	var _require4 = __webpack_require__(114),
+	    setupEvents = _require4.setupEvents,
+	    clientEvents = _require4.clientEvents;
+
+	var debuggerClient = null;
+	var threadClient = null;
+	var tabTarget = null;
+
+	function getThreadClient() {
+	  return threadClient;
+	}
+
+	function setThreadClient(client) {
+	  threadClient = client;
+	}
+
+	function getTabTarget() {
+	  return tabTarget;
+	}
+
+	function setTabTarget(target) {
+	  tabTarget = target;
+	}
+
+	function lookupTabTarget(tab) {
+	  var options = { client: debuggerClient, form: tab, chrome: false };
+	  return TargetFactory.forRemoteTab(options);
+	}
+
+	function createTabs(tabs) {
+	  return tabs.map(tab => {
+	    return {
+	      title: tab.title,
+	      url: tab.url,
+	      id: tab.actor,
+	      tab,
+	      clientType: "firefox"
+	    };
+	  });
+	}
+
+	function connectClient() {
+	  var useProxy = !getValue("firefox.webSocketConnection");
+	  var firefoxHost = getValue(useProxy ? "firefox.proxyHost" : "firefox.webSocketHost");
+
+	  var socket = new WebSocket(`ws://${ firefoxHost }`);
+	  var transport = useProxy ? new DebuggerTransport(socket) : new WebsocketTransport(socket);
+
+	  return new Promise((resolve, reject) => {
+	    debuggerClient = new DebuggerClient(transport);
+	    debuggerClient.connect().then(() => {
+	      if (debuggerClient !== null) {
+	        return debuggerClient.listTabs().then(response => {
+	          resolve(createTabs(response.tabs));
+	        });
+	      }
+	      return resolve([]);
+	    }).catch(err => {
+	      console.log(err);
+	      resolve([]);
+	    });
+	  });
+	}
+
+	function connectTab(tab) {
+	  return new Promise((resolve, reject) => {
+	    window.addEventListener("beforeunload", () => {
+	      var tt = getTabTarget();
+	      if (tt !== null) {
+	        tt.destroy();
+	      }
+	    });
+
+	    lookupTabTarget(tab).then(target => {
+	      tabTarget = target;
+	      target.activeTab.attachThread({}, (res, _threadClient) => {
+	        threadClient = _threadClient;
+	        threadClient.resume();
+	        resolve();
+	      });
+	    });
+	  });
+	}
+
+	function initPage(actions) {
+	  tabTarget = getTabTarget();
+	  threadClient = getThreadClient();
+
+	  if (!threadClient || !tabTarget || !actions) {
+	    return;
+	  }
+
+	  setupCommands({ threadClient, tabTarget, debuggerClient });
+
+	  if (actions) {
+	    // Listen to all the requested events.
+	    setupEvents({ threadClient, actions });
+	    Object.keys(clientEvents).forEach(eventName => {
+	      if (threadClient) {
+	        threadClient.addListener(eventName, clientEvents[eventName]);
+	      }
+	    });
+	  }
+	}
+
+	module.exports = {
+	  connectClient,
+	  connectTab,
+	  clientCommands,
+	  clientEvents,
+	  getThreadClient,
+	  setThreadClient,
+	  getTabTarget,
+	  setTabTarget,
+	  initPage
+	};
+
+/***/ },
+/* 26 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const { KeyShortcuts } = __webpack_require__(27);
+	const { DebuggerTransport } = __webpack_require__(41);
+	const { DebuggerClient } = __webpack_require__(53);
+	const PrefsHelper = __webpack_require__(57).PrefsHelper;
+	const { TargetFactory } = __webpack_require__(58);
+	const DevToolsUtils = __webpack_require__(42);
+	const AppConstants = __webpack_require__(44);
+	const EventEmitter = __webpack_require__(34);
+	const WebsocketTransport = __webpack_require__(59);
+	const Menu = __webpack_require__(60);
+	const MenuItem = __webpack_require__(61);
+	const Tree = __webpack_require__(62);
+	const sourceUtils = __webpack_require__(63);
+	const frame = __webpack_require__(64);
+
 	module.exports = {
 	  KeyShortcuts,
 	  PrefsHelper,
 	  DebuggerClient,
 	  DebuggerTransport,
 	  TargetFactory,
 	  DevToolsUtils,
 	  AppConstants,
 	  EventEmitter,
 	  WebsocketTransport,
 	  Menu,
-	  MenuItem
-	};
-
-/***/ },
-/* 29 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
-	
+	  MenuItem,
+	  Tree,
+	  sourceUtils,
+	  frame
+	};
+
+
+/***/ },
+/* 27 */
+/***/ function(module, exports, __webpack_require__) {
+
 	/* 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/. */
-	
-	var _require = __webpack_require__(30);
-	
-	var appinfo = _require.Services.appinfo;
-	
-	var EventEmitter = __webpack_require__(60);
-	var isOSX = appinfo.OS === "Darwin";
+
+	const { Services: { appinfo }} = __webpack_require__(28);
+	const EventEmitter = __webpack_require__(34);
+	const isOSX = appinfo.OS === "Darwin";
 	"use strict";
-	
+
 	// List of electron keys mapped to DOM API (DOM_VK_*) key code
-	var ElectronKeysMapping = {
+	const ElectronKeysMapping = {
 	  "F1": "DOM_VK_F1",
 	  "F2": "DOM_VK_F2",
 	  "F3": "DOM_VK_F3",
 	  "F4": "DOM_VK_F4",
 	  "F5": "DOM_VK_F5",
 	  "F6": "DOM_VK_F6",
 	  "F7": "DOM_VK_F7",
 	  "F8": "DOM_VK_F8",
@@ -1949,72 +1546,69 @@ var Debugger =
 	  "PageUp": "DOM_VK_PAGE_UP",
 	  "PageDown": "DOM_VK_PAGE_DOWN",
 	  "Escape": "DOM_VK_ESCAPE",
 	  "Esc": "DOM_VK_ESCAPE",
 	  "Tab": "DOM_VK_TAB",
 	  "VolumeUp": "DOM_VK_VOLUME_UP",
 	  "VolumeDown": "DOM_VK_VOLUME_DOWN",
 	  "VolumeMute": "DOM_VK_VOLUME_MUTE",
-	  "PrintScreen": "DOM_VK_PRINTSCREEN"
-	};
-	
+	  "PrintScreen": "DOM_VK_PRINTSCREEN",
+	};
+
 	/**
 	 * Helper to listen for keyboard events decribed in .properties file.
 	 *
 	 * let shortcuts = new KeyShortcuts({
 	 *   window
 	 * });
 	 * shortcuts.on("Ctrl+F", event => {
 	 *   // `event` is the KeyboardEvent which relates to the key shortcuts
 	 * });
 	 *
 	 * @param DOMWindow window
 	 *        The window object of the document to listen events from.
 	 * @param DOMElement target
 	 *        Optional DOM Element on which we should listen events from.
 	 *        If omitted, we listen for all events fired on `window`.
 	 */
-	function KeyShortcuts(_ref) {
-	  var window = _ref.window;
-	  var target = _ref.target;
-	
+	function KeyShortcuts({ window, target }) {
 	  this.window = window;
 	  this.target = target || window;
 	  this.keys = new Map();
 	  this.eventEmitter = new EventEmitter();
 	  this.target.addEventListener("keydown", this);
 	}
-	
+
 	/*
 	 * Parse an electron-like key string and return a normalized object which
 	 * allow efficient match on DOM key event. The normalized object matches DOM
 	 * API.
 	 *
 	 * @param DOMWindow window
 	 *        Any DOM Window object, just to fetch its `KeyboardEvent` object
 	 * @param String str
 	 *        The shortcut string to parse, following this document:
 	 *        https://github.com/electron/electron/blob/master/docs/api/accelerator.md
 	 */
-	KeyShortcuts.parseElectronKey = function (window, str) {
-	  var modifiers = str.split("+");
-	  var key = modifiers.pop();
-	
-	  var shortcut = {
+	KeyShortcuts.parseElectronKey = function(window, str) {
+	  let modifiers = str.split("+");
+	  let key = modifiers.pop();
+
+	  let shortcut = {
 	    ctrl: false,
 	    meta: false,
 	    alt: false,
 	    shift: false,
 	    // Set for character keys
 	    key: undefined,
 	    // Set for non-character keys
-	    keyCode: undefined
-	  };
-	  for (var mod of modifiers) {
+	    keyCode: undefined,
+	  };
+	  for (let mod of modifiers) {
 	    if (mod === "Alt") {
 	      shortcut.alt = true;
 	    } else if (["Command", "Cmd"].includes(mod)) {
 	      shortcut.meta = true;
 	    } else if (["CommandOrControl", "CmdOrCtrl"].includes(mod)) {
 	      if (isOSX) {
 	        shortcut.meta = true;
 	      } else {
@@ -2024,3004 +1618,523 @@ var Debugger =
 	      shortcut.ctrl = true;
 	    } else if (mod === "Shift") {
 	      shortcut.shift = true;
 	    } else {
 	      console.error("Unsupported modifier:", mod, "from key:", str);
 	      return null;
 	    }
 	  }
-	
+
 	  // Plus is a special case. It's a character key and shouldn't be matched
 	  // against a keycode as it is only accessible via Shift/Capslock
 	  if (key === "Plus") {
 	    key = "+";
 	  }
-	
+
 	  if (typeof key === "string" && key.length === 1) {
 	    // Match any single character
 	    shortcut.key = key.toLowerCase();
 	  } else if (key in ElectronKeysMapping) {
 	    // Maps the others manually to DOM API DOM_VK_*
 	    key = ElectronKeysMapping[key];
 	    shortcut.keyCode = window.KeyboardEvent[key];
 	    // Used only to stringify the shortcut
 	    shortcut.keyCodeString = key;
 	    shortcut.key = key;
 	  } else {
 	    console.error("Unsupported key:", key);
 	    return null;
 	  }
-	
+
 	  return shortcut;
 	};
-	
-	KeyShortcuts.stringify = function (shortcut) {
-	  var list = [];
+
+	KeyShortcuts.stringify = function(shortcut) {
+	  let list = [];
 	  if (shortcut.alt) {
 	    list.push("Alt");
 	  }
 	  if (shortcut.ctrl) {
 	    list.push("Ctrl");
 	  }
 	  if (shortcut.meta) {
 	    list.push("Cmd");
 	  }
 	  if (shortcut.shift) {
 	    list.push("Shift");
 	  }
-	  var key = void 0;
+	  let key;
 	  if (shortcut.key) {
 	    key = shortcut.key.toUpperCase();
 	  } else {
 	    key = shortcut.keyCodeString;
 	  }
 	  list.push(key);
 	  return list.join("+");
 	};
-	
+
 	KeyShortcuts.prototype = {
 	  destroy() {
 	    this.target.removeEventListener("keydown", this);
 	    this.keys.clear();
 	  },
-	
+
 	  doesEventMatchShortcut(event, shortcut) {
 	    if (shortcut.meta != event.metaKey) {
 	      return false;
 	    }
 	    if (shortcut.ctrl != event.ctrlKey) {
 	      return false;
 	    }
 	    if (shortcut.alt != event.altKey) {
 	      return false;
 	    }
 	    // Shift is a special modifier, it may implicitely be required if the
 	    // expected key is a special character accessible via shift.
-	    if (shortcut.shift != event.shiftKey && event.key && event.key.match(/[a-zA-Z]/)) {
+	    if (shortcut.shift != event.shiftKey && event.key &&
+	        event.key.match(/[a-zA-Z]/)) {
 	      return false;
 	    }
 	    if (shortcut.keyCode) {
 	      return event.keyCode == shortcut.keyCode;
 	    } else if (event.key in ElectronKeysMapping) {
 	      return ElectronKeysMapping[event.key] === shortcut.key;
 	    }
-	
+
 	    // get the key from the keyCode if key is not provided.
-	    var key = event.key || String.fromCharCode(event.keyCode);
-	
+	    let key = event.key || String.fromCharCode(event.keyCode);
+
 	    // For character keys, we match if the final character is the expected one.
 	    // But for digits we also accept indirect match to please azerty keyboard,
 	    // which requires Shift to be pressed to get digits.
-	    return key.toLowerCase() == shortcut.key || shortcut.key.match(/[0-9]/) && event.keyCode == shortcut.key.charCodeAt(0);
-	  },
-	
+	    return key.toLowerCase() == shortcut.key ||
+	      (shortcut.key.match(/^[0-9]$/) &&
+	       event.keyCode == shortcut.key.charCodeAt(0));
+	  },
+
 	  handleEvent(event) {
-	    for (var _ref2 of this.keys) {
-	      var _ref3 = _slicedToArray(_ref2, 2);
-	
-	      var key = _ref3[0];
-	      var shortcut = _ref3[1];
-	
+	    for (let [key, shortcut] of this.keys) {
 	      if (this.doesEventMatchShortcut(event, shortcut)) {
 	        this.eventEmitter.emit(key, event);
 	      }
 	    }
 	  },
-	
+
 	  on(key, listener) {
 	    if (typeof listener !== "function") {
-	      throw new Error("KeyShortcuts.on() expects a function as " + "second argument");
+	      throw new Error("KeyShortcuts.on() expects a function as " +
+	                      "second argument");
 	    }
 	    if (!this.keys.has(key)) {
-	      var shortcut = KeyShortcuts.parseElectronKey(this.window, key);
+	      let shortcut = KeyShortcuts.parseElectronKey(this.window, key);
 	      // The key string is wrong and we were unable to compute the key shortcut
 	      if (!shortcut) {
 	        return;
 	      }
 	      this.keys.set(key, shortcut);
 	    }
 	    this.eventEmitter.on(key, listener);
 	  },
-	
+
 	  off(key, listener) {
 	    this.eventEmitter.off(key, listener);
-	  }
+	  },
 	};
 	exports.KeyShortcuts = KeyShortcuts;
 
-/***/ },
-/* 30 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var Services = __webpack_require__(31);
-	var SplitBox = __webpack_require__(32);
+
+/***/ },
+/* 28 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const Services = __webpack_require__(29);
+	const SplitBox = __webpack_require__(30);
 	// const SplitBoxCSS = require("./client/shared/components/splitter/SplitBox.css")
-	var rep = __webpack_require__(34).Rep;
-	// const repCSS = require("./client/shared/components/reps/reps.css");
-	var Grip = __webpack_require__(44).Grip;
-	var sprintf = __webpack_require__(59).sprintf;
-	
+	const sprintf = __webpack_require__(33).sprintf;
+
 	module.exports = {
 	  Services,
 	  SplitBox,
 	  // SplitBoxCSS,
-	  rep,
-	  // repCSS,
-	  Grip,
 	  sprintf
 	};
 
-/***/ },
-/* 31 */
+
+/***/ },
+/* 29 */
 /***/ function(module, exports) {
 
 	module.exports = devtoolsRequire("Services");
 
 /***/ },
-/* 32 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var React = __webpack_require__(2);
-	var ReactDOM = __webpack_require__(16);
-	var Draggable = React.createFactory(__webpack_require__(33));
-	var dom = React.DOM;
-	var PropTypes = React.PropTypes;
-	
+/* 30 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(2);
+	const ReactDOM = __webpack_require__(31);
+	const Draggable = React.createFactory(__webpack_require__(32));
+	const { DOM: dom, PropTypes } = React;
+
 	/**
 	 * This component represents a Splitter. The splitter supports vertical
 	 * as well as horizontal mode.
 	 */
-	
-	var SplitBox = React.createClass({
-	
+	const SplitBox = React.createClass({
+
 	  propTypes: {
 	    // Custom class name. You can use more names separated by a space.
 	    className: PropTypes.string,
 	    // Initial size of controlled panel.
 	    initialSize: PropTypes.any,
 	    // Optional initial width of controlled panel.
 	    initialWidth: PropTypes.number,
 	    // Optional initial height of controlled panel.
 	    initialHeight: PropTypes.number,
 	    // Left/top panel
 	    startPanel: PropTypes.any,
+	    // Left/top panel collapse state.
+	    startPanelCollapsed: PropTypes.bool,
 	    // Min panel size.
 	    minSize: PropTypes.any,
 	    // Max panel size.
 	    maxSize: PropTypes.any,
 	    // Right/bottom panel
 	    endPanel: PropTypes.any,
+	    // Right/bottom panel collapse state.
+	    endPanelCollapsed: PropTypes.bool,
 	    // True if the right/bottom panel should be controlled.
 	    endPanelControl: PropTypes.bool,
 	    // Size of the splitter handle bar.
 	    splitterSize: PropTypes.number,
 	    // True if the splitter bar is vertical (default is vertical).
 	    vert: PropTypes.bool,
 	    // Optional style properties passed into the splitbox
 	    style: PropTypes.object
 	  },
-	
+
 	  displayName: "SplitBox",
-	
+
 	  getDefaultProps() {
 	    return {
 	      splitterSize: 5,
 	      vert: true,
-	      endPanelControl: false
-	    };
-	  },
-	
+	      endPanelControl: false,
+	      endPanelCollapsed: false,
+	      startPanelCollapsed: false
+	    };
+	  },
+
 	  /**
 	   * The state stores the current orientation (vertical or horizontal)
 	   * and the current size (width/height). All these values can change
 	   * during the component's life time.
 	   */
 	  getInitialState() {
 	    return {
 	      vert: this.props.vert,
 	      width: this.props.initialWidth || this.props.initialSize,
 	      height: this.props.initialHeight || this.props.initialSize
 	    };
 	  },
-	
+
+	  componentWillReceiveProps(nextProps) {
+	    if (this.props.vert !== nextProps.vert) {
+	      this.setState({ vert: nextProps.vert });
+	    }
+	  },
+
 	  // Dragging Events
-	
+
 	  /**
 	   * Set 'resizing' cursor on entire document during splitter dragging.
 	   * This avoids cursor-flickering that happens when the mouse leaves
 	   * the splitter bar area (happens frequently).
 	   */
 	  onStartMove() {
-	    var splitBox = ReactDOM.findDOMNode(this);
-	    var doc = splitBox.ownerDocument;
-	    var defaultCursor = doc.documentElement.style.cursor;
-	    doc.documentElement.style.cursor = this.state.vert ? "ew-resize" : "ns-resize";
-	
+	    const splitBox = ReactDOM.findDOMNode(this);
+	    const doc = splitBox.ownerDocument;
+	    let defaultCursor = doc.documentElement.style.cursor;
+	    doc.documentElement.style.cursor =
+	      (this.state.vert ? "ew-resize" : "ns-resize");
+
 	    splitBox.classList.add("dragging");
-	
+
 	    this.setState({
 	      defaultCursor: defaultCursor
 	    });
 	  },
-	
+
 	  onStopMove() {
-	    var splitBox = ReactDOM.findDOMNode(this);
-	    var doc = splitBox.ownerDocument;
+	    const splitBox = ReactDOM.findDOMNode(this);
+	    const doc = splitBox.ownerDocument;
 	    doc.documentElement.style.cursor = this.state.defaultCursor;
-	
+
 	    splitBox.classList.remove("dragging");
 	  },
-	
+
 	  screenX() {
-	    var borderWidth = (window.outerWidth - window.innerWidth) / 2;
-	    return window.screenX + borderWidth;
-	  },
-	
+	    // NOTE: in practice the window might have a border which calls for comparing window.outerWidth and window.innerWidth
+	    return window.screenX;
+	  },
+
 	  screenY() {
-	    var borderHeignt = window.outerHeight - window.innerHeight;
-	    return window.screenY + borderHeignt;
-	  },
-	
+	    // NOTE: in practice the window might have a border which calls for comparing window.outerHeight and window.innerHeight
+	    return window.screenY;
+	  },
+
 	  /**
 	   * Adjust size of the controlled panel. Depending on the current
 	   * orientation we either remember the width or height of
 	   * the splitter box.
 	   */
 	  onMove(x, y) {
-	    var node = ReactDOM.findDOMNode(this);
-	    var doc = node.ownerDocument;
-	    var win = doc.defaultView;
-	
-	    var size = void 0;
-	    var endPanelControl = this.props.endPanelControl;
-	
-	
+	    const node = ReactDOM.findDOMNode(this);
+	    const doc = node.ownerDocument;
+	    const win = doc.defaultView;
+
+	    let size;
+	    let { endPanelControl } = this.props;
+
 	    if (this.state.vert) {
 	      // Switch the control flag in case of RTL. Note that RTL
 	      // has impact on vertical splitter only.
-	      var dir = win.getComputedStyle(doc.documentElement).direction;
+	      let dir = win.getComputedStyle(doc.documentElement).direction;
 	      if (dir == "rtl") {
 	        endPanelControl = !endPanelControl;
 	      }
-	
-	      var innerOffset = x - this.screenX();
-	      size = endPanelControl ? node.offsetLeft + node.offsetWidth - innerOffset : innerOffset - node.offsetLeft;
-	
+
+	      let innerOffset = x - this.screenX();
+	      size = endPanelControl ?
+	        (node.offsetLeft + node.offsetWidth) - innerOffset :
+	        innerOffset - node.offsetLeft;
+
 	      this.setState({
 	        width: size
 	      });
 	    } else {
-	      var _innerOffset = y - this.screenY();
-	      size = endPanelControl ? node.offsetTop + node.offsetHeight - _innerOffset : _innerOffset - node.offsetTop;
-	
+	      let innerOffset = y - this.screenY();
+	      size = endPanelControl ?
+	        (node.offsetTop + node.offsetHeight) - innerOffset :
+	        innerOffset - node.offsetTop;
+
 	      this.setState({
 	        height: size
 	      });
 	    }
 	  },
-	
+
 	  // Rendering
-	
-	  render() {
-	    var vert = this.state.vert;
-	    var _props = this.props;
-	    var startPanel = _props.startPanel;
-	    var endPanel = _props.endPanel;
-	    var endPanelControl = _props.endPanelControl;
-	    var minSize = _props.minSize;
-	    var maxSize = _props.maxSize;
-	    var splitterSize = _props.splitterSize;
-	
-	
-	    var style = Object.assign({}, this.props.style);
-	
-	    // Calculate class names list.
-	    var classNames = ["split-box"];
-	    classNames.push(vert ? "vert" : "horz");
-	    if (this.props.className) {
-	      classNames = classNames.concat(this.props.className.split(" "));
-	    }
-	
-	    var leftPanelStyle = void 0;
-	    var rightPanelStyle = void 0;
-	
+	  preparePanelStyles() {
+	    const vert = this.state.vert;
+	    const {
+	      minSize, maxSize, startPanelCollapsed, endPanelControl,
+	      endPanelCollapsed } = this.props;
+	    let leftPanelStyle, rightPanelStyle;
+
 	    // Set proper size for panels depending on the current state.
 	    if (vert) {
+	      let startWidth = endPanelControl ? null : this.state.width,
+	        endWidth = endPanelControl ? this.state.width : null;
+
 	      leftPanelStyle = {
 	        maxWidth: endPanelControl ? null : maxSize,
 	        minWidth: endPanelControl ? null : minSize,
-	        width: endPanelControl ? null : this.state.width
+	        width: startPanelCollapsed ? 0 : startWidth
 	      };
 	      rightPanelStyle = {
 	        maxWidth: endPanelControl ? maxSize : null,
 	        minWidth: endPanelControl ? minSize : null,
-	        width: endPanelControl ? this.state.width : null
-	      };
-	    } else {
+	        width: endPanelCollapsed ? 0 : endWidth
+	      };
+	    } else {
+	      let startHeight = endPanelControl ? null : this.state.height,
+	        endHeight = endPanelControl ? this.state.height : null;
+
 	      leftPanelStyle = {
 	        maxHeight: endPanelControl ? null : maxSize,
 	        minHeight: endPanelControl ? null : minSize,
-	        height: endPanelControl ? null : this.state.height
+	        height: endPanelCollapsed ? maxSize : startHeight
 	      };
 	      rightPanelStyle = {
 	        maxHeight: endPanelControl ? maxSize : null,
 	        minHeight: endPanelControl ? minSize : null,
-	        height: endPanelControl ? this.state.height : null
-	      };
-	    }
-	
+	        height: startPanelCollapsed ? maxSize : endHeight
+	      };
+	    }
+
+	    return { leftPanelStyle, rightPanelStyle };
+	  },
+
+	  render() {
+	    const vert = this.state.vert;
+	    const {
+	      startPanelCollapsed,
+	      startPanel,
+	      endPanel,
+	      endPanelControl,
+	      splitterSize,
+	      endPanelCollapsed
+	    } = this.props;
+
+	    let style = Object.assign({}, this.props.style);
+
+	    // Calculate class names list.
+	    let classNames = ["split-box"];
+	    classNames.push(vert ? "vert" : "horz");
+	    if (this.props.className) {
+	      classNames = classNames.concat(this.props.className.split(" "));
+	    }
+
+	    const { leftPanelStyle, rightPanelStyle } = this.preparePanelStyles();
+
 	    // Calculate splitter size
-	    var splitterStyle = {
-	      flex: "0 0 " + splitterSize + "px"
-	    };
-	
-	    return dom.div({
-	      className: classNames.join(" "),
-	      style: style }, startPanel ? dom.div({
-	      className: endPanelControl ? "uncontrolled" : "controlled",
-	      style: leftPanelStyle }, startPanel) : null, Draggable({
-	      className: "splitter",
-	      style: splitterStyle,
-	      onStart: this.onStartMove,
-	      onStop: this.onStopMove,
-	      onMove: this.onMove
-	    }), endPanel ? dom.div({
-	      className: endPanelControl ? "controlled" : "uncontrolled",
-	      style: rightPanelStyle }, endPanel) : null);
-	  }
-	});
-	
+	    let splitterStyle = {
+	      flex: `0 0 ${splitterSize}px`
+	    };
+
+	    return (
+	      dom.div({
+	        className: classNames.join(" "),
+	        style: style },
+	        !startPanelCollapsed ?
+	          dom.div({
+	            className: endPanelControl ? "uncontrolled" : "controlled",
+	            style: leftPanelStyle },
+	            startPanel
+	          ) : null,
+	        Draggable({
+	          className: "splitter",
+	          style: splitterStyle,
+	          onStart: this.onStartMove,
+	          onStop: this.onStopMove,
+	          onMove: this.onMove
+	        }),
+	        !endPanelCollapsed ?
+	          dom.div({
+	            className: endPanelControl ? "controlled" : "uncontrolled",
+	            style: rightPanelStyle },
+	            endPanel
+	          ) : null
+	      )
+	    );
+	  }
+	});
+
 	module.exports = SplitBox;
 
-/***/ },
-/* 33 */
+
+/***/ },
+/* 31 */
+/***/ function(module, exports, __webpack_require__) {
+
+	/**
+	 * ReactDOM v0.14.7
+	 *
+	 * Copyright 2013-2015, Facebook, Inc.
+	 * All rights reserved.
+	 *
+	 * This source code is licensed under the BSD-style license found in the
+	 * LICENSE file in the root directory of this source tree. An additional grant
+	 * of patent rights can be found in the PATENTS file in the same directory.
+	 *
+	 */
+	// Based off https://github.com/ForbesLindesay/umd/blob/master/template.js
+	;(function(f) {
+	  // CommonJS
+	  if (true) {
+	    module.exports = f(__webpack_require__(2));
+
+	  // RequireJS
+	  } else if (typeof define === "function" && define.amd) {
+	    define(['react'], f);
+
+	  // <script>
+	  } else {
+	    var g;
+	    if (typeof window !== "undefined") {
+	      g = window;
+	    } else if (typeof global !== "undefined") {
+	      g = global;
+	    } else if (typeof self !== "undefined") {
+	      g = self;
+	    } else {
+	      // works providing we're not in "use strict";
+	      // needed for Java 8 Nashorn
+	      // see https://github.com/facebook/react/issues/3037
+	      g = this;
+	    }
+	    g.ReactDOM = f(g.React);
+	  }
+
+	})(function(React) {
+	  return React.__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
+	});
+
+
+/***/ },
+/* 32 */
 /***/ function(module, exports, __webpack_require__) {
 
 	/* 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,
+	 * 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/. */
-	
-	var React = __webpack_require__(2);
-	var ReactDOM = __webpack_require__(16);
-	var dom = React.DOM;
-	var PropTypes = React.PropTypes;
-	
-	
-	var Draggable = React.createClass({
+
+	const React = __webpack_require__(2);
+	const ReactDOM = __webpack_require__(31);
+	const { DOM: dom, PropTypes } = React;
+
+	const Draggable = React.createClass({
 	  displayName: "Draggable",
-	
+
 	  propTypes: {
 	    onMove: PropTypes.func.isRequired,
 	    onStart: PropTypes.func,
 	    onStop: PropTypes.func,
 	    style: PropTypes.object,
 	    className: PropTypes.string
 	  },
-	
+
 	  startDragging(ev) {
 	    ev.preventDefault();
-	    var doc = ReactDOM.findDOMNode(this).ownerDocument;
+	    const doc = ReactDOM.findDOMNode(this).ownerDocument;
 	    doc.addEventListener("mousemove", this.onMove);
 	    doc.addEventListener("mouseup", this.onUp);
 	    this.props.onStart && this.props.onStart();
 	  },
-	
+
 	  onMove(ev) {
 	    ev.preventDefault();
 	    // Use screen coordinates so, moving mouse over iframes
 	    // doesn't mangle (relative) coordinates.
 	    this.props.onMove(ev.screenX, ev.screenY);
 	  },
-	
+
 	  onUp(ev) {
 	    ev.preventDefault();
-	    var doc = ReactDOM.findDOMNode(this).ownerDocument;
+	    const doc = ReactDOM.findDOMNode(this).ownerDocument;
 	    doc.removeEventListener("mousemove", this.onMove);
 	    doc.removeEventListener("mouseup", this.onUp);
 	    this.props.onStop && this.props.onStop();
 	  },
-	
+
 	  render() {
 	    return dom.div({
 	      style: this.props.style,
 	      className: this.props.className,
 	      onMouseDown: this.startDragging
 	    });
 	  }
 	});
-	
+
 	module.exports = Draggable;
 
-/***/ },
-/* 34 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-	/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-	/* 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/. */
-	
-	"use strict";
-	
-	// Make this available to both AMD and CJS environments
-	
-	!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
-	  // Dependencies
-	  var React = __webpack_require__(2);
-	
-	  var _require = __webpack_require__(35);
-	
-	  var isGrip = _require.isGrip;
-	
-	  // Load all existing rep templates
-	
-	  var _require2 = __webpack_require__(36);
-	
-	  var Undefined = _require2.Undefined;
-	
-	  var _require3 = __webpack_require__(37);
-	
-	  var Null = _require3.Null;
-	
-	  var _require4 = __webpack_require__(38);
-	
-	  var StringRep = _require4.StringRep;
-	
-	  var _require5 = __webpack_require__(39);
-	
-	  var Number = _require5.Number;
-	
-	  var _require6 = __webpack_require__(40);
-	
-	  var ArrayRep = _require6.ArrayRep;
-	
-	  var _require7 = __webpack_require__(42);
-	
-	  var Obj = _require7.Obj;
-	
-	  var _require8 = __webpack_require__(45);
-	
-	  var SymbolRep = _require8.SymbolRep;
-	
-	  // DOM types (grips)
-	
-	  var _require9 = __webpack_require__(46);
-	
-	  var Attribute = _require9.Attribute;
-	
-	  var _require10 = __webpack_require__(47);
-	
-	  var DateTime = _require10.DateTime;
-	
-	  var _require11 = __webpack_require__(48);
-	
-	  var Document = _require11.Document;
-	
-	  var _require12 = __webpack_require__(49);
-	
-	  var Event = _require12.Event;
-	
-	  var _require13 = __webpack_require__(50);
-	
-	  var Func = _require13.Func;
-	
-	  var _require14 = __webpack_require__(51);
-	
-	  var RegExp = _require14.RegExp;
-	
-	  var _require15 = __webpack_require__(52);
-	
-	  var StyleSheet = _require15.StyleSheet;
-	
-	  var _require16 = __webpack_require__(53);
-	
-	  var TextNode = _require16.TextNode;
-	
-	  var _require17 = __webpack_require__(54);
-	
-	  var Window = _require17.Window;
-	
-	  var _require18 = __webpack_require__(55);
-	
-	  var ObjectWithText = _require18.ObjectWithText;
-	
-	  var _require19 = __webpack_require__(56);
-	
-	  var ObjectWithURL = _require19.ObjectWithURL;
-	
-	  var _require20 = __webpack_require__(57);
-	
-	  var GripArray = _require20.GripArray;
-	
-	  var _require21 = __webpack_require__(58);
-	
-	  var GripMap = _require21.GripMap;
-	
-	  var _require22 = __webpack_require__(44);
-	
-	  var Grip = _require22.Grip;
-	
-	  // List of all registered template.
-	  // XXX there should be a way for extensions to register a new
-	  // or modify an existing rep.
-	
-	  var reps = [RegExp, StyleSheet, Event, DateTime, TextNode, Attribute, Func, ArrayRep, Document, Window, ObjectWithText, ObjectWithURL, GripArray, GripMap, Grip, Undefined, Null, StringRep, Number, SymbolRep];
-	
-	  /**
-	   * 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.
-	   */
-	  var Rep = React.createClass({
-	    displayName: "Rep",
-	
-	    propTypes: {
-	      object: React.PropTypes.any,
-	      defaultRep: React.PropTypes.object,
-	      mode: React.PropTypes.string
-	    },
-	
-	    render: function () {
-	      var rep = getRep(this.props.object, this.props.defaultRep);
-	      return rep(this.props);
-	    }
-	  });
-	
-	  // Helpers
-	
-	  /**
-	   * Return a rep object that is responsible for rendering given
-	   * object.
-	   *
-	   * @param object {Object} Object to be rendered in the UI. This
-	   * can be generic JS object as well as a grip (handle to a remote
-	   * debuggee object).
-	   *
-	   * @param defaultObject {React.Component} The default template
-	   * that should be used to render given object if none is found.
-	   */
-	  function getRep(object) {
-	    var defaultRep = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Obj;
-	
-	    var type = typeof object;
-	    if (type == "object" && object instanceof String) {
-	      type = "string";
-	    } else if (type == "object" && object.type === "symbol") {
-	      type = "symbol";
-	    }
-	
-	    if (isGrip(object)) {
-	      type = object.class;
-	    }
-	
-	    for (var i = 0; i < reps.length; i++) {
-	      var rep = reps[i];
-	      try {
-	        // supportsObject could return weight (not only true/false
-	        // but a number), which would allow to priorities templates and
-	        // support better extensibility.
-	        if (rep.supportsObject(object, type)) {
-	          return React.createFactory(rep.rep);
-	        }
-	      } catch (err) {
-	        console.error(err);
-	      }
-	    }
-	
-	    return React.createFactory(defaultRep.rep);
-	  }
-	
-	  // Exports from this module
-	  exports.Rep = Rep;
-	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-
-/***/ },
-/* 35 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var __WEBPACK_AMD_DEFINE_RESULT__;/* globals URLSearchParams */
-	/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-	/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-	/* 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/. */
-	
-	"use strict";
-	
-	// Make this available to both AMD and CJS environments
-	
-	function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
-	
-	!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
-	  // Dependencies
-	  var React = __webpack_require__(2);
-	
-	  /**
-	   * Create React factories for given arguments.
-	   * Example:
-	   *   const { Rep } = createFactories(require("./rep"));
-	   */
-	  function createFactories(args) {
-	    var result = {};
-	    for (var p in args) {
-	      result[p] = React.createFactory(args[p]);
-	    }
-	    return result;
-	  }
-	
-	  /**
-	   * Returns true if the given object is a grip (see RDP protocol)
-	   */
-	  function isGrip(object) {
-	    return object && object.actor;
-	  }
-	
-	  function escapeNewLines(value) {
-	    return value.replace(/\r/gm, "\\r").replace(/\n/gm, "\\n");
-	  }
-	
-	  function cropMultipleLines(text, limit) {
-	    return escapeNewLines(cropString(text, limit));
-	  }
-	
-	  function cropString(text, limit, alternativeText) {
-	    if (!alternativeText) {
-	      alternativeText = "\u2026";
-	    }
-	
-	    // Make sure it's a string.
-	    text = text + "";
-	
-	    // Crop the string only if a limit is actually specified.
-	    if (!limit || limit <= 0) {
-	      return text;
-	    }
-	
-	    // Set the limit at least to the length of the alternative text
-	    // plus one character of the original text.
-	    if (limit <= alternativeText.length) {
-	      limit = alternativeText.length + 1;
-	    }
-	
-	    var halfLimit = (limit - alternativeText.length) / 2;
-	
-	    if (text.length > limit) {
-	      return text.substr(0, Math.ceil(halfLimit)) + alternativeText + text.substr(text.length - Math.floor(halfLimit));
-	    }
-	
-	    return text;
-	  }
-	
-	  function parseURLParams(url) {
-	    url = new URL(url);
-	    return parseURLEncodedText(url.searchParams);
-	  }
-	
-	  function parseURLEncodedText(text) {
-	    var params = [];
-	
-	    // In case the text is empty just return the empty parameters
-	    if (text == "") {
-	      return params;
-	    }
-	
-	    var searchParams = new URLSearchParams(text);
-	    var entries = [].concat(_toConsumableArray(searchParams.entries()));
-	    return entries.map(entry => {
-	      return {
-	        name: entry[0],
-	        value: entry[1]
-	      };
-	    });
-	  }
-	
-	  function getFileName(url) {
-	    var split = splitURLBase(url);
-	    return split.name;
-	  }
-	
-	  function splitURLBase(url) {
-	    if (!isDataURL(url)) {
-	      return splitURLTrue(url);
-	    }
-	    return {};
-	  }
-	
-	  function getURLDisplayString(url) {
-	    return cropString(url);
-	  }
-	
-	  function isDataURL(url) {
-	    return url && url.substr(0, 5) == "data:";
-	  }
-	
-	  function splitURLTrue(url) {
-	    var reSplitFile = /(.*?):\/{2,3}([^\/]*)(.*?)([^\/]*?)($|\?.*)/;
-	    var m = reSplitFile.exec(url);
-	
-	    if (!m) {
-	      return {
-	        name: url,
-	        path: url
-	      };
-	    } else if (m[4] == "" && m[5] == "") {
-	      return {
-	        protocol: m[1],
-	        domain: m[2],
-	        path: m[3],
-	        name: m[3] != "/" ? m[3] : m[2]
-	      };
-	    }
-	
-	    return {
-	      protocol: m[1],
-	      domain: m[2],
-	      path: m[2] + m[3],
-	      name: m[4] + m[5]
-	    };
-	  }
-	
-	  // Exports from this module
-	  exports.createFactories = createFactories;
-	  exports.isGrip = isGrip;
-	  exports.cropString = cropString;
-	  exports.cropMultipleLines = cropMultipleLines;
-	  exports.parseURLParams = parseURLParams;
-	  exports.parseURLEncodedText = parseURLEncodedText;
-	  exports.getFileName = getFileName;
-	  exports.getURLDisplayString = getURLDisplayString;
-	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-
-/***/ },
-/* 36 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-	/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-	/* 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/. */
-	
-	"use strict";
-	
-	// Make this available to both AMD and CJS environments
-	
-	!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
-	  // Dependencies
-	  var React = __webpack_require__(2);
-	
-	  // Shortcuts
-	  var span = React.DOM.span;
-	
-	  /**
-	   * Renders undefined value
-	   */
-	
-	  var Undefined = React.createClass({
-	    displayName: "UndefinedRep",
-	
-	    render: function () {
-	      return span({ className: "objectBox objectBox-undefined" }, "undefined");
-	    }
-	  });
-	
-	  function supportsObject(object, type) {
-	    if (object && object.type && object.type == "undefined") {
-	      return true;
-	    }
-	
-	    return type == "undefined";
-	  }
-	
-	  // Exports from this module
-	
-	  exports.Undefined = {
-	    rep: Undefined,
-	    supportsObject: supportsObject
-	  };
-	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-
-/***/ },
-/* 37 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-	/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-	/* 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/. */
-	
-	"use strict";
-	
-	// Make this available to both AMD and CJS environments
-	
-	!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
-	  // Dependencies
-	  var React = __webpack_require__(2);
-	
-	  // Shortcuts
-	  var span = React.DOM.span;
-	
-	  /**
-	   * Renders null value
-	   */
-	
-	  var Null = React.createClass({
-	    displayName: "NullRep",
-	
-	    render: function () {
-	      return span({ className: "objectBox objectBox-null" }, "null");
-	    }
-	  });
-	
-	  function supportsObject(object, type) {
-	    if (object && object.type && object.type == "null") {
-	      return true;
-	    }
-	
-	    return object == null;
-	  }
-	
-	  // Exports from this module
-	
-	  exports.Null = {
-	    rep: Null,
-	    supportsObject: supportsObject
-	  };
-	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-
-/***/ },
-/* 38 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-	/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-	/* 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/. */
-	
-	"use strict";
-	
-	// Make this available to both AMD and CJS environments
-	
-	!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
-	  // Dependencies
-	  var React = __webpack_require__(2);
-	
-	  var _require = __webpack_require__(35);
-	
-	  var cropMultipleLines = _require.cropMultipleLines;
-	
-	  // Shortcuts
-	
-	  var span = React.DOM.span;
-	
-	  /**
-	   * Renders a string. String value is enclosed within quotes.
-	   */
-	
-	  var StringRep = React.createClass({
-	    displayName: "StringRep",
-	
-	    propTypes: {
-	      useQuotes: React.PropTypes.bool
-	    },
-	
-	    getDefaultProps: function () {
-	      return {
-	        useQuotes: true
-	      };
-	    },
-	
-	    render: function () {
-	      var text = this.props.object;
-	      var member = this.props.member;
-	      if (member && member.open) {
-	        return span({ className: "objectBox objectBox-string" }, "\"" + text + "\"");
-	      }
-	
-	      var croppedString = this.props.cropLimit ? cropMultipleLines(text, this.props.cropLimit) : cropMultipleLines(text);
-	
-	      var formattedString = this.props.useQuotes ? "\"" + croppedString + "\"" : croppedString;
-	
-	      return span({ className: "objectBox objectBox-string" }, formattedString);
-	    }
-	  });
-	
-	  function supportsObject(object, type) {
-	    return type == "string";
-	  }
-	
-	  // Exports from this module
-	
-	  exports.StringRep = {
-	    rep: StringRep,
-	    supportsObject: supportsObject
-	  };
-	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-
-/***/ },
-/* 39 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-	/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-	/* 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/. */
-	
-	"use strict";
-	
-	// Make this available to both AMD and CJS environments
-	
-	!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
-	  // Dependencies
-	  var React = __webpack_require__(2);
-	
-	  // Shortcuts
-	  var span = React.DOM.span;
-	
-	  /**
-	   * Renders a number
-	   */
-	
-	  var Number = React.createClass({
-	    displayName: "Number",
-	
-	    stringify: function (object) {
-	      var isNegativeZero = Object.is(object, -0) || object.type && object.type == "-0";
-	
-	      return isNegativeZero ? "-0" : String(object);
-	    },
-	
-	    render: function () {
-	      var value = this.props.object;
-	
-	      return span({ className: "objectBox objectBox-number" }, this.stringify(value));
-	    }
-	  });
-	
-	  function supportsObject(object, type) {
-	    return type == "boolean" || type == "number" || type == "object" && object.type == "-0";
-	  }
-	
-	  // Exports from this module
-	
-	  exports.Number = {
-	    rep: Number,
-	    supportsObject: supportsObject
-	  };
-	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-
-/***/ },
-/* 40 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-	/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-	/* 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/. */
-	
-	"use strict";
-	
-	// Make this available to both AMD and CJS environments
-	
-	!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
-	  // Dependencies
-	  var React = __webpack_require__(2);
-	
-	  var _require = __webpack_require__(35);
-	
-	  var createFactories = _require.createFactories;
-	
-	  var _createFactories = createFactories(__webpack_require__(41));
-	
-	  var Caption = _createFactories.Caption;
-	
-	  // Shortcuts
-	
-	  var DOM = React.DOM;
-	
-	  /**
-	   * Renders an array. The array is enclosed by left and right bracket
-	   * and the max number of rendered items depends on the current mode.
-	   */
-	  var ArrayRep = React.createClass({
-	    displayName: "ArrayRep",
-	
-	    getTitle: function (object, context) {
-	      return "[" + object.length + "]";
-	    },
-	
-	    arrayIterator: function (array, max) {
-	      var items = [];
-	      var delim = void 0;
-	
-	      for (var i = 0; i < array.length && i < max; i++) {
-	        try {
-	          var value = array[i];
-	
-	          delim = i == array.length - 1 ? "" : ", ";
-	
-	          items.push(ItemRep({
-	            key: i,
-	            object: value,
-	            // Hardcode tiny mode to avoid recursive handling.
-	            mode: "tiny",
-	            delim: delim
-	          }));
-	        } catch (exc) {
-	          items.push(ItemRep({
-	            key: i,
-	            object: exc,
-	            mode: "tiny",
-	            delim: delim
-	          }));
-	        }
-	      }
-	
-	      if (array.length > max) {
-	        var objectLink = this.props.objectLink || DOM.span;
-	        items.push(Caption({
-	          key: "more",
-	          object: objectLink({
-	            object: this.props.object
-	          }, array.length - max + " more…")
-	        }));
-	      }
-	
-	      return items;
-	    },
-	
-	    /**
-	     * Returns true if the passed object is an array with additional (custom)
-	     * properties, otherwise returns false. Custom properties should be
-	     * displayed in extra expandable section.
-	     *
-	     * Example array with a custom property.
-	     * let arr = [0, 1];
-	     * arr.myProp = "Hello";
-	     *
-	     * @param {Array} array The array object.
-	     */
-	    hasSpecialProperties: function (array) {
-	      function isInteger(x) {
-	        var y = parseInt(x, 10);
-	        if (isNaN(y)) {
-	          return false;
-	        }
-	        return x === y.toString();
-	      }
-	
-	      var props = Object.getOwnPropertyNames(array);
-	      for (var i = 0; i < props.length; i++) {
-	        var p = props[i];
-	
-	        // Valid indexes are skipped
-	        if (isInteger(p)) {
-	          continue;
-	        }
-	
-	        // Ignore standard 'length' property, anything else is custom.
-	        if (p != "length") {
-	          return true;
-	        }
-	      }
-	
-	      return false;
-	    },
-	
-	    // Event Handlers
-	
-	    onToggleProperties: function (event) {},
-	
-	    onClickBracket: function (event) {},
-	
-	    render: function () {
-	      var mode = this.props.mode || "short";
-	      var object = this.props.object;
-	      var items = void 0;
-	      var brackets = void 0;
-	      var needSpace = function (space) {
-	        return space ? { left: "[ ", right: " ]" } : { left: "[", right: "]" };
-	      };
-	
-	      if (mode == "tiny") {
-	        var isEmpty = object.length === 0;
-	        items = DOM.span({ className: "length" }, isEmpty ? "" : object.length);
-	        brackets = needSpace(false);
-	      } else {
-	        var max = mode == "short" ? 3 : 300;
-	        items = this.arrayIterator(object, max);
-	        brackets = needSpace(items.length > 0);
-	      }
-	
-	      var objectLink = this.props.objectLink || DOM.span;
-	
-	      return DOM.span({
-	        className: "objectBox objectBox-array" }, objectLink({
-	        className: "arrayLeftBracket",
-	        object: object
-	      }, brackets.left), items, objectLink({
-	        className: "arrayRightBracket",
-	        object: object
-	      }, brackets.right), DOM.span({
-	        className: "arrayProperties",
-	        role: "group" }));
-	    }
-	  });
-	
-	  /**
-	   * Renders array item. Individual values are separated by a comma.
-	   */
-	  var ItemRep = React.createFactory(React.createClass({
-	    displayName: "ItemRep",
-	
-	    render: function () {
-	      var _createFactories2 = createFactories(__webpack_require__(34));
-	
-	      var Rep = _createFactories2.Rep;
-	
-	
-	      var object = this.props.object;
-	      var delim = this.props.delim;
-	      var mode = this.props.mode;
-	      return DOM.span({}, Rep({ object: object, mode: mode }), delim);
-	    }
-	  }));
-	
-	  function supportsObject(object, type) {
-	    return Array.isArray(object) || Object.prototype.toString.call(object) === "[object Arguments]";
-	  }
-	
-	  // Exports from this module
-	  exports.ArrayRep = {
-	    rep: ArrayRep,
-	    supportsObject: supportsObject
-	  };
-	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-
-/***/ },
-/* 41 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-	/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-	/* 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/. */
-	
-	"use strict";
-	
-	// Make this available to both AMD and CJS environments
-	
-	!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
-	  // Dependencies
-	  var React = __webpack_require__(2);
-	  var DOM = React.DOM;
-	
-	  /**
-	   * Renders a caption. This template is used by other components
-	   * that needs to distinguish between a simple text/value and a label.
-	   */
-	  var Caption = React.createClass({
-	    displayName: "Caption",
-	
-	    render: function () {
-	      return DOM.span({ "className": "caption" }, this.props.object);
-	    }
-	  });
-	
-	  // Exports from this module
-	  exports.Caption = Caption;
-	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-
-/***/ },
-/* 42 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-	/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-	/* 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/. */
-	
-	"use strict";
-	// Make this available to both AMD and CJS environments
-	
-	!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
-	  // Dependencies
-	  var React = __webpack_require__(2);
-	
-	  var _require = __webpack_require__(35);
-	
-	  var createFactories = _require.createFactories;
-	
-	  var _createFactories = createFactories(__webpack_require__(41));
-	
-	  var Caption = _createFactories.Caption;
-	
-	  var _createFactories2 = createFactories(__webpack_require__(43));
-	
-	  var PropRep = _createFactories2.PropRep;
-	  // Shortcuts
-	
-	  var span = React.DOM.span;
-	  /**
-	   * Renders an object. An object is represented by a list of its
-	   * properties enclosed in curly brackets.
-	   */
-	
-	  var Obj = React.createClass({
-	    displayName: "Obj",
-	
-	    propTypes: {
-	      object: React.PropTypes.object,
-	      mode: React.PropTypes.string
-	    },
-	
-	    getTitle: function (object) {
-	      var className = object && object.class ? object.class : "Object";
-	      if (this.props.objectLink) {
-	        return this.props.objectLink({
-	          object: object
-	        }, className);
-	      }
-	      return className;
-	    },
-	
-	    safePropIterator: function (object, max) {
-	      max = typeof max === "undefined" ? 3 : max;
-	      try {
-	        return this.propIterator(object, max);
-	      } catch (err) {
-	        console.error(err);
-	      }
-	      return [];
-	    },
-	
-	    propIterator: function (object, max) {
-	      var isInterestingProp = (t, value) => {
-	        // Do not pick objects, it could cause recursion.
-	        return t == "boolean" || t == "number" || t == "string" && value;
-	      };
-	
-	      // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=945377
-	      if (Object.prototype.toString.call(object) === "[object Generator]") {
-	        object = Object.getPrototypeOf(object);
-	      }
-	
-	      // Object members with non-empty values are preferred since it gives the
-	      // user a better overview of the object.
-	      var props = this.getProps(object, max, isInterestingProp);
-	
-	      if (props.length <= max) {
-	        // There are not enough props yet (or at least, not enough props to
-	        // be able to know whether we should print "more…" or not).
-	        // Let's display also empty members and functions.
-	        props = props.concat(this.getProps(object, max, (t, value) => {
-	          return !isInterestingProp(t, value);
-	        }));
-	      }
-	
-	      if (props.length > max) {
-	        props.pop();
-	        var objectLink = this.props.objectLink || span;
-	
-	        props.push(Caption({
-	          key: "more",
-	          object: objectLink({
-	            object: object
-	          }, Object.keys(object).length - max + " more…")
-	        }));
-	      } else if (props.length > 0) {
-	        // Remove the last comma.
-	        props[props.length - 1] = React.cloneElement(props[props.length - 1], { delim: "" });
-	      }
-	
-	      return props;
-	    },
-	
-	    getProps: function (object, max, filter) {
-	      var props = [];
-	
-	      max = max || 3;
-	      if (!object) {
-	        return props;
-	      }
-	
-	      // Hardcode tiny mode to avoid recursive handling.
-	      var mode = "tiny";
-	
-	      try {
-	        for (var name in object) {
-	          if (props.length > max) {
-	            return props;
-	          }
-	
-	          var value = void 0;
-	          try {
-	            value = object[name];
-	          } catch (exc) {
-	            continue;
-	          }
-	
-	          var t = typeof value;
-	          if (filter(t, value)) {
-	            props.push(PropRep({
-	              key: name,
-	              mode: mode,
-	              name: name,
-	              object: value,
-	              equal: ": ",
-	              delim: ", "
-	            }));
-	          }
-	        }
-	      } catch (err) {
-	        console.error(err);
-	      }
-	
-	      return props;
-	    },
-	
-	    render: function () {
-	      var object = this.props.object;
-	      var props = this.safePropIterator(object);
-	      var objectLink = this.props.objectLink || span;
-	
-	      if (this.props.mode == "tiny" || !props.length) {
-	        return span({ className: "objectBox objectBox-object" }, objectLink({ className: "objectTitle" }, this.getTitle(object)));
-	      }
-	
-	      return span({ className: "objectBox objectBox-object" }, this.getTitle(object), objectLink({
-	        className: "objectLeftBrace",
-	        object: object
-	      }, " { "), props, objectLink({
-	        className: "objectRightBrace",
-	        object: object
-	      }, " }"));
-	    }
-	  });
-	  function supportsObject(object, type) {
-	    return true;
-	  }
-	
-	  // Exports from this module
-	  exports.Obj = {
-	    rep: Obj,
-	    supportsObject: supportsObject
-	  };
-	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-
-/***/ },
-/* 43 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-	/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-	/* 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/. */
-	"use strict";
-	
-	// Make this available to both AMD and CJS environments
-	
-	!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
-	  var React = __webpack_require__(2);
-	
-	  var _require = __webpack_require__(35);
-	
-	  var createFactories = _require.createFactories;
-	  var span = React.DOM.span;
-	
-	  /**
-	   * 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.
-	   */
-	
-	  var PropRep = React.createFactory(React.createClass({
-	    displayName: "PropRep",
-	
-	    propTypes: {
-	      // Property name.
-	      name: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.object]).isRequired,
-	      // Equal character rendered between property name and value.
-	      equal: React.PropTypes.string,
-	      // Delimiter character used to separate individual properties.
-	      delim: React.PropTypes.string,
-	      mode: React.PropTypes.string
-	    },
-	
-	    render: function () {
-	      var _require2 = __webpack_require__(44);
-	
-	      var Grip = _require2.Grip;
-	
-	      var _createFactories = createFactories(__webpack_require__(34));
-	
-	      var Rep = _createFactories.Rep;
-	
-	
-	      var key = void 0;
-	      // The key can be a simple string, for plain objects,
-	      // or another object for maps and weakmaps.
-	      if (typeof this.props.name === "string") {
-	        key = span({ "className": "nodeName" }, this.props.name);
-	      } else {
-	        key = Rep({
-	          object: this.props.name,
-	          mode: this.props.mode || "tiny",
-	          defaultRep: Grip,
-	          objectLink: this.props.objectLink
-	        });
-	      }
-	
-	      return span({}, key, span({
-	        "className": "objectEqual"
-	      }, this.props.equal), Rep(this.props), span({
-	        "className": "objectComma"
-	      }, this.props.delim));
-	    }
-	  }));
-	
-	  // Exports from this module
-	  exports.PropRep = PropRep;
-	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-
-/***/ },
-/* 44 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-	/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-	/* 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/. */
-	"use strict";
-	
-	// Make this available to both AMD and CJS environments
-	
-	!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
-	  // ReactJS
-	  var React = __webpack_require__(2);
-	  // Dependencies
-	
-	  var _require = __webpack_require__(35);
-	
-	  var createFactories = _require.createFactories;
-	  var isGrip = _require.isGrip;
-	
-	  var _createFactories = createFactories(__webpack_require__(41));
-	
-	  var Caption = _createFactories.Caption;
-	
-	  var _createFactories2 = createFactories(__webpack_require__(43));
-	
-	  var PropRep = _createFactories2.PropRep;
-	  // Shortcuts
-	
-	  var span = React.DOM.span;
-	
-	  /**
-	   * Renders generic grip. Grip is client representation
-	   * of remote JS object and is used as an input object
-	   * for this rep component.
-	   */
-	
-	  var GripRep = React.createClass({
-	    displayName: "Grip",
-	
-	    propTypes: {
-	      object: React.PropTypes.object.isRequired,
-	      mode: React.PropTypes.string,
-	      isInterestingProp: React.PropTypes.func
-	    },
-	
-	    getTitle: function (object) {
-	      if (this.props.objectLink) {
-	        return this.props.objectLink({
-	          object: object
-	        }, object.class);
-	      }
-	      return object.class || "Object";
-	    },
-	
-	    safePropIterator: function (object, max) {
-	      max = typeof max === "undefined" ? 3 : max;
-	      try {
-	        return this.propIterator(object, max);
-	      } catch (err) {
-	        console.error(err);
-	      }
-	      return [];
-	    },
-	
-	    propIterator: function (object, max) {
-	      // Property filter. Show only interesting properties to the user.
-	      var isInterestingProp = this.props.isInterestingProp || ((type, value) => {
-	        return type == "boolean" || type == "number" || type == "string" && value.length != 0;
-	      });
-	
-	      var ownProperties = object.preview ? object.preview.ownProperties : [];
-	      var indexes = this.getPropIndexes(ownProperties, max, isInterestingProp);
-	      if (indexes.length < max && indexes.length < object.ownPropertyLength) {
-	        // There are not enough props yet. Then add uninteresting props to display them.
-	        indexes = indexes.concat(this.getPropIndexes(ownProperties, max - indexes.length, (t, value, name) => {
-	          return !isInterestingProp(t, value, name);
-	        }));
-	      }
-	
-	      var props = this.getProps(ownProperties, indexes);
-	      if (props.length < object.ownPropertyLength) {
-	        // There are some undisplayed props. Then display "more...".
-	        var objectLink = this.props.objectLink || span;
-	
-	        props.push(Caption({
-	          key: "more",
-	          object: objectLink({
-	            object: object
-	          }, (object ? object.ownPropertyLength : 0) - max + " more…")
-	        }));
-	      } else if (props.length > 0) {
-	        // Remove the last comma.
-	        // NOTE: do not change comp._store.props directly to update a property,
-	        // it should be re-rendered or cloned with changed props
-	        var last = props.length - 1;
-	        props[last] = React.cloneElement(props[last], {
-	          delim: ""
-	        });
-	      }
-	
-	      return props;
-	    },
-	
-	    /**
-	     * Get props ordered by index.
-	     *
-	     * @param {Object} ownProperties Props object.
-	     * @param {Array} indexes Indexes of props.
-	     * @return {Array} Props.
-	     */
-	    getProps: function (ownProperties, indexes) {
-	      var props = [];
-	
-	      // Make indexes ordered by ascending.
-	      indexes.sort(function (a, b) {
-	        return a - b;
-	      });
-	
-	      indexes.forEach(i => {
-	        var name = Object.keys(ownProperties)[i];
-	        var prop = ownProperties[name];
-	        var value = prop.value !== undefined ? prop.value : prop;
-	        props.push(PropRep(Object.assign({}, this.props, {
-	          key: name,
-	          mode: "tiny",
-	          name: name,
-	          object: value,
-	          equal: ": ",
-	          delim: ", ",
-	          defaultRep: Grip
-	        })));
-	      });
-	
-	      return props;
-	    },
-	
-	    /**
-	     * Get the indexes of props in the object.
-	     *
-	     * @param {Object} ownProperties Props object.
-	     * @param {Number} max The maximum length of indexes array.
-	     * @param {Function} filter Filter the props you want.
-	     * @return {Array} Indexes of interesting props in the object.
-	     */
-	    getPropIndexes: function (ownProperties, max, filter) {
-	      var indexes = [];
-	
-	      try {
-	        var i = 0;
-	        for (var name in ownProperties) {
-	          if (indexes.length >= max) {
-	            return indexes;
-	          }
-	
-	          var prop = ownProperties[name];
-	          var value = prop.value !== undefined ? prop.value : prop;
-	
-	          // Type is specified in grip's "class" field and for primitive
-	          // values use typeof.
-	          var type = value.class || typeof value;
-	          type = type.toLowerCase();
-	
-	          if (filter(type, value, name)) {
-	            indexes.push(i);
-	          }
-	          i++;
-	        }
-	      } catch (err) {
-	        console.error(err);
-	      }
-	
-	      return indexes;
-	    },
-	
-	    render: function () {
-	      var object = this.props.object;
-	      var props = this.safePropIterator(object, this.props.mode == "long" ? 100 : 3);
-	
-	      var objectLink = this.props.objectLink || span;
-	      if (this.props.mode == "tiny" || !props.length) {
-	        return span({ className: "objectBox objectBox-object" }, this.getTitle(object), objectLink({
-	          className: "objectLeftBrace",
-	          object: object
-	        }, ""));
-	      }
-	
-	      return span({ className: "objectBox objectBox-object" }, this.getTitle(object), objectLink({
-	        className: "objectLeftBrace",
-	        object: object
-	      }, " { "), props, objectLink({
-	        className: "objectRightBrace",
-	        object: object
-	      }, " }"));
-	    }
-	  });
-	
-	  // Registration
-	  function supportsObject(object, type) {
-	    if (!isGrip(object)) {
-	      return false;
-	    }
-	    return object.preview && object.preview.ownProperties;
-	  }
-	
-	  var Grip = {
-	    rep: GripRep,
-	    supportsObject: supportsObject
-	  };
-	
-	  // Exports from this module
-	  exports.Grip = Grip;
-	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-
-/***/ },
-/* 45 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-	/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-	/* 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/. */
-	
-	"use strict";
-	
-	// Make this available to both AMD and CJS environments
-	
-	!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
-	  // Dependencies
-	  var React = __webpack_require__(2);
-	
-	  // Shortcuts
-	  var span = React.DOM.span;
-	
-	  /**
-	   * Renders a symbol.
-	   */
-	
-	  var SymbolRep = React.createClass({
-	    displayName: "SymbolRep",
-	
-	    propTypes: {
-	      object: React.PropTypes.object.isRequired
-	    },
-	
-	    render: function () {
-	      var object = this.props.object;
-	      var name = object.name;
-	
-	
-	      return span({ className: "objectBox objectBox-symbol" }, `Symbol(${ name || "" })`);
-	    }
-	  });
-	
-	  function supportsObject(object, type) {
-	    return type == "symbol";
-	  }
-	
-	  // Exports from this module
-	  exports.SymbolRep = {
-	    rep: SymbolRep,
-	    supportsObject: supportsObject
-	  };
-	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-
-/***/ },
-/* 46 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-	/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-	/* 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/. */
-	"use strict";
-	
-	// Make this available to both AMD and CJS environments
-	
-	!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
-	  // ReactJS
-	  var React = __webpack_require__(2);
-	
-	  // Reps
-	
-	  var _require = __webpack_require__(35);
-	
-	  var createFactories = _require.createFactories;
-	  var isGrip = _require.isGrip;
-	
-	  var _require2 = __webpack_require__(38);
-	
-	  var StringRep = _require2.StringRep;
-	
-	  // Shortcuts
-	
-	  var span = React.DOM.span;
-	
-	  var _createFactories = createFactories(StringRep);
-	
-	  var StringRepFactory = _createFactories.rep;
-	
-	  /**
-	   * Renders DOM attribute
-	   */
-	
-	  var Attribute = React.createClass({
-	    displayName: "Attr",
-	
-	    propTypes: {
-	      object: React.PropTypes.object.isRequired
-	    },
-	
-	    getTitle: function (grip) {
-	      return grip.preview.nodeName;
-	    },
-	
-	    render: function () {
-	      var grip = this.props.object;
-	      var value = grip.preview.value;
-	      var objectLink = this.props.objectLink || span;
-	
-	      return objectLink({ className: "objectLink-Attr" }, span({}, span({ className: "attrTitle" }, this.getTitle(grip)), span({ className: "attrEqual" }, "="), StringRepFactory({ object: value })));
-	    }
-	  });
-	
-	  // Registration
-	
-	  function supportsObject(grip, type) {
-	    if (!isGrip(grip)) {
-	      return false;
-	    }
-	
-	    return type == "Attr" && grip.preview;
-	  }
-	
-	  exports.Attribute = {
-	    rep: Attribute,
-	    supportsObject: supportsObject
-	  };
-	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-
-/***/ },
-/* 47 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-	/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-	/* 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/. */
-	"use strict";
-	
-	// Make this available to both AMD and CJS environments
-	
-	!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
-	  // ReactJS
-	  var React = __webpack_require__(2);
-	
-	  // Reps
-	
-	  var _require = __webpack_require__(35);
-	
-	  var isGrip = _require.isGrip;
-	
-	  // Shortcuts
-	
-	  var span = React.DOM.span;
-	
-	  /**
-	   * Used to render JS built-in Date() object.
-	   */
-	
-	  var DateTime = React.createClass({
-	    displayName: "Date",
-	
-	    propTypes: {
-	      object: React.PropTypes.object.isRequired
-	    },
-	
-	    getTitle: function (grip) {
-	      if (this.props.objectLink) {
-	        return this.props.objectLink({
-	          object: grip
-	        }, grip.class + " ");
-	      }
-	      return "";
-	    },
-	
-	    render: function () {
-	      var grip = this.props.object;
-	      return span({ className: "objectBox" }, this.getTitle(grip), span({ className: "Date" }, new Date(grip.preview.timestamp).toISOString()));
-	    }
-	  });
-	
-	  // Registration
-	
-	  function supportsObject(grip, type) {
-	    if (!isGrip(grip)) {
-	      return false;
-	    }
-	
-	    return type == "Date" && grip.preview;
-	  }
-	
-	  // Exports from this module
-	  exports.DateTime = {
-	    rep: DateTime,
-	    supportsObject: supportsObject
-	  };
-	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-
-/***/ },
-/* 48 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-	/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-	/* 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/. */
-	"use strict";
-	
-	// Make this available to both AMD and CJS environments
-	
-	!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
-	  // ReactJS
-	  var React = __webpack_require__(2);
-	
-	  // Reps
-	
-	  var _require = __webpack_require__(35);
-	
-	  var isGrip = _require.isGrip;
-	  var getURLDisplayString = _require.getURLDisplayString;
-	
-	  // Shortcuts
-	
-	  var span = React.DOM.span;
-	
-	  /**
-	   * Renders DOM document object.
-	   */
-	
-	  var Document = React.createClass({
-	    displayName: "Document",
-	
-	    propTypes: {
-	      object: React.PropTypes.object.isRequired
-	    },
-	
-	    getLocation: function (grip) {
-	      var location = grip.preview.location;
-	      return location ? getURLDisplayString(location) : "";
-	    },
-	
-	    getTitle: function (grip) {
-	      if (this.props.objectLink) {
-	        return span({ className: "objectBox" }, this.props.objectLink({
-	          object: grip
-	        }, grip.class + " "));
-	      }
-	      return "";
-	    },
-	
-	    getTooltip: function (doc) {
-	      return doc.location.href;
-	    },
-	
-	    render: function () {
-	      var grip = this.props.object;
-	
-	      return span({ className: "objectBox objectBox-object" }, this.getTitle(grip), span({ className: "objectPropValue" }, this.getLocation(grip)));
-	    }
-	  });
-	
-	  // Registration
-	
-	  function supportsObject(object, type) {
-	    if (!isGrip(object)) {
-	      return false;
-	    }
-	
-	    return object.preview && type == "HTMLDocument";
-	  }
-	
-	  // Exports from this module
-	  exports.Document = {
-	    rep: Document,
-	    supportsObject: supportsObject
-	  };
-	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-
-/***/ },
-/* 49 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-	/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-	/* 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/. */
-	"use strict";
-	
-	// Make this available to both AMD and CJS environments
-	
-	!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
-	  // ReactJS
-	  var React = __webpack_require__(2);
-	
-	  // Reps
-	
-	  var _require = __webpack_require__(35);
-	
-	  var createFactories = _require.createFactories;
-	  var isGrip = _require.isGrip;
-	
-	  var _createFactories = createFactories(__webpack_require__(44).Grip);
-	
-	  var rep = _createFactories.rep;
-	
-	  /**
-	   * Renders DOM event objects.
-	   */
-	
-	  var Event = React.createClass({
-	    displayName: "event",
-	
-	    propTypes: {
-	      object: React.PropTypes.object.isRequired
-	    },
-	
-	    render: function () {
-	      // Use `Object.assign` to keep `this.props` without changes because:
-	      // 1. JSON.stringify/JSON.parse is slow.
-	      // 2. Immutable.js is planned for the future.
-	      var props = Object.assign({}, this.props);
-	      props.object = Object.assign({}, this.props.object);
-	      props.object.preview = Object.assign({}, this.props.object.preview);
-	      props.object.preview.ownProperties = props.object.preview.properties;
-	      delete props.object.preview.properties;
-	      props.object.ownPropertyLength = Object.keys(props.object.preview.ownProperties).length;
-	
-	      switch (props.object.class) {
-	        case "MouseEvent":
-	          props.isInterestingProp = (type, value, name) => {
-	            return name == "clientX" || name == "clientY" || name == "layerX" || name == "layerY";
-	          };
-	          break;
-	        case "KeyboardEvent":
-	          props.isInterestingProp = (type, value, name) => {
-	            return name == "key" || name == "charCode" || name == "keyCode";
-	          };
-	          break;
-	        case "MessageEvent":
-	          props.isInterestingProp = (type, value, name) => {
-	            return name == "isTrusted" || name == "data";
-	          };
-	          break;
-	      }
-	      return rep(props);
-	    }
-	  });
-	
-	  // Registration
-	
-	  function supportsObject(grip, type) {
-	    if (!isGrip(grip)) {
-	      return false;
-	    }
-	
-	    return grip.preview && grip.preview.kind == "DOMEvent";
-	  }
-	
-	  // Exports from this module
-	  exports.Event = {
-	    rep: Event,
-	    supportsObject: supportsObject
-	  };
-	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-
-/***/ },
-/* 50 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-	/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-	/* 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/. */
-	"use strict";
-	
-	// Make this available to both AMD and CJS environments
-	
-	!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
-	  // ReactJS
-	  var React = __webpack_require__(2);
-	
-	  // Reps
-	
-	  var _require = __webpack_require__(35);
-	
-	  var isGrip = _require.isGrip;
-	  var cropString = _require.cropString;
-	
-	  // Shortcuts
-	
-	  var span = React.DOM.span;
-	
-	  /**
-	   * This component represents a template for Function objects.
-	   */
-	
-	  var Func = React.createClass({
-	    displayName: "Func",
-	
-	    propTypes: {
-	      object: React.PropTypes.object.isRequired
-	    },
-	
-	    getTitle: function (grip) {
-	      if (this.props.objectLink) {
-	        return this.props.objectLink({
-	          object: grip
-	        }, "function ");
-	      }
-	      return "";
-	    },
-	
-	    summarizeFunction: function (grip) {
-	      var name = grip.userDisplayName || grip.displayName || grip.name || "function";
-	      return cropString(name + "()", 100);
-	    },
-	
-	    render: function () {
-	      var grip = this.props.object;
-	
-	      return span({ className: "objectBox objectBox-function" }, this.getTitle(grip), this.summarizeFunction(grip));
-	    }
-	  });
-	
-	  // Registration
-	
-	  function supportsObject(grip, type) {
-	    if (!isGrip(grip)) {
-	      return type == "function";
-	    }
-	
-	    return type == "Function";
-	  }
-	
-	  // Exports from this module
-	
-	  exports.Func = {
-	    rep: Func,
-	    supportsObject: supportsObject
-	  };
-	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-
-/***/ },
-/* 51 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-	/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-	/* 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/. */
-	"use strict";
-	
-	// Make this available to both AMD and CJS environments
-	
-	!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
-	  // ReactJS
-	  var React = __webpack_require__(2);
-	
-	  // Reps
-	
-	  var _require = __webpack_require__(35);
-	
-	  var isGrip = _require.isGrip;
-	
-	  // Shortcuts
-	
-	  var span = React.DOM.span;
-	
-	  /**
-	   * Renders a grip object with regular expression.
-	   */
-	
-	  var RegExp = React.createClass({
-	    displayName: "regexp",
-	
-	    propTypes: {
-	      object: React.PropTypes.object.isRequired
-	    },
-	
-	    getSource: function (grip) {
-	      return grip.displayString;
-	    },
-	
-	    render: function () {
-	      var grip = this.props.object;
-	      var objectLink = this.props.objectLink || span;
-	
-	      return span({ className: "objectBox objectBox-regexp" }, objectLink({
-	        object: grip,
-	        className: "regexpSource"
-	      }, this.getSource(grip)));
-	    }
-	  });
-	
-	  // Registration
-	
-	  function supportsObject(object, type) {
-	    if (!isGrip(object)) {
-	      return false;
-	    }
-	
-	    return type == "RegExp";
-	  }
-	
-	  // Exports from this module
-	  exports.RegExp = {
-	    rep: RegExp,
-	    supportsObject: supportsObject
-	  };
-	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-
-/***/ },
-/* 52 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-	/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-	/* 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/. */
-	"use strict";
-	
-	// Make this available to both AMD and CJS environments
-	
-	!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
-	  // ReactJS
-	  var React = __webpack_require__(2);
-	
-	  // Reps
-	
-	  var _require = __webpack_require__(35);
-	
-	  var isGrip = _require.isGrip;
-	  var getURLDisplayString = _require.getURLDisplayString;
-	
-	  // Shortcuts
-	
-	  var DOM = React.DOM;
-	
-	  /**
-	   * Renders a grip representing CSSStyleSheet
-	   */
-	  var StyleSheet = React.createClass({
-	    displayName: "object",
-	
-	    propTypes: {
-	      object: React.PropTypes.object.isRequired
-	    },
-	
-	    getTitle: function (grip) {
-	      var title = "StyleSheet ";
-	      if (this.props.objectLink) {
-	        return DOM.span({ className: "objectBox" }, this.props.objectLink({
-	          object: grip
-	        }, title));
-	      }
-	      return title;
-	    },
-	
-	    getLocation: function (grip) {
-	      // Embedded stylesheets don't have URL and so, no preview.
-	      var url = grip.preview ? grip.preview.url : "";
-	      return url ? getURLDisplayString(url) : "";
-	    },
-	
-	    render: function () {
-	      var grip = this.props.object;
-	
-	      return DOM.span({ className: "objectBox objectBox-object" }, this.getTitle(grip), DOM.span({ className: "objectPropValue" }, this.getLocation(grip)));
-	    }
-	  });
-	
-	  // Registration
-	
-	  function supportsObject(object, type) {
-	    if (!isGrip(object)) {
-	      return false;
-	    }
-	
-	    return type == "CSSStyleSheet";
-	  }
-	
-	  // Exports from this module
-	
-	  exports.StyleSheet = {
-	    rep: StyleSheet,
-	    supportsObject: supportsObject
-	  };
-	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-
-/***/ },
-/* 53 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-	/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-	/* 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/. */
-	"use strict";
-	
-	// Make this available to both AMD and CJS environments
-	
-	!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
-	  // ReactJS
-	  var React = __webpack_require__(2);
-	
-	  // Reps
-	
-	  var _require = __webpack_require__(35);
-	
-	  var isGrip = _require.isGrip;
-	  var cropMultipleLines = _require.cropMultipleLines;
-	
-	  // Shortcuts
-	
-	  var DOM = React.DOM;
-	
-	  /**
-	   * Renders DOM #text node.
-	   */
-	  var TextNode = React.createClass({
-	    displayName: "TextNode",
-	
-	    propTypes: {
-	      object: React.PropTypes.object.isRequired,
-	      mode: React.PropTypes.string
-	    },
-	
-	    getTextContent: function (grip) {
-	      return cropMultipleLines(grip.preview.textContent);
-	    },
-	
-	    getTitle: function (grip) {
-	      if (this.props.objectLink) {
-	        return this.props.objectLink({
-	          object: grip
-	        }, "#text");
-	      }
-	      return "";
-	    },
-	
-	    render: function () {
-	      var grip = this.props.object;
-	      var mode = this.props.mode || "short";
-	
-	      if (mode == "short" || mode == "tiny") {
-	        return DOM.span({ className: "objectBox objectBox-textNode" }, this.getTitle(grip), "\"" + this.getTextContent(grip) + "\"");
-	      }
-	
-	      var objectLink = this.props.objectLink || DOM.span;
-	      return DOM.span({ className: "objectBox objectBox-textNode" }, this.getTitle(grip), objectLink({
-	        object: grip
-	      }, "<"), DOM.span({ className: "nodeTag" }, "TextNode"), " textContent=\"", DOM.span({ className: "nodeValue" }, this.getTextContent(grip)), "\"", objectLink({
-	        object: grip
-	      }, ">;"));
-	    }
-	  });
-	
-	  // Registration
-	
-	  function supportsObject(grip, type) {
-	    if (!isGrip(grip)) {
-	      return false;
-	    }
-	
-	    return grip.preview && grip.class == "Text";
-	  }
-	
-	  // Exports from this module
-	  exports.TextNode = {
-	    rep: TextNode,
-	    supportsObject: supportsObject
-	  };
-	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-
-/***/ },
-/* 54 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-	/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-	/* 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/. */
-	"use strict";
-	
-	// Make this available to both AMD and CJS environments
-	
-	!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
-	  // ReactJS
-	  var React = __webpack_require__(2);
-	
-	  // Reps
-	
-	  var _require = __webpack_require__(35);
-	
-	  var isGrip = _require.isGrip;
-	  var getURLDisplayString = _require.getURLDisplayString;
-	
-	  // Shortcuts
-	
-	  var DOM = React.DOM;
-	
-	  /**
-	   * Renders a grip representing a window.
-	   */
-	  var Window = React.createClass({
-	    displayName: "Window",
-	
-	    propTypes: {
-	      object: React.PropTypes.object.isRequired,
-	      mode: React.PropTypes.string
-	    },
-	
-	    getTitle: function (grip) {
-	      if (this.props.objectLink) {
-	        return DOM.span({ className: "objectBox" }, this.props.objectLink({
-	          object: grip
-	        }, grip.class + " "));
-	      }
-	      return "";
-	    },
-	
-	    getLocation: function (grip) {
-	      return getURLDisplayString(grip.preview.url);
-	    },
-	
-	    getDisplayValue: function (grip) {
-	      if (this.props.mode === "tiny") {
-	        return grip.isGlobal ? "Global" : "Window";
-	      } else {
-	        return this.getLocation(grip);
-	      }
-	    },
-	
-	    render: function () {
-	      var grip = this.props.object;
-	
-	      return DOM.span({ className: "objectBox objectBox-Window" }, this.getTitle(grip), DOM.span({ className: "objectPropValue" }, this.getDisplayValue(grip)));
-	    }
-	  });
-	
-	  // Registration
-	
-	  function supportsObject(object, type) {
-	    if (!isGrip(object)) {
-	      return false;
-	    }
-	
-	    return object.preview && type == "Window";
-	  }
-	
-	  // Exports from this module
-	  exports.Window = {
-	    rep: Window,
-	    supportsObject: supportsObject
-	  };
-	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-
-/***/ },
-/* 55 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-	/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-	/* 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/. */
-	"use strict";
-	
-	// Make this available to both AMD and CJS environments
-	
-	!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
-	  // ReactJS
-	  var React = __webpack_require__(2);
-	
-	  // Reps
-	
-	  var _require = __webpack_require__(35);
-	
-	  var isGrip = _require.isGrip;
-	
-	  // Shortcuts
-	
-	  var span = React.DOM.span;
-	
-	  /**
-	   * Renders a grip object with textual data.
-	   */
-	
-	  var ObjectWithText = React.createClass({
-	    displayName: "ObjectWithText",
-	
-	    propTypes: {
-	      object: React.PropTypes.object.isRequired
-	    },
-	
-	    getTitle: function (grip) {
-	      if (this.props.objectLink) {
-	        return span({ className: "objectBox" }, this.props.objectLink({
-	          object: grip
-	        }, this.getType(grip) + " "));
-	      }
-	      return "";
-	    },
-	
-	    getType: function (grip) {
-	      return grip.class;
-	    },
-	
-	    getDescription: function (grip) {
-	      return "\"" + grip.preview.text + "\"";
-	    },
-	
-	    render: function () {
-	      var grip = this.props.object;
-	      return span({ className: "objectBox objectBox-" + this.getType(grip) }, this.getTitle(grip), span({ className: "objectPropValue" }, this.getDescription(grip)));
-	    }
-	  });
-	
-	  // Registration
-	
-	  function supportsObject(grip, type) {
-	    if (!isGrip(grip)) {
-	      return false;
-	    }
-	
-	    return grip.preview && grip.preview.kind == "ObjectWithText";
-	  }
-	
-	  // Exports from this module
-	  exports.ObjectWithText = {
-	    rep: ObjectWithText,
-	    supportsObject: supportsObject
-	  };
-	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-
-/***/ },
-/* 56 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-	/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-	/* 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/. */
-	"use strict";
-	
-	// Make this available to both AMD and CJS environments
-	
-	!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
-	  // ReactJS
-	  var React = __webpack_require__(2);
-	
-	  // Reps
-	
-	  var _require = __webpack_require__(35);
-	
-	  var isGrip = _require.isGrip;
-	  var getURLDisplayString = _require.getURLDisplayString;
-	
-	  // Shortcuts
-	
-	  var span = React.DOM.span;
-	
-	  /**
-	   * Renders a grip object with URL data.
-	   */
-	
-	  var ObjectWithURL = React.createClass({
-	    displayName: "ObjectWithURL",
-	
-	    propTypes: {
-	      object: React.PropTypes.object.isRequired
-	    },
-	
-	    getTitle: function (grip) {
-	      if (this.props.objectLink) {
-	        return span({ className: "objectBox" }, this.props.objectLink({
-	          object: grip
-	        }, this.getType(grip) + " "));
-	      }
-	      return "";
-	    },
-	
-	    getType: function (grip) {
-	      return grip.class;
-	    },
-	
-	    getDescription: function (grip) {
-	      return getURLDisplayString(grip.preview.url);
-	    },
-	
-	    render: function () {
-	      var grip = this.props.object;
-	      return span({ className: "objectBox objectBox-" + this.getType(grip) }, this.getTitle(grip), span({ className: "objectPropValue" }, this.getDescription(grip)));
-	    }
-	  });
-	
-	  // Registration
-	
-	  function supportsObject(grip, type) {
-	    if (!isGrip(grip)) {
-	      return false;
-	    }
-	
-	    return grip.preview && grip.preview.kind == "ObjectWithURL";
-	  }
-	
-	  // Exports from this module
-	  exports.ObjectWithURL = {
-	    rep: ObjectWithURL,
-	    supportsObject: supportsObject
-	  };
-	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-
-/***/ },
-/* 57 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-	/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-	/* 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/. */
-	
-	"use strict";
-	
-	// Make this available to both AMD and CJS environments
-	
-	!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
-	  // Dependencies
-	  var React = __webpack_require__(2);
-	
-	  var _require = __webpack_require__(35);
-	
-	  var createFactories = _require.createFactories;
-	  var isGrip = _require.isGrip;
-	
-	  var _createFactories = createFactories(__webpack_require__(41));
-	
-	  var Caption = _createFactories.Caption;
-	
-	  // Shortcuts
-	
-	  var span = React.DOM.span;
-	
-	  /**
-	   * Renders an array. The array is enclosed by left and right bracket
-	   * and the max number of rendered items depends on the current mode.
-	   */
-	
-	  var GripArray = React.createClass({
-	    displayName: "GripArray",
-	
-	    propTypes: {
-	      object: React.PropTypes.object.isRequired,
-	      mode: React.PropTypes.string,
-	      provider: React.PropTypes.object
-	    },
-	
-	    getLength: function (grip) {
-	      return grip.preview ? grip.preview.length : 0;
-	    },
-	
-	    getTitle: function (object, context) {
-	      var objectLink = this.props.objectLink || span;
-	      if (this.props.mode != "tiny") {
-	        return objectLink({
-	          object: object
-	        }, object.class + " ");
-	      }
-	      return "";
-	    },
-	
-	    arrayIterator: function (grip, max) {
-	      var items = [];
-	
-	      if (!grip.preview || !grip.preview.length) {
-	        return items;
-	      }
-	
-	      var array = grip.preview.items;
-	      if (!array) {
-	        return items;
-	      }
-	
-	      var delim = void 0;
-	      // number of grip.preview.items is limited to 10, but we may have more
-	      // items in grip-array
-	      var delimMax = grip.preview.length > array.length ? array.length : array.length - 1;
-	      var provider = this.props.provider;
-	
-	      for (var i = 0; i < array.length && i < max; i++) {
-	        try {
-	          var itemGrip = array[i];
-	          var value = provider ? provider.getValue(itemGrip) : itemGrip;
-	
-	          delim = i == delimMax ? "" : ", ";
-	
-	          items.push(GripArrayItem(Object.assign({}, this.props, {
-	            key: i,
-	            object: value,
-	            delim: delim })));
-	        } catch (exc) {
-	          items.push(GripArrayItem(Object.assign({}, this.props, {
-	            object: exc,
-	            delim: delim,
-	            key: i })));
-	        }
-	      }
-	      if (array.length > max || grip.preview.length > array.length) {
-	        var objectLink = this.props.objectLink || span;
-	        var leftItemNum = grip.preview.length - max > 0 ? grip.preview.length - max : grip.preview.length - array.length;
-	        items.push(Caption({
-	          key: "more",
-	          object: objectLink({
-	            object: this.props.object
-	          }, leftItemNum + " more…")
-	        }));
-	      }
-	
-	      return items;
-	    },
-	
-	    render: function () {
-	      var mode = this.props.mode || "short";
-	      var object = this.props.object;
-	
-	      var items = void 0;
-	      var brackets = void 0;
-	      var needSpace = function (space) {
-	        return space ? { left: "[ ", right: " ]" } : { left: "[", right: "]" };
-	      };
-	
-	      if (mode == "tiny") {
-	        var objectLength = this.getLength(object);
-	        var isEmpty = objectLength === 0;
-	        items = span({ className: "length" }, isEmpty ? "" : objectLength);
-	        brackets = needSpace(false);
-	      } else {
-	        var max = mode == "short" ? 3 : 300;
-	        items = this.arrayIterator(object, max);
-	        brackets = needSpace(items.length > 0);
-	      }
-	
-	      var objectLink = this.props.objectLink || span;
-	      var title = this.getTitle(object);
-	
-	      return span({
-	        className: "objectBox objectBox-array" }, title, objectLink({
-	        className: "arrayLeftBracket",
-	        object: object
-	      }, brackets.left), items, objectLink({
-	        className: "arrayRightBracket",
-	        object: object
-	      }, brackets.right), span({
-	        className: "arrayProperties",
-	        role: "group" }));
-	    }
-	  });
-	
-	  /**
-	   * Renders array item. Individual values are separated by
-	   * a delimiter (a comma by default).
-	   */
-	  var GripArrayItem = React.createFactory(React.createClass({
-	    displayName: "GripArrayItem",
-	
-	    propTypes: {
-	      delim: React.PropTypes.string
-	    },
-	
-	    render: function () {
-	      var _createFactories2 = createFactories(__webpack_require__(34));
-	
-	      var Rep = _createFactories2.Rep;
-	
-	
-	      return span({}, Rep(Object.assign({}, this.props, {
-	        mode: "tiny"
-	      })), this.props.delim);
-	    }
-	  }));
-	
-	  function supportsObject(grip, type) {
-	    if (!isGrip(grip)) {
-	      return false;
-	    }
-	
-	    return grip.preview && grip.preview.kind == "ArrayLike";
-	  }
-	
-	  // Exports from this module
-	  exports.GripArray = {
-	    rep: GripArray,
-	    supportsObject: supportsObject
-	  };
-	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-
-/***/ },
-/* 58 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-	/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-	/* 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/. */
-	
-	"use strict";
-	// Make this available to both AMD and CJS environments
-	
-	var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
-	
-	!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
-	  // Dependencies
-	  var React = __webpack_require__(2);
-	
-	  var _require = __webpack_require__(35);
-	
-	  var createFactories = _require.createFactories;
-	  var isGrip = _require.isGrip;
-	
-	  var _createFactories = createFactories(__webpack_require__(41));
-	
-	  var Caption = _createFactories.Caption;
-	
-	  var _createFactories2 = createFactories(__webpack_require__(43));
-	
-	  var PropRep = _createFactories2.PropRep;
-	
-	  // Shortcuts
-	
-	  var span = React.DOM.span;
-	  /**
-	   * Renders an map. A map is represented by a list of its
-	   * entries enclosed in curly brackets.
-	   */
-	
-	  var GripMap = React.createClass({
-	    displayName: "GripMap",
-	
-	    propTypes: {
-	      object: React.PropTypes.object,
-	      mode: React.PropTypes.string
-	    },
-	
-	    getTitle: function (object) {
-	      var title = object && object.class ? object.class : "Map";
-	      if (this.props.objectLink) {
-	        return this.props.objectLink({
-	          object: object
-	        }, title);
-	      }
-	      return title;
-	    },
-	
-	    safeEntriesIterator: function (object, max) {
-	      max = typeof max === "undefined" ? 3 : max;
-	      try {
-	        return this.entriesIterator(object, max);
-	      } catch (err) {
-	        console.error(err);
-	      }
-	      return [];
-	    },
-	
-	    entriesIterator: function (object, max) {
-	      // Entry filter. Show only interesting entries to the user.
-	      var isInterestingEntry = this.props.isInterestingEntry || ((type, value) => {
-	        return type == "boolean" || type == "number" || type == "string" && value.length != 0;
-	      });
-	
-	      var mapEntries = object.preview && object.preview.entries ? object.preview.entries : [];
-	
-	      var indexes = this.getEntriesIndexes(mapEntries, max, isInterestingEntry);
-	      if (indexes.length < max && indexes.length < mapEntries.length) {
-	        // There are not enough entries yet, so we add uninteresting entries.
-	        indexes = indexes.concat(this.getEntriesIndexes(mapEntries, max - indexes.length, (t, value, name) => {
-	          return !isInterestingEntry(t, value, name);
-	        }));
-	      }
-	
-	      var entries = this.getEntries(mapEntries, indexes);
-	      if (entries.length < mapEntries.length) {
-	        // There are some undisplayed entries. Then display "more…".
-	        var objectLink = this.props.objectLink || span;
-	
-	        entries.push(Caption({
-	          key: "more",
-	          object: objectLink({
-	            object: object
-	          }, `${ mapEntries.length - max } more…`)
-	        }));
-	      }
-	
-	      return entries;
-	    },
-	
-	    /**
-	     * Get entries ordered by index.
-	     *
-	     * @param {Array} entries Entries array.
-	     * @param {Array} indexes Indexes of entries.
-	     * @return {Array} Array of PropRep.
-	     */
-	    getEntries: function (entries, indexes) {
-	      // Make indexes ordered by ascending.
-	      indexes.sort(function (a, b) {
-	        return a - b;
-	      });
-	
-	      return indexes.map((index, i) => {
-	        var _entries$index = _slicedToArray(entries[index], 2);
-	
-	        var key = _entries$index[0];
-	        var entryValue = _entries$index[1];
-	
-	        var value = entryValue.value !== undefined ? entryValue.value : entryValue;
-	
-	        return PropRep({
-	          // key,
-	          name: key,
-	          equal: ": ",
-	          object: value,
-	          // Do not add a trailing comma on the last entry
-	          // if there won't be a "more..." item.
-	          delim: i < indexes.length - 1 || indexes.length < entries.length ? ", " : "",
-	          mode: "tiny",
-	          objectLink: this.props.objectLink
-	        });
-	      });
-	    },
-	
-	    /**
-	     * Get the indexes of entries in the map.
-	     *
-	     * @param {Array} entries Entries array.
-	     * @param {Number} max The maximum length of indexes array.
-	     * @param {Function} filter Filter the entry you want.
-	     * @return {Array} Indexes of filtered entries in the map.
-	     */
-	    getEntriesIndexes: function (entries, max, filter) {
-	      return entries.reduce((indexes, _ref, i) => {
-	        var _ref2 = _slicedToArray(_ref, 2);
-	
-	        var key = _ref2[0];
-	        var entry = _ref2[1];
-	
-	        if (indexes.length < max) {
-	          var value = entry && entry.value !== undefined ? entry.value : entry;
-	          // Type is specified in grip's "class" field and for primitive
-	          // values use typeof.
-	          var type = (value && value.class ? value.class : typeof value).toLowerCase();
-	
-	          if (filter(type, value, key)) {
-	            indexes.push(i);
-	          }
-	        }
-	
-	        return indexes;
-	      }, []);
-	    },
-	
-	    render: function () {
-	      var object = this.props.object;
-	      var props = this.safeEntriesIterator(object, this.props.mode == "long" ? 100 : 3);
-	
-	      var objectLink = this.props.objectLink || span;
-	      if (this.props.mode == "tiny") {
-	        return span({ className: "objectBox objectBox-object" }, this.getTitle(object), objectLink({
-	          className: "objectLeftBrace",
-	          object: object
-	        }, ""));
-	      }
-	
-	      return span({ className: "objectBox objectBox-object" }, this.getTitle(object), objectLink({
-	        className: "objectLeftBrace",
-	        object: object
-	      }, " { "), props, objectLink({
-	        className: "objectRightBrace",
-	        object: object
-	      }, " }"));
-	    }
-	  });
-	
-	  function supportsObject(grip, type) {
-	    if (!isGrip(grip)) {
-	      return false;
-	    }
-	    return grip.preview && grip.preview.kind == "MapLike";
-	  }
-	
-	  // Exports from this module
-	  exports.GripMap = {
-	    rep: GripMap,
-	    supportsObject: supportsObject
-	  };
-	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-
-/***/ },
-/* 59 */
+
+/***/ },
+/* 33 */
 /***/ function(module, exports, __webpack_require__) {
 
 	/**
 	 * Copyright (c) 2007-2016, Alexandru Marasteanu <hello [at) alexei (dot] ro>
 	 * All rights reserved.
 	 *
 	 * Redistribution and use in source and binary forms, with or without
 	 * modification, are permitted provided that the following conditions are met:
@@ -5041,550 +2154,519 @@ var Debugger =
 	 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 	 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 	 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 	 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 	 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 	 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 	 *
 	 */
-	
+
 	/* globals window, exports, define */
-	
-	(function (window) {
-	    'use strict';
-	
+
+	(function(window) {
+	    'use strict'
+
 	    var re = {
 	        not_string: /[^s]/,
 	        not_bool: /[^t]/,
 	        not_type: /[^T]/,
 	        not_primitive: /[^v]/,
 	        number: /[diefg]/,
 	        numeric_arg: /bcdiefguxX/,
 	        json: /[j]/,
 	        not_json: /[^j]/,
 	        text: /^[^\x25]+/,
 	        modulo: /^\x25{2}/,
 	        placeholder: /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-gijosStTuvxX])/,
 	        key: /^([a-z_][a-z_\d]*)/i,
 	        key_access: /^\.([a-z_][a-z_\d]*)/i,
 	        index_access: /^\[(\d+)\]/,
 	        sign: /^[\+\-]/
-	    };
-	
+	    }
+
 	    function sprintf() {
-	        var key = arguments[0],
-	            cache = sprintf.cache;
+	        var key = arguments[0], cache = sprintf.cache
 	        if (!(cache[key] && cache.hasOwnProperty(key))) {
-	            cache[key] = sprintf.parse(key);
-	        }
-	        return sprintf.format.call(null, cache[key], arguments);
-	    }
-	
-	    sprintf.format = function (parse_tree, argv) {
-	        var cursor = 1,
-	            tree_length = parse_tree.length,
-	            node_type = '',
-	            arg,
-	            output = [],
-	            i,
-	            k,
-	            match,
-	            pad,
-	            pad_character,
-	            pad_length,
-	            is_positive = true,
-	            sign = '';
+	            cache[key] = sprintf.parse(key)
+	        }
+	        return sprintf.format.call(null, cache[key], arguments)
+	    }
+
+	    sprintf.format = function(parse_tree, argv) {
+	        var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length, is_positive = true, sign = ''
 	        for (i = 0; i < tree_length; i++) {
-	            node_type = get_type(parse_tree[i]);
+	            node_type = get_type(parse_tree[i])
 	            if (node_type === 'string') {
-	                output[output.length] = parse_tree[i];
-	            } else if (node_type === 'array') {
-	                match = parse_tree[i]; // convenience purposes only
-	                if (match[2]) {
-	                    // keyword argument
-	                    arg = argv[cursor];
+	                output[output.length] = parse_tree[i]
+	            }
+	            else if (node_type === 'array') {
+	                match = parse_tree[i] // convenience purposes only
+	                if (match[2]) { // keyword argument
+	                    arg = argv[cursor]
 	                    for (k = 0; k < match[2].length; k++) {
 	                        if (!arg.hasOwnProperty(match[2][k])) {
-	                            throw new Error(sprintf('[sprintf] property "%s" does not exist', match[2][k]));
+	                            throw new Error(sprintf('[sprintf] property "%s" does not exist', match[2][k]))
 	                        }
-	                        arg = arg[match[2][k]];
+	                        arg = arg[match[2][k]]
 	                    }
-	                } else if (match[1]) {
-	                    // positional argument (explicit)
-	                    arg = argv[match[1]];
-	                } else {
-	                    // positional argument (implicit)
-	                    arg = argv[cursor++];
+	                }
+	                else if (match[1]) { // positional argument (explicit)
+	                    arg = argv[match[1]]
+	                }
+	                else { // positional argument (implicit)
+	                    arg = argv[cursor++]
 	                }
-	
+
 	                if (re.not_type.test(match[8]) && re.not_primitive.test(match[8]) && get_type(arg) == 'function') {
-	                    arg = arg();
+	                    arg = arg()
 	                }
-	
-	                if (re.numeric_arg.test(match[8]) && get_type(arg) != 'number' && isNaN(arg)) {
-	                    throw new TypeError(sprintf("[sprintf] expecting number but found %s", get_type(arg)));
+
+	                if (re.numeric_arg.test(match[8]) && (get_type(arg) != 'number' && isNaN(arg))) {
+	                    throw new TypeError(sprintf("[sprintf] expecting number but found %s", get_type(arg)))
 	                }
-	
+
 	                if (re.number.test(match[8])) {
-	                    is_positive = arg >= 0;
+	                    is_positive = arg >= 0
 	                }
-	
+
 	                switch (match[8]) {
 	                    case 'b':
-	                        arg = parseInt(arg, 10).toString(2);
-	                        break;
+	                        arg = parseInt(arg, 10).toString(2)
+	                    break
 	                    case 'c':
-	                        arg = String.fromCharCode(parseInt(arg, 10));
-	                        break;
+	                        arg = String.fromCharCode(parseInt(arg, 10))
+	                    break
 	                    case 'd':
 	                    case 'i':
-	                        arg = parseInt(arg, 10);
-	                        break;
+	                        arg = parseInt(arg, 10)
+	                    break
 	                    case 'j':
-	                        arg = JSON.stringify(arg, null, match[6] ? parseInt(match[6]) : 0);
-	                        break;
+	                        arg = JSON.stringify(arg, null, match[6] ? parseInt(match[6]) : 0)
+	                    break
 	                    case 'e':
-	                        arg = match[7] ? parseFloat(arg).toExponential(match[7]) : parseFloat(arg).toExponential();
-	                        break;
+	                        arg = match[7] ? parseFloat(arg).toExponential(match[7]) : parseFloat(arg).toExponential()
+	                    break
 	                    case 'f':
-	                        arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg);
-	                        break;
+	                        arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg)
+	                    break
 	                    case 'g':
-	                        arg = match[7] ? parseFloat(arg).toPrecision(match[7]) : parseFloat(arg);
-	                        break;
+	                        arg = match[7] ? parseFloat(arg).toPrecision(match[7]) : parseFloat(arg)
+	                    break
 	                    case 'o':
-	                        arg = arg.toString(8);
-	                        break;
+	                        arg = arg.toString(8)
+	                    break
 	                    case 's':
 	                    case 'S':
-	                        arg = String(arg);
-	                        arg = match[7] ? arg.substring(0, match[7]) : arg;
-	                        break;
+	                        arg = String(arg)
+	                        arg = (match[7] ? arg.substring(0, match[7]) : arg)
+	                    break
 	                    case 't':
-	                        arg = String(!!arg);
-	                        arg = match[7] ? arg.substring(0, match[7]) : arg;
-	                        break;
+	                        arg = String(!!arg)
+	                        arg = (match[7] ? arg.substring(0, match[7]) : arg)
+	                    break
 	                    case 'T':
-	                        arg = get_type(arg);
-	                        arg = match[7] ? arg.substring(0, match[7]) : arg;
-	                        break;
+	                        arg = get_type(arg)
+	                        arg = (match[7] ? arg.substring(0, match[7]) : arg)
+	                    break
 	                    case 'u':
-	                        arg = parseInt(arg, 10) >>> 0;
-	                        break;
+	                        arg = parseInt(arg, 10) >>> 0
+	                    break
 	                    case 'v':
-	                        arg = arg.valueOf();
-	                        arg = match[7] ? arg.substring(0, match[7]) : arg;
-	                        break;
+	                        arg = arg.valueOf()
+	                        arg = (match[7] ? arg.substring(0, match[7]) : arg)
+	                    break
 	                    case 'x':
-	                        arg = parseInt(arg, 10).toString(16);
-	                        break;
+	                        arg = parseInt(arg, 10).toString(16)
+	                    break
 	                    case 'X':
-	                        arg = parseInt(arg, 10).toString(16).toUpperCase();
-	                        break;
+	                        arg = parseInt(arg, 10).toString(16).toUpperCase()
+	                    break
 	                }
 	                if (re.json.test(match[8])) {
-	                    output[output.length] = arg;
-	                } else {
+	                    output[output.length] = arg
+	                }
+	                else {
 	                    if (re.number.test(match[8]) && (!is_positive || match[3])) {
-	                        sign = is_positive ? '+' : '-';
-	                        arg = arg.toString().replace(re.sign, '');
-	                    } else {
-	                        sign = '';
+	                        sign = is_positive ? '+' : '-'
+	                        arg = arg.toString().replace(re.sign, '')
 	                    }
-	                    pad_character = match[4] ? match[4] === '0' ? '0' : match[4].charAt(1) : ' ';
-	                    pad_length = match[6] - (sign + arg).length;
-	                    pad = match[6] ? pad_length > 0 ? str_repeat(pad_character, pad_length) : '' : '';
-	                    output[output.length] = match[5] ? sign + arg + pad : pad_character === '0' ? sign + pad + arg : pad + sign + arg;
+	                    else {
+	                        sign = ''
+	                    }
+	                    pad_character = match[4] ? match[4] === '0' ? '0' : match[4].charAt(1) : ' '
+	                    pad_length = match[6] - (sign + arg).length
+	                    pad = match[6] ? (pad_length > 0 ? str_repeat(pad_character, pad_length) : '') : ''
+	                    output[output.length] = match[5] ? sign + arg + pad : (pad_character === '0' ? sign + pad + arg : pad + sign + arg)
 	                }
 	            }
 	        }
-	        return output.join('');
-	    };
-	
-	    sprintf.cache = {};
-	
-	    sprintf.parse = function (fmt) {
-	        var _fmt = fmt,
-	            match = [],
-	            parse_tree = [],
-	            arg_names = 0;
+	        return output.join('')
+	    }
+
+	    sprintf.cache = {}
+
+	    sprintf.parse = function(fmt) {
+	        var _fmt = fmt, match = [], parse_tree = [], arg_names = 0
 	        while (_fmt) {
 	            if ((match = re.text.exec(_fmt)) !== null) {
-	                parse_tree[parse_tree.length] = match[0];
-	            } else if ((match = re.modulo.exec(_fmt)) !== null) {
-	                parse_tree[parse_tree.length] = '%';
-	            } else if ((match = re.placeholder.exec(_fmt)) !== null) {
+	                parse_tree[parse_tree.length] = match[0]
+	            }
+	            else if ((match = re.modulo.exec(_fmt)) !== null) {
+	                parse_tree[parse_tree.length] = '%'
+	            }
+	            else if ((match = re.placeholder.exec(_fmt)) !== null) {
 	                if (match[2]) {
-	                    arg_names |= 1;
-	                    var field_list = [],
-	                        replacement_field = match[2],
-	                        field_match = [];
+	                    arg_names |= 1
+	                    var field_list = [], replacement_field = match[2], field_match = []
 	                    if ((field_match = re.key.exec(replacement_field)) !== null) {
-	                        field_list[field_list.length] = field_match[1];
+	                        field_list[field_list.length] = field_match[1]
 	                        while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
 	                            if ((field_match = re.key_access.exec(replacement_field)) !== null) {
-	                                field_list[field_list.length] = field_match[1];
-	                            } else if ((field_match = re.index_access.exec(replacement_field)) !== null) {
-	                                field_list[field_list.length] = field_match[1];
-	                            } else {
-	                                throw new SyntaxError("[sprintf] failed to parse named argument key");
+	                                field_list[field_list.length] = field_match[1]
+	                            }
+	                            else if ((field_match = re.index_access.exec(replacement_field)) !== null) {
+	                                field_list[field_list.length] = field_match[1]
+	                            }
+	                            else {
+	                                throw new SyntaxError("[sprintf] failed to parse named argument key")
 	                            }
 	                        }
-	                    } else {
-	                        throw new SyntaxError("[sprintf] failed to parse named argument key");
+	                    }
+	                    else {
+	                        throw new SyntaxError("[sprintf] failed to parse named argument key")
 	                    }
-	                    match[2] = field_list;
-	                } else {
-	                    arg_names |= 2;
+	                    match[2] = field_list
+	                }
+	                else {
+	                    arg_names |= 2
 	                }
 	                if (arg_names === 3) {
-	                    throw new Error("[sprintf] mixing positional and named placeholders is not (yet) supported");
+	                    throw new Error("[sprintf] mixing positional and named placeholders is not (yet) supported")
 	                }
-	                parse_tree[parse_tree.length] = match;
-	            } else {
-	                throw new SyntaxError("[sprintf] unexpected placeholder");
+	                parse_tree[parse_tree.length] = match
+	            }
+	            else {
+	                throw new SyntaxError("[sprintf] unexpected placeholder")
 	            }
-	            _fmt = _fmt.substring(match[0].length);
-	        }
-	        return parse_tree;
-	    };
-	
-	    var vsprintf = function (fmt, argv, _argv) {
-	        _argv = (argv || []).slice(0);
-	        _argv.splice(0, 0, fmt);
-	        return sprintf.apply(null, _argv);
-	    };
-	
+	            _fmt = _fmt.substring(match[0].length)
+	        }
+	        return parse_tree
+	    }
+
+	    var vsprintf = function(fmt, argv, _argv) {
+	        _argv = (argv || []).slice(0)
+	        _argv.splice(0, 0, fmt)
+	        return sprintf.apply(null, _argv)
+	    }
+
 	    /**
 	     * helpers
 	     */
 	    function get_type(variable) {
 	        if (typeof variable === 'number') {
-	            return 'number';
-	        } else if (typeof variable === 'string') {
-	            return 'string';
-	        } else {
-	            return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();
-	        }
-	    }
-	
+	            return 'number'
+	        }
+	        else if (typeof variable === 'string') {
+	            return 'string'
+	        }
+	        else {
+	            return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase()
+	        }
+	    }
+
 	    var preformattedPadding = {
 	        '0': ['', '0', '00', '000', '0000', '00000', '000000', '0000000'],
 	        ' ': ['', ' ', '  ', '   ', '    ', '     ', '      ', '       '],
-	        '_': ['', '_', '__', '___', '____', '_____', '______', '_______']
-	    };
+	        '_': ['', '_', '__', '___', '____', '_____', '______', '_______'],
+	    }
 	    function str_repeat(input, multiplier) {
 	        if (multiplier >= 0 && multiplier <= 7 && preformattedPadding[input]) {
-	            return preformattedPadding[input][multiplier];
-	        }
-	        return Array(multiplier + 1).join(input);
-	    }
-	
+	            return preformattedPadding[input][multiplier]
+	        }
+	        return Array(multiplier + 1).join(input)
+	    }
+
 	    /**
 	     * export to either browser or node.js
 	     */
 	    if (true) {
-	        exports.sprintf = sprintf;
-	        exports.vsprintf = vsprintf;
-	    } else {
-	        window.sprintf = sprintf;
-	        window.vsprintf = vsprintf;
-	
+	        exports.sprintf = sprintf
+	        exports.vsprintf = vsprintf
+	    }
+	    else {
+	        window.sprintf = sprintf
+	        window.vsprintf = vsprintf
+
 	        if (typeof define === 'function' && define.amd) {
-	            define(function () {
+	            define(function() {
 	                return {
 	                    sprintf: sprintf,
 	                    vsprintf: vsprintf
-	                };
-	            });
+	                }
+	            })
 	        }
 	    }
 	})(typeof window === 'undefined' ? this : window);
 
-/***/ },
-/* 60 */
+
+/***/ },
+/* 34 */
 /***/ function(module, exports, __webpack_require__) {
 
 	/* 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/. */
-	
+
 	/**
 	 * EventEmitter.
 	 */
-	
+
 	var EventEmitter = function EventEmitter() {};
 	module.exports = EventEmitter;
-	
-	var _require = __webpack_require__(61);
-	
-	var Cu = _require.Cu;
-	
-	var promise = __webpack_require__(66);
-	
+
+	const { Cu } = __webpack_require__(35);
+	const promise = __webpack_require__(40);
+
 	/**
 	 * Decorate an object with event emitter functionality.
 	 *
 	 * @param Object aObjectToDecorate
 	 *        Bind all public methods of EventEmitter to
 	 *        the aObjectToDecorate object.
 	 */
-	EventEmitter.decorate = function EventEmitter_decorate(aObjectToDecorate) {
-	  var emitter = new EventEmitter();
+	EventEmitter.decorate = function EventEmitter_decorate (aObjectToDecorate) {
+	  let emitter = new EventEmitter();
 	  aObjectToDecorate.on = emitter.on.bind(emitter);
 	  aObjectToDecorate.off = emitter.off.bind(emitter);
 	  aObjectToDecorate.once = emitter.once.bind(emitter);
 	  aObjectToDecorate.emit = emitter.emit.bind(emitter);
 	};
-	
+
 	EventEmitter.prototype = {
 	  /**
 	   * Connect a listener.
 	   *
 	   * @param string aEvent
 	   *        The event name to which we're connecting.
 	   * @param function aListener
 	   *        Called when the event is fired.
 	   */