Merge autoland to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 15 Sep 2017 14:15:29 -0400
changeset 665597 31992a5c3d64ade078accdaab8ac4ffb5e43a9d7
parent 665543 9071a20f3eaa804a439990b7596dbc16d52d1e20 (current diff)
parent 665596 7ef7bcbd8884ababc8461fa3fe18d649526227d7 (diff)
child 665598 b42a99aeb7fadfb2e41d2f75094da682b3afca3b
child 665623 7aceaf8bcb9f582db0f93488b48ef7019e348dba
push id80115
push userbmo:eoger@fastmail.com
push dateFri, 15 Sep 2017 18:29:01 +0000
reviewersmerge
milestone57.0a1
Merge autoland to m-c. a=merge
browser/themes/shared/icons/email-link.svg
gfx/webrender/res/ps_box_shadow.fs.glsl
gfx/webrender/res/ps_box_shadow.vs.glsl
gfx/webrender/res/ps_image.fs.glsl
gfx/webrender/res/ps_image.vs.glsl
gfx/webrender/res/ps_rectangle.fs.glsl
gfx/webrender/res/ps_rectangle.vs.glsl
gfx/webrender/res/ps_text_run.fs.glsl
gfx/webrender/res/ps_text_run.vs.glsl
gfx/webrender/res/ps_yuv_image.fs.glsl
gfx/webrender/res/ps_yuv_image.vs.glsl
memory/build/mozmemory_wrap.c
testing/talos/talos/tests/perf-reftest-singletons/bloom_basic_singleton.manifest
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1695,16 +1695,21 @@ pref("browser.crashReports.unsubmittedCh
 #ifdef NIGHTLY_BUILD
 pref("extensions.formautofill.available", "on");
 #elif MOZ_UPDATE_CHANNEL == release
 pref("extensions.formautofill.available", "staged-rollout");
 #else
 pref("extensions.formautofill.available", "detect");
 #endif
 pref("extensions.formautofill.addresses.enabled", true);
+#ifdef NIGHTLY_BUILD
+pref("extensions.formautofill.creditCards.available", true);
+#else
+pref("extensions.formautofill.creditCards.available", false);
+#endif
 pref("extensions.formautofill.creditCards.enabled", true);
 pref("extensions.formautofill.firstTimeUse", true);
 pref("extensions.formautofill.heuristics.enabled", true);
 pref("extensions.formautofill.loglevel", "Warn");
 
 // Whether or not to restore a session with lazy-browser tabs.
 pref("browser.sessionstore.restore_tabs_lazily", true);
 
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -541,16 +541,29 @@ toolbar:not(#TabsToolbar) > #personal-bo
   width: 1px;
   min-width: 1px;
 }
 
 #urlbar {
   -moz-binding: url(chrome://browser/content/urlbarBindings.xml#urlbar);
 }
 
+/* Display URLs left-to-right but right aligned in RTL mode. */
+html|input.urlbar-input:-moz-locale-dir(rtl) {
+  direction: ltr !important;
+  text-align: right !important;
+}
+
+/* Make sure that the location bar's alignment in RTL mode changes according
+   to the input box direction if the user switches the text direction using
+   cmd_switchTextDirection (which applies a dir attribute to the <input>). */
+html|input.urlbar-input[dir=ltr]:-moz-locale-dir(rtl) {
+  text-align: left !important;
+}
+
 /*
  * Display visual cue that browser is under remote control by Marionette.
  * This is to help users visually distinguish a user agent session that
  * is under remote control from those used for normal browsing sessions.
  *
  * Attribute is controlled by browser.js:/gRemoteControl.
  */
 #main-window[remotecontrol] #urlbar {
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -32,17 +32,17 @@ file, You can obtain one at http://mozil
         <children includes="image|deck|stack|box">
           <xul:image class="autocomplete-icon" allowevents="true"/>
         </children>
         <xul:hbox anonid="textbox-input-box"
                   class="textbox-input-box urlbar-input-box"
                   flex="1" xbl:inherits="tooltiptext=inputtooltiptext">
           <children/>
           <html:input anonid="input"
-                      class="autocomplete-textbox urlbar-input textbox-input uri-element-right-align"
+                      class="autocomplete-textbox urlbar-input textbox-input"
                       allowevents="true"
                       inputmode="url"
                       xbl:inherits="tooltiptext=inputtooltiptext,value,maxlength,disabled,size,readonly,placeholder,tabindex,accesskey,focused,textoverflow"/>
         </xul:hbox>
         <xul:image anonid="urlbar-go-button"
                    class="urlbar-go-button urlbar-icon"
                    onclick="gURLBar.handleCommand(event);"
                    tooltiptext="&goEndCap.tooltip;"
--- a/browser/components/customizableui/SearchWidgetTracker.jsm
+++ b/browser/components/customizableui/SearchWidgetTracker.jsm
@@ -31,20 +31,25 @@ const SearchWidgetTracker = {
     this.onWidgetReset = this.onWidgetUndoMove = node => {
       if (node.id == WIDGET_ID) {
         this.syncPreferenceWithWidget();
       }
     };
     CustomizableUI.addListener(this);
     Services.prefs.addObserver(PREF_NAME,
                                () => this.syncWidgetWithPreference());
+  },
 
+  onAreaNodeRegistered(aArea) {
     // The placement of the widget always takes priority, and the preference
-    // should always match the actual placement when the browser starts up.
-    this.syncPreferenceWithWidget();
+    // should always match the actual placement when the browser starts up - i.e.
+    // once the navigation bar has been registered.
+    if (aArea == CustomizableUI.AREA_NAVBAR) {
+      this.syncPreferenceWithWidget();
+    }
   },
 
   onCustomizeEnd() {
     // onWidgetUndoMove does not fire when the search container is moved back to
     // the customization palette as a result of an undo, so we sync again here.
     this.syncPreferenceWithWidget();
   },
 
--- a/browser/components/extensions/ext-c-devtools-panels.js
+++ b/browser/components/extensions/ext-c-devtools-panels.js
@@ -217,16 +217,25 @@ class ChildDevToolsInspectorSidebar exte
       setObject(jsonObject, rootTitle) {
         return context.cloneScope.Promise.resolve().then(() => {
           return context.childManager.callParentAsyncFunction(
             "devtools.panels.elements.Sidebar.setObject",
             [id, jsonObject, rootTitle]
           );
         });
       },
+
+      setExpression(evalExpression, rootTitle) {
+        return context.cloneScope.Promise.resolve().then(() => {
+          return context.childManager.callParentAsyncFunction(
+            "devtools.panels.elements.Sidebar.setExpression",
+            [id, evalExpression, rootTitle]
+          );
+        });
+      },
     };
   }
 }
 
 this.devtools_panels = class extends ExtensionAPI {
   getAPI(context) {
     const themeChangeObserver = ExtensionChildDevToolsUtils.getThemeChangeObserver();
 
--- a/browser/components/extensions/ext-devtools-inspectedWindow.js
+++ b/browser/components/extensions/ext-devtools-inspectedWindow.js
@@ -1,81 +1,58 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
-/* global getDevToolsTargetForContext */
+// The ext-* files are imported into the same scopes.
+/* import-globals-from ext-devtools.js */
+/* import-globals-from ext-browser.js */
 
 XPCOMUtils.defineLazyModuleGetter(this, "DevToolsShim",
                                   "chrome://devtools-shim/content/DevToolsShim.jsm");
 
 var {
   SpreadArgs,
 } = ExtensionCommon;
 
 this.devtools_inspectedWindow = class extends ExtensionAPI {
   getAPI(context) {
-    // Lazily retrieve and store an inspectedWindow actor front per child context.
+    // Lazily retrieved inspectedWindow actor front per child context.
     let waitForInspectedWindowFront;
-    async function getInspectedWindowFront() {
-      // If there is not yet a front instance, then a lazily cloned target for the context is
-      // retrieved using the DevtoolsParentContextsManager helper (which is an asynchronous operation,
-      // because the first time that the target has been cloned, it is not ready to be used to create
-      // the front instance until it is connected to the remote debugger successfully).
-      const clonedTarget = await getDevToolsTargetForContext(context);
-      return DevToolsShim.createWebExtensionInspectedWindowFront(clonedTarget);
-    }
-
-    function getToolboxOptions() {
-      const options = {};
-      const toolbox = context.devToolsToolbox;
-      const selectedNode = toolbox.selection;
-
-      if (selectedNode && selectedNode.nodeFront) {
-        // If there is a selected node in the inspector, we hand over
-        // its actor id to the eval request in order to provide the "$0" binding.
-        options.toolboxSelectedNodeActorID = selectedNode.nodeFront.actorID;
-      }
-
-      // Provide the console actor ID to implement the "inspect" binding.
-      options.toolboxConsoleActorID = toolbox.target.form.consoleActor;
-
-      return options;
-    }
 
     // TODO(rpl): retrive a more detailed callerInfo object, like the filename and
     // lineNumber of the actual extension called, in the child process.
     const callerInfo = {
       addonId: context.extension.id,
       url: context.extension.baseURI.spec,
     };
 
     return {
       devtools: {
         inspectedWindow: {
           async eval(expression, options) {
             if (!waitForInspectedWindowFront) {
-              waitForInspectedWindowFront = getInspectedWindowFront();
+              waitForInspectedWindowFront = getInspectedWindowFront(context);
             }
 
             const front = await waitForInspectedWindowFront;
 
-            const evalOptions = Object.assign({}, options, getToolboxOptions());
+            const evalOptions = Object.assign({}, options, getToolboxEvalOptions(context));
 
             const evalResult = await front.eval(callerInfo, expression, evalOptions);
 
             // TODO(rpl): check for additional undocumented behaviors on chrome
             // (e.g. if we should also print error to the console or set lastError?).
             return new SpreadArgs([evalResult.value, evalResult.exceptionInfo]);
           },
           async reload(options) {
             const {ignoreCache, userAgent, injectedScript} = options || {};
 
             if (!waitForInspectedWindowFront) {
-              waitForInspectedWindowFront = getInspectedWindowFront();
+              waitForInspectedWindowFront = getInspectedWindowFront(context);
             }
 
             const front = await waitForInspectedWindowFront;
             front.reload(callerInfo, {ignoreCache, userAgent, injectedScript});
           },
         },
       },
     };
--- a/browser/components/extensions/ext-devtools-panels.js
+++ b/browser/components/extensions/ext-devtools-panels.js
@@ -439,16 +439,27 @@ class ParentDevToolsInspectorSidebar {
     }
   }
 }
 
 const sidebarsById = new Map();
 
 this.devtools_panels = class extends ExtensionAPI {
   getAPI(context) {
+    // Lazily retrieved inspectedWindow actor front per child context
+    // (used by Sidebar.setExpression).
+    let waitForInspectedWindowFront;
+
+    // TODO(rpl): retrive a more detailed callerInfo object, like the filename and
+    // lineNumber of the actual extension called, in the child process.
+    const callerInfo = {
+      addonId: context.extension.id,
+      url: context.extension.baseURI.spec,
+    };
+
     // An incremental "per context" id used in the generated devtools panel id.
     let nextPanelId = 0;
 
     const toolboxSelectionObserver = new DevToolsSelectionObserver(context);
 
     function newBasePanelId() {
       return `${context.extension.id}-${context.contextId}-${nextPanelId++}`;
     }
@@ -487,16 +498,37 @@ this.devtools_panels = class extends Ext
             // The following methods are used internally to allow the sidebar API
             // piece that is running in the child process to asks the parent process
             // to execute the sidebar methods.
             Sidebar: {
               setObject(sidebarId, jsonObject, rootTitle) {
                 const sidebar = sidebarsById.get(sidebarId);
                 return sidebar.setObject(jsonObject, rootTitle);
               },
+              async setExpression(sidebarId, evalExpression, rootTitle) {
+                const sidebar = sidebarsById.get(sidebarId);
+
+                if (!waitForInspectedWindowFront) {
+                  waitForInspectedWindowFront = getInspectedWindowFront(context);
+                }
+
+                const front = await waitForInspectedWindowFront;
+                const evalOptions = Object.assign({}, getToolboxEvalOptions(context));
+                const evalResult = await front.eval(callerInfo, evalExpression, evalOptions);
+
+                let jsonObject;
+
+                if (evalResult.exceptionInfo) {
+                  jsonObject = evalResult.exceptionInfo;
+                } else {
+                  jsonObject = evalResult.value;
+                }
+
+                return sidebar.setObject(jsonObject, rootTitle);
+              },
             },
           },
           create(title, icon, url) {
             // Get a fallback icon from the manifest data.
             if (icon === "" && context.extension.manifest.icons) {
               const iconInfo = IconDetails.getPreferredIcon(context.extension.manifest.icons,
                                                             context.extension, 128);
               icon = iconInfo ? iconInfo.icon : "";
--- a/browser/components/extensions/ext-devtools.js
+++ b/browser/components/extensions/ext-devtools.js
@@ -1,14 +1,14 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
-/* exported getDevToolsTargetForContext */
-/* global getTargetTabIdForToolbox, getDevToolsTargetForContext */
+/* exported getDevToolsTargetForContext, getInspectedWindowFront, getToolboxEvalOptions */
+/* global getTargetTabIdForToolbox, getDevToolsTargetForContext, getInspectedWindowFront, getToolboxEvalOptions */
 
 // The ext-* files are imported into the same scopes.
 /* import-globals-from ext-browser.js */
 
 /**
  * This module provides helpers used by the other specialized `ext-devtools-*.js` modules
  * and the implementation of the `devtools_page`.
  */
@@ -80,16 +80,46 @@ global.getTargetTabIdForToolbox = (toolb
   }
 
   let parentWindow = target.tab.linkedBrowser.ownerGlobal;
   let tab = parentWindow.gBrowser.getTabForBrowser(target.tab.linkedBrowser);
 
   return tabTracker.getId(tab);
 };
 
+// Create an InspectedWindowFront instance for a given context (used in devtoools.inspectedWindow.eval
+// and in sidebar.setExpression API methods).
+global.getInspectedWindowFront = async function(context) {
+  // If there is not yet a front instance, then a lazily cloned target for the context is
+  // retrieved using the DevtoolsParentContextsManager helper (which is an asynchronous operation,
+  // because the first time that the target has been cloned, it is not ready to be used to create
+  // the front instance until it is connected to the remote debugger successfully).
+  const clonedTarget = await getDevToolsTargetForContext(context);
+  return DevToolsShim.createWebExtensionInspectedWindowFront(clonedTarget);
+};
+
+// Get the WebExtensionInspectedWindowActor eval options (needed to provide the $0 and inspect
+// binding provided to the evaluated js code).
+global.getToolboxEvalOptions = function(context) {
+  const options = {};
+  const toolbox = context.devToolsToolbox;
+  const selectedNode = toolbox.selection;
+
+  if (selectedNode && selectedNode.nodeFront) {
+    // If there is a selected node in the inspector, we hand over
+    // its actor id to the eval request in order to provide the "$0" binding.
+    options.toolboxSelectedNodeActorID = selectedNode.nodeFront.actorID;
+  }
+
+  // Provide the console actor ID to implement the "inspect" binding.
+  options.toolboxConsoleActorID = toolbox.target.form.consoleActor;
+
+  return options;
+};
+
 /**
  * The DevToolsPage represents the "devtools_page" related to a particular
  * Toolbox and WebExtension.
  *
  * The devtools_page contexts are invisible WebExtensions contexts, similar to the
  * background page, associated to a single developer toolbox (e.g. If an add-on
  * registers a devtools_page and the user opens 3 developer toolbox in 3 webpages,
  * 3 devtools_page contexts will be created for that add-on).
--- a/browser/components/extensions/schemas/devtools_panels.json
+++ b/browser/components/extensions/schemas/devtools_panels.json
@@ -175,17 +175,16 @@
                 "name": "height",
                 "type": "string",
                 "description": "A CSS-like size specification, such as <code>'100px'</code> or <code>'12ex'</code>."
               }
             ]
           },
           {
             "name": "setExpression",
-            "unsupported": true,
             "async": "callback",
             "type": "function",
             "description": "Sets an expression that is evaluated within the inspected page. The result is displayed in the sidebar pane.",
             "parameters": [
               {
                 "name": "expression",
                 "type": "string",
                 "description": "An expression to be evaluated in context of the inspected page. JavaScript objects and DOM nodes are displayed in an expandable tree similar to the console/watch."
--- a/browser/components/extensions/test/browser/browser_ext_devtools_inspectedWindow_eval_bindings.js
+++ b/browser/components/extensions/test/browser/browser_ext_devtools_inspectedWindow_eval_bindings.js
@@ -133,16 +133,44 @@ add_task(async function test_devtools_in
             resolve(m.node);
             jsterm.hud.off("new-messages", onThisMessage);
             return;
           }
         });
       });
       let objectInspectors = [...messageNode.querySelectorAll(".tree")];
       is(objectInspectors.length, 1, "There is the expected number of object inspectors");
+
+      // We need to wait for the object to be expanded so we don't call the server on a closed connection.
+      const [oi] = objectInspectors;
+      let nodes = oi.querySelectorAll(".node");
+
+      ok(nodes.length >= 1, "The object preview is rendered as expected");
+
+      // The tree can still be collapsed since the properties are fetched asynchronously.
+      if (nodes.length === 1) {
+        info("Waiting for the object properties to be displayed");
+        // If this is the case, we wait for the properties to be fetched and displayed.
+        await new Promise(resolve => {
+          const observer = new MutationObserver(mutations => {
+            resolve();
+            observer.disconnect();
+          });
+          observer.observe(oi, {childList: true});
+        });
+
+        // Retrieve the new nodes.
+        nodes = oi.querySelectorAll(".node");
+      }
+
+      // We should have 3 nodes :
+      //   ▼ Object { testkey: "testvalue" }
+      //   |  testkey: "testvalue"
+      //   |  ▶︎ __proto__: Object { … }
+      is(nodes.length, 3, "The object preview has the expected number of nodes");
     } else {
       const options = await new Promise(resolve => {
         jsterm.once("variablesview-open", (evt, view, options) => resolve(options));
       });
 
       const objectType = options.objectActor.type;
       const objectPreviewProperties = options.objectActor.preview.ownProperties;
       is(objectType, "object", "The inspected object has the expected type");
--- a/browser/components/extensions/test/browser/browser_ext_devtools_panels_elements_sidebar.js
+++ b/browser/components/extensions/test/browser/browser_ext_devtools_panels_elements_sidebar.js
@@ -1,41 +1,52 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
                                   "resource://devtools/client/framework/gDevTools.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "devtools",
                                   "resource://devtools/shared/Loader.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ContentTaskUtils",
+                                  "resource://testing-common/ContentTaskUtils.jsm");
 
 function isActiveSidebarTabTitle(inspector, expectedTabTitle, message) {
   const actualTabTitle = inspector.panelDoc.querySelector(".tabs-menu-item.is-active").innerText;
   is(actualTabTitle, expectedTabTitle, message);
 }
 
 add_task(async function test_devtools_panels_elements_sidebar() {
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "http://mochi.test:8888/");
 
   async function devtools_page() {
     const sidebar1 = await browser.devtools.panels.elements.createSidebarPane("Test Sidebar 1");
     const sidebar2 = await browser.devtools.panels.elements.createSidebarPane("Test Sidebar 2");
+    const sidebar3 = await browser.devtools.panels.elements.createSidebarPane("Test Sidebar 3");
 
     const onShownListener = (event, sidebarInstance) => {
       browser.test.sendMessage(`devtools_sidebar_${event}`, sidebarInstance);
     };
 
     sidebar1.onShown.addListener(() => onShownListener("shown", "sidebar1"));
     sidebar2.onShown.addListener(() => onShownListener("shown", "sidebar2"));
+    sidebar3.onShown.addListener(() => onShownListener("shown", "sidebar3"));
+
     sidebar1.onHidden.addListener(() => onShownListener("hidden", "sidebar1"));
     sidebar2.onHidden.addListener(() => onShownListener("hidden", "sidebar2"));
+    sidebar3.onHidden.addListener(() => onShownListener("hidden", "sidebar3"));
 
     sidebar1.setObject({propertyName: "propertyValue"}, "Optional Root Object Title");
     sidebar2.setObject({anotherPropertyName: 123});
 
+    // Refresh the sidebar content on every inspector selection.
+    browser.devtools.panels.elements.onSelectionChanged.addListener(() => {
+      sidebar3.setExpression("$0 && $0.tagName", "Selected Element tagName");
+    });
+
     browser.test.sendMessage("devtools_page_loaded");
   }
 
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
       devtools_page: "devtools_page.html",
     },
     files: {
@@ -110,25 +121,59 @@ add_task(async function test_devtools_pa
   ok(sidebarPanel2, "Got a rendered sidebar panel for the second registered extension sidebar");
 
   is(sidebarPanel2.querySelectorAll("table.treeTable").length, 1,
      "The second sidebar panel contains a rendered TreeView component");
 
   is(sidebarPanel2.querySelectorAll("table.treeTable .numberCell").length, 1,
      "The TreeView component contains the expected a cell of type number.");
 
+  inspector.sidebar.show(sidebarIds[2]);
+
+  const shownSidebarInstance3 = await extension.awaitMessage("devtools_sidebar_shown");
+  const hiddenSidebarInstance2 = await extension.awaitMessage("devtools_sidebar_hidden");
+
+  is(shownSidebarInstance3, "sidebar3", "Got the shown event on the third extension sidebar");
+  is(hiddenSidebarInstance2, "sidebar2", "Got the hidden event on the second extension sidebar");
+
+  isActiveSidebarTabTitle(inspector, "Test Sidebar 3",
+                          "Got the expected title on the active sidebar tab");
+
+  const sidebarPanel3 = inspector.sidebar.getTabPanel(sidebarIds[2]);
+
+  ok(sidebarPanel3, "Got a rendered sidebar panel for the third registered extension sidebar");
+
+  info("Waiting for the third panel to be rendered");
+  await ContentTaskUtils.waitForCondition(() => {
+    return sidebarPanel3.querySelectorAll("table.treeTable").length > 0;
+  });
+
+  is(sidebarPanel3.querySelectorAll("table.treeTable").length, 1,
+     "The third sidebar panel contains a rendered TreeView component");
+
+  const treeViewStringValues = sidebarPanel3.querySelectorAll("table.treeTable .stringCell");
+
+  is(treeViewStringValues.length, 1,
+     "The TreeView component contains the expected content of type string.");
+
+  is(treeViewStringValues[0].innerText, "\"BODY\"",
+     "Got the expected content in the sidebar.setExpression rendered TreeView");
+
   await extension.unload();
 
   is(Array.from(toolbox._inspectorExtensionSidebars.keys()).length, 0,
      "All the registered sidebars have been unregistered on extension unload");
 
   is(inspector.sidebar.getTabPanel(sidebarIds[0]), undefined,
      "The first registered sidebar has been removed");
 
   is(inspector.sidebar.getTabPanel(sidebarIds[1]), undefined,
      "The second registered sidebar has been removed");
 
+  is(inspector.sidebar.getTabPanel(sidebarIds[2]), undefined,
+     "The third registered sidebar has been removed");
+
   await gDevTools.closeToolbox(target);
 
   await target.destroy();
 
   await BrowserTestUtils.removeTab(tab);
 });
--- a/browser/extensions/formautofill/FormAutofillParent.jsm
+++ b/browser/extensions/formautofill/FormAutofillParent.jsm
@@ -83,27 +83,31 @@ FormAutofillParent.prototype = {
   /**
    * Initializes ProfileStorage and registers the message handler.
    */
   async init() {
     Services.obs.addObserver(this, "sync-pane-loaded");
     Services.ppmm.addMessageListener("FormAutofill:InitStorage", this);
     Services.ppmm.addMessageListener("FormAutofill:GetRecords", this);
     Services.ppmm.addMessageListener("FormAutofill:SaveAddress", this);
-    Services.ppmm.addMessageListener("FormAutofill:SaveCreditCard", this);
     Services.ppmm.addMessageListener("FormAutofill:RemoveAddresses", this);
-    Services.ppmm.addMessageListener("FormAutofill:RemoveCreditCards", this);
     Services.ppmm.addMessageListener("FormAutofill:OpenPreferences", this);
-    Services.ppmm.addMessageListener("FormAutofill:GetDecryptedString", this);
     Services.mm.addMessageListener("FormAutofill:OnFormSubmit", this);
 
     // Observing the pref and storage changes
     Services.prefs.addObserver(ENABLED_AUTOFILL_ADDRESSES_PREF, this);
-    Services.prefs.addObserver(ENABLED_AUTOFILL_CREDITCARDS_PREF, this);
     Services.obs.addObserver(this, "formautofill-storage-changed");
+
+    // Only listen to credit card related messages if it is available
+    if (FormAutofillUtils.isAutofillCreditCardsAvailable) {
+      Services.ppmm.addMessageListener("FormAutofill:SaveCreditCard", this);
+      Services.ppmm.addMessageListener("FormAutofill:RemoveCreditCards", this);
+      Services.ppmm.addMessageListener("FormAutofill:GetDecryptedString", this);
+      Services.prefs.addObserver(ENABLED_AUTOFILL_CREDITCARDS_PREF, this);
+    }
   },
 
   observe(subject, topic, data) {
     log.debug("observe:", topic, "with data:", data);
     switch (topic) {
       case "sync-pane-loaded": {
         let formAutofillPreferences = new FormAutofillPreferences();
         let document = subject.document;
@@ -243,22 +247,26 @@ FormAutofillParent.prototype = {
    * @private
    */
   _uninit() {
     this.profileStorage._saveImmediately();
 
     Services.ppmm.removeMessageListener("FormAutofill:InitStorage", this);
     Services.ppmm.removeMessageListener("FormAutofill:GetRecords", this);
     Services.ppmm.removeMessageListener("FormAutofill:SaveAddress", this);
-    Services.ppmm.removeMessageListener("FormAutofill:SaveCreditCard", this);
     Services.ppmm.removeMessageListener("FormAutofill:RemoveAddresses", this);
-    Services.ppmm.removeMessageListener("FormAutofill:RemoveCreditCards", this);
     Services.obs.removeObserver(this, "sync-pane-loaded");
     Services.prefs.removeObserver(ENABLED_AUTOFILL_ADDRESSES_PREF, this);
-    Services.prefs.removeObserver(ENABLED_AUTOFILL_CREDITCARDS_PREF, this);
+
+    if (FormAutofillUtils.isAutofillCreditCardsAvailable) {
+      Services.ppmm.removeMessageListener("FormAutofill:SaveCreditCard", this);
+      Services.ppmm.removeMessageListener("FormAutofill:RemoveCreditCards", this);
+      Services.ppmm.removeMessageListener("FormAutofill:GetDecryptedString", this);
+      Services.prefs.removeObserver(ENABLED_AUTOFILL_CREDITCARDS_PREF, this);
+    }
   },
 
   /**
    * Get the records from profile store and return results back to content
    * process. It will decrypt the credit card number and append
    * "cc-number-decrypted" to each record if MasterPassword isn't set.
    *
    * @private
--- a/browser/extensions/formautofill/FormAutofillPreferences.jsm
+++ b/browser/extensions/formautofill/FormAutofillPreferences.jsm
@@ -17,17 +17,24 @@ const BUNDLE_URI = "chrome://formautofil
 const MANAGE_ADDRESSES_URL = "chrome://formautofill/content/manageAddresses.xhtml";
 const MANAGE_CREDITCARDS_URL = "chrome://formautofill/content/manageCreditCards.xhtml";
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://formautofill/FormAutofillUtils.jsm");
 
-const {ENABLED_AUTOFILL_ADDRESSES_PREF, ENABLED_AUTOFILL_CREDITCARDS_PREF} = FormAutofillUtils;
+const {
+  ENABLED_AUTOFILL_ADDRESSES_PREF,
+  ENABLED_AUTOFILL_CREDITCARDS_PREF,
+  MANAGE_ADDRESSES_KEYWORDS,
+  EDIT_ADDRESS_KEYWORDS,
+  MANAGE_CREDITCARDS_KEYWORDS,
+  EDIT_CREDITCARD_KEYWORDS,
+} = FormAutofillUtils;
 // Add credit card enabled flag in telemetry environment for recording the number of
 // users who disable/enable the credit card autofill feature.
 
 this.log = null;
 FormAutofillUtils.defineLazyLogGetter(this, this.EXPORTED_SYMBOLS[0]);
 
 function FormAutofillPreferences() {
   this.bundle = Services.strings.createBundle(BUNDLE_URI);
@@ -56,79 +63,103 @@ FormAutofillPreferences.prototype = {
   },
 
   /**
    * Create Form Autofill preference group
    *
    * @param  {XULDocument} document
    */
   createPreferenceGroup(document) {
+    let learnMoreURL = Services.urlFormatter.formatURLPref("app.support.baseURL") + "autofill-card-address";
     let formAutofillGroup = document.createElementNS(XUL_NS, "vbox");
     let addressAutofill = document.createElementNS(XUL_NS, "hbox");
     let addressAutofillCheckboxGroup = document.createElementNS(XUL_NS, "description");
     let addressAutofillCheckbox = document.createElementNS(XUL_NS, "checkbox");
     let addressAutofillLearnMore = document.createElementNS(XUL_NS, "label");
     let savedAddressesBtn = document.createElementNS(XUL_NS, "button");
-    let creditCardAutofill = document.createElementNS(XUL_NS, "hbox");
-    let creditCardAutofillCheckboxGroup = document.createElementNS(XUL_NS, "description");
-    let creditCardAutofillCheckbox = document.createElementNS(XUL_NS, "checkbox");
-    let creditCardAutofillLearnMore = document.createElementNS(XUL_NS, "label");
-    let savedCreditCardsBtn = document.createElementNS(XUL_NS, "button");
+    // Wrappers are used to properly compute the search tooltip positions
+    let savedAddressesBtnWrapper = document.createElementNS(XUL_NS, "hbox");
+    let savedCreditCardsBtnWrapper = document.createElementNS(XUL_NS, "hbox");
 
     savedAddressesBtn.className = "accessory-button";
-    savedCreditCardsBtn.className = "accessory-button";
     addressAutofillLearnMore.className = "learnMore text-link";
-    creditCardAutofillLearnMore.className = "learnMore text-link";
+
+    formAutofillGroup.id = "formAutofillGroup";
+    addressAutofill.id = "addressAutofill";
+    addressAutofillLearnMore.id = "addressAutofillLearnMore";
+
+    addressAutofillLearnMore.setAttribute("value", this.bundle.GetStringFromName("learnMore"));
+    addressAutofillCheckbox.setAttribute("label", this.bundle.GetStringFromName("enableAddressAutofill"));
+    savedAddressesBtn.setAttribute("label", this.bundle.GetStringFromName("savedAddresses"));
+
+    addressAutofillLearnMore.setAttribute("href", learnMoreURL);
+
+    // Add preferences search support
+    savedAddressesBtn.setAttribute("searchkeywords", MANAGE_ADDRESSES_KEYWORDS.concat(EDIT_ADDRESS_KEYWORDS)
+                                                       .map(key => this.bundle.GetStringFromName(key)).join("\n"));
+
+    // Manually set the checked state
+    if (FormAutofillUtils.isAutofillAddressesEnabled) {
+      addressAutofillCheckbox.setAttribute("checked", true);
+    }
+
+    addressAutofillCheckboxGroup.flex = 1;
+
+    formAutofillGroup.appendChild(addressAutofill);
+    addressAutofill.appendChild(addressAutofillCheckboxGroup);
+    addressAutofillCheckboxGroup.appendChild(addressAutofillCheckbox);
+    addressAutofillCheckboxGroup.appendChild(addressAutofillLearnMore);
+    addressAutofill.appendChild(savedAddressesBtnWrapper);
+    savedAddressesBtnWrapper.appendChild(savedAddressesBtn);
 
     this.refs = {
       formAutofillGroup,
       addressAutofillCheckbox,
       savedAddressesBtn,
-      creditCardAutofillCheckbox,
-      savedCreditCardsBtn,
     };
 
-    formAutofillGroup.id = "formAutofillGroup";
-    addressAutofill.id = "addressAutofill";
-    addressAutofillLearnMore.id = "addressAutofillLearnMore";
-    creditCardAutofill.id = "creditCardAutofill";
-    creditCardAutofillLearnMore.id = "creditCardAutofillLearnMore";
+    if (FormAutofillUtils.isAutofillCreditCardsAvailable) {
+      let creditCardAutofill = document.createElementNS(XUL_NS, "hbox");
+      let creditCardAutofillCheckboxGroup = document.createElementNS(XUL_NS, "description");
+      let creditCardAutofillCheckbox = document.createElementNS(XUL_NS, "checkbox");
+      let creditCardAutofillLearnMore = document.createElementNS(XUL_NS, "label");
+      let savedCreditCardsBtn = document.createElementNS(XUL_NS, "button");
+      savedCreditCardsBtn.className = "accessory-button";
+      creditCardAutofillLearnMore.className = "learnMore text-link";
 
-    addressAutofillLearnMore.setAttribute("value", this.bundle.GetStringFromName("learnMore"));
-    addressAutofillCheckbox.setAttribute("label", this.bundle.GetStringFromName("enableAddressAutofill"));
-    savedAddressesBtn.setAttribute("label", this.bundle.GetStringFromName("savedAddresses"));
-    creditCardAutofillLearnMore.setAttribute("value", this.bundle.GetStringFromName("learnMore"));
-    creditCardAutofillCheckbox.setAttribute("label", this.bundle.GetStringFromName("enableCreditCardAutofill"));
-    savedCreditCardsBtn.setAttribute("label", this.bundle.GetStringFromName("savedCreditCards"));
+      creditCardAutofill.id = "creditCardAutofill";
+      creditCardAutofillLearnMore.id = "creditCardAutofillLearnMore";
 
-    let learnMoreURL = Services.urlFormatter.formatURLPref("app.support.baseURL") + "autofill-card-address";
-    addressAutofillLearnMore.setAttribute("href", learnMoreURL);
-    creditCardAutofillLearnMore.setAttribute("href", learnMoreURL);
+      creditCardAutofillLearnMore.setAttribute("value", this.bundle.GetStringFromName("learnMore"));
+      creditCardAutofillCheckbox.setAttribute("label", this.bundle.GetStringFromName("enableCreditCardAutofill"));
+      savedCreditCardsBtn.setAttribute("label", this.bundle.GetStringFromName("savedCreditCards"));
+
+      creditCardAutofillLearnMore.setAttribute("href", learnMoreURL);
 
-    // Manually set the checked state
-    if (FormAutofillUtils.isAutofillAddressesEnabled) {
-      addressAutofillCheckbox.setAttribute("checked", true);
-    }
-    if (FormAutofillUtils.isAutofillCreditCardsEnabled) {
-      creditCardAutofillCheckbox.setAttribute("checked", true);
-    }
+      // Add preferences search support
+      savedCreditCardsBtn.setAttribute("searchkeywords", MANAGE_CREDITCARDS_KEYWORDS.concat(EDIT_CREDITCARD_KEYWORDS)
+                                                           .map(key => this.bundle.GetStringFromName(key)).join("\n"));
 
-    addressAutofillCheckboxGroup.flex = 1;
-    creditCardAutofillCheckboxGroup.flex = 1;
+      // Manually set the checked state
+      if (FormAutofillUtils.isAutofillCreditCardsEnabled) {
+        creditCardAutofillCheckbox.setAttribute("checked", true);
+      }
+
+      creditCardAutofillCheckboxGroup.flex = 1;
 
-    formAutofillGroup.appendChild(addressAutofill);
-    addressAutofill.appendChild(addressAutofillCheckboxGroup);
-    addressAutofillCheckboxGroup.appendChild(addressAutofillCheckbox);
-    addressAutofillCheckboxGroup.appendChild(addressAutofillLearnMore);
-    addressAutofill.appendChild(savedAddressesBtn);
-    formAutofillGroup.appendChild(creditCardAutofill);
-    creditCardAutofill.appendChild(creditCardAutofillCheckboxGroup);
-    creditCardAutofillCheckboxGroup.appendChild(creditCardAutofillCheckbox);
-    creditCardAutofillCheckboxGroup.appendChild(creditCardAutofillLearnMore);
-    creditCardAutofill.appendChild(savedCreditCardsBtn);
+      formAutofillGroup.appendChild(creditCardAutofill);
+      creditCardAutofill.appendChild(creditCardAutofillCheckboxGroup);
+      creditCardAutofillCheckboxGroup.appendChild(creditCardAutofillCheckbox);
+      creditCardAutofillCheckboxGroup.appendChild(creditCardAutofillLearnMore);
+      creditCardAutofill.appendChild(savedCreditCardsBtnWrapper);
+      savedCreditCardsBtnWrapper.appendChild(savedCreditCardsBtn);
+
+      this.refs.creditCardAutofillCheckbox = creditCardAutofillCheckbox;
+      this.refs.savedCreditCardsBtn = savedCreditCardsBtn;
+    }
   },
 
   /**
    * Handle events
    *
    * @param  {DOMEvent} event
    */
   handleEvent(event) {
--- a/browser/extensions/formautofill/FormAutofillUtils.jsm
+++ b/browser/extensions/formautofill/FormAutofillUtils.jsm
@@ -14,29 +14,42 @@ const ADDRESS_REFERENCES = "chrome://for
 //       bug 1370193.
 const ALTERNATIVE_COUNTRY_NAMES = {
   "US": ["US", "United States of America", "United States", "America", "U.S.", "USA", "U.S.A.", "U.S.A"],
 };
 
 const ADDRESSES_COLLECTION_NAME = "addresses";
 const CREDITCARDS_COLLECTION_NAME = "creditCards";
 const ENABLED_AUTOFILL_ADDRESSES_PREF = "extensions.formautofill.addresses.enabled";
+const AUTOFILL_CREDITCARDS_AVAILABLE_PREF = "extensions.formautofill.creditCards.available";
 const ENABLED_AUTOFILL_CREDITCARDS_PREF = "extensions.formautofill.creditCards.enabled";
+const MANAGE_ADDRESSES_KEYWORDS = ["manageAddressesTitle", "addNewAddressTitle"];
+const EDIT_ADDRESS_KEYWORDS = [
+  "givenName", "additionalName", "familyName", "organization", "streetAddress",
+  "state", "province", "city", "country", "zip", "postalCode", "email", "tel",
+];
+const MANAGE_CREDITCARDS_KEYWORDS = ["manageCreditCardsTitle", "addNewCreditCardTitle", "showCreditCards"];
+const EDIT_CREDITCARD_KEYWORDS = ["cardNumber", "nameOnCard", "cardExpires"];
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 this.FormAutofillUtils = {
   get AUTOFILL_FIELDS_THRESHOLD() { return 3; },
   get isAutofillEnabled() { return this.isAutofillAddressesEnabled || this.isAutofillCreditCardsEnabled; },
+  get isAutofillCreditCardsEnabled() { return this.isAutofillCreditCardsAvailable && this._isAutofillCreditCardsEnabled; },
 
   ADDRESSES_COLLECTION_NAME,
   CREDITCARDS_COLLECTION_NAME,
   ENABLED_AUTOFILL_ADDRESSES_PREF,
   ENABLED_AUTOFILL_CREDITCARDS_PREF,
+  MANAGE_ADDRESSES_KEYWORDS,
+  EDIT_ADDRESS_KEYWORDS,
+  MANAGE_CREDITCARDS_KEYWORDS,
+  EDIT_CREDITCARD_KEYWORDS,
 
   _fieldNameInfo: {
     "name": "name",
     "given-name": "name",
     "additional-name": "name",
     "family-name": "name",
     "organization": "organization",
     "street-address": "address",
@@ -521,9 +534,11 @@ this.FormAutofillUtils.defineLazyLogGett
 
 XPCOMUtils.defineLazyGetter(FormAutofillUtils, "stringBundle", function() {
   return Services.strings.createBundle("chrome://formautofill/locale/formautofill.properties");
 });
 
 XPCOMUtils.defineLazyPreferenceGetter(this.FormAutofillUtils,
                                       "isAutofillAddressesEnabled", ENABLED_AUTOFILL_ADDRESSES_PREF);
 XPCOMUtils.defineLazyPreferenceGetter(this.FormAutofillUtils,
-                                      "isAutofillCreditCardsEnabled", ENABLED_AUTOFILL_CREDITCARDS_PREF);
+                                      "isAutofillCreditCardsAvailable", AUTOFILL_CREDITCARDS_AVAILABLE_PREF);
+XPCOMUtils.defineLazyPreferenceGetter(this.FormAutofillUtils,
+                                      "_isAutofillCreditCardsEnabled", ENABLED_AUTOFILL_CREDITCARDS_PREF);
--- a/browser/extensions/formautofill/content/manageAddresses.xhtml
+++ b/browser/extensions/formautofill/content/manageAddresses.xhtml
@@ -12,17 +12,20 @@
 </head>
 <body>
   <fieldset>
     <legend data-localization="addressesListHeader"/>
     <select id="addresses" size="9" multiple="multiple"/>
   </fieldset>
   <div id="controls-container">
     <button id="remove" disabled="disabled" data-localization="remove"/>
-    <button id="add" data-localization="add"/>
+    <!-- Wrapper is used to properly compute the search tooltip position -->
+    <div>
+      <button id="add" data-localization="add"/>
+    </div>
     <button id="edit" disabled="disabled" data-localization="edit"/>
   </div>
   <script type="application/javascript">
     "use strict";
     /* global ManageAddresses */
     new ManageAddresses({
       records: document.getElementById("addresses"),
       controlsContainer: document.getElementById("controls-container"),
--- a/browser/extensions/formautofill/content/manageCreditCards.xhtml
+++ b/browser/extensions/formautofill/content/manageCreditCards.xhtml
@@ -13,17 +13,20 @@
 <body>
   <fieldset>
     <legend data-localization="creditCardsListHeader"/>
     <select id="credit-cards" size="9" multiple="multiple"/>
   </fieldset>
   <div id="controls-container">
     <button id="remove" disabled="disabled" data-localization="remove"/>
     <button id="show-hide-credit-cards" data-localization="showCreditCards"/>
-    <button id="add" data-localization="add"/>
+    <!-- Wrapper is used to properly compute the search tooltip position -->
+    <div>
+      <button id="add" data-localization="add"/>
+    </div>
     <button id="edit" disabled="disabled" data-localization="edit"/>
   </div>
   <script type="application/javascript">
     "use strict";
     /* global ManageCreditCards */
     new ManageCreditCards({
       records: document.getElementById("credit-cards"),
       controlsContainer: document.getElementById("controls-container"),
--- a/browser/extensions/formautofill/content/manageDialog.js
+++ b/browser/extensions/formautofill/content/manageDialog.js
@@ -266,16 +266,19 @@ class ManageRecords {
     this._elements.controlsContainer.removeEventListener("click", this);
     Services.obs.removeObserver(this, "formautofill-storage-changed");
   }
 }
 
 class ManageAddresses extends ManageRecords {
   constructor(elements) {
     super("addresses", elements);
+    elements.add.setAttribute("searchkeywords", FormAutofillUtils.EDIT_ADDRESS_KEYWORDS
+                                                  .map(key => FormAutofillUtils.stringBundle.GetStringFromName(key))
+                                                  .join("\n"));
   }
 
   /**
    * Open the edit address dialog to create/edit an address.
    *
    * @param  {object} address [optional]
    */
   openEditDialog(address) {
@@ -322,16 +325,19 @@ class ManageAddresses extends ManageReco
     }
     return parts.join(", ");
   }
 }
 
 class ManageCreditCards extends ManageRecords {
   constructor(elements) {
     super("creditCards", elements);
+    elements.add.setAttribute("searchkeywords", FormAutofillUtils.EDIT_CREDITCARD_KEYWORDS
+                                                  .map(key => FormAutofillUtils.stringBundle.GetStringFromName(key))
+                                                  .join("\n"));
     this._hasMasterPassword = MasterPassword.isEnabled;
     this._isDecrypted = false;
     if (this._hasMasterPassword) {
       elements.showHideCreditCards.setAttribute("hidden", true);
     }
   }
 
   /**
--- a/browser/extensions/formautofill/test/browser/browser_privacyPreferences.js
+++ b/browser/extensions/formautofill/test/browser/browser_privacyPreferences.js
@@ -78,8 +78,22 @@ add_task(async function test_autofillDis
         "Form Autofill group should be visible");
       is(content.document.querySelector(selectors.addressAutofillCheckbox).checked, false,
         "Checkbox should be unchecked when Autofill Addresses is disabled");
       is(content.document.querySelector(selectors.creditCardAutofillCheckbox).checked, false,
         "Checkbox should be unchecked when Autofill Credit Cards is disabled");
     });
   });
 });
+
+add_task(async function test_creditCardNotAvailable() {
+  SpecialPowers.pushPrefEnv({set: [[AUTOFILL_CREDITCARDS_AVAILABLE_PREF, false]]});
+  let finalPrefPaneLoaded = TestUtils.topicObserved("sync-pane-loaded", () => true);
+  await BrowserTestUtils.withNewTab({gBrowser, url: PAGE_PRIVACY}, async function(browser) {
+    await finalPrefPaneLoaded;
+    await ContentTask.spawn(browser, SELECTORS, (selectors) => {
+      is(content.document.querySelector(selectors.group).hidden, false,
+        "Form Autofill group should be visible");
+      ok(!content.document.querySelector(selectors.creditCardAutofillCheckbox),
+        "Autofill credit cards checkbox should not exist");
+    });
+  });
+});
--- a/browser/extensions/formautofill/test/browser/head.js
+++ b/browser/extensions/formautofill/test/browser/head.js
@@ -1,28 +1,30 @@
 /* exported MANAGE_ADDRESSES_DIALOG_URL, MANAGE_CREDIT_CARDS_DIALOG_URL, EDIT_ADDRESS_DIALOG_URL, EDIT_CREDIT_CARD_DIALOG_URL,
             BASE_URL, TEST_ADDRESS_1, TEST_ADDRESS_2, TEST_ADDRESS_3, TEST_ADDRESS_4, TEST_ADDRESS_5,
             TEST_CREDIT_CARD_1, TEST_CREDIT_CARD_2, TEST_CREDIT_CARD_3, FORM_URL, CREDITCARD_FORM_URL,
-            FTU_PREF, ENABLED_AUTOFILL_ADDRESSES_PREF, ENABLED_AUTOFILL_CREDITCARDS_PREF, SYNC_USERNAME_PREF, SYNC_ADDRESSES_PREF,
+            FTU_PREF, ENABLED_AUTOFILL_ADDRESSES_PREF, AUTOFILL_CREDITCARDS_AVAILABLE_PREF, ENABLED_AUTOFILL_CREDITCARDS_PREF,
+            SYNC_USERNAME_PREF, SYNC_ADDRESSES_PREF,
             sleep, expectPopupOpen, openPopupOn, expectPopupClose, closePopup, clickDoorhangerButton,
             getAddresses, saveAddress, removeAddresses, saveCreditCard,
             getDisplayedPopupItems, getDoorhangerCheckbox, waitForMasterPasswordDialog */
 
 "use strict";
 
 const MANAGE_ADDRESSES_DIALOG_URL = "chrome://formautofill/content/manageAddresses.xhtml";
 const MANAGE_CREDIT_CARDS_DIALOG_URL = "chrome://formautofill/content/manageCreditCards.xhtml";
 const EDIT_ADDRESS_DIALOG_URL = "chrome://formautofill/content/editAddress.xhtml";
 const EDIT_CREDIT_CARD_DIALOG_URL = "chrome://formautofill/content/editCreditCard.xhtml";
 const BASE_URL = "http://mochi.test:8888/browser/browser/extensions/formautofill/test/browser/";
 const FORM_URL = "http://mochi.test:8888/browser/browser/extensions/formautofill/test/browser/autocomplete_basic.html";
 const CREDITCARD_FORM_URL =
   "http://mochi.test:8888/browser/browser/extensions/formautofill/test/browser/autocomplete_creditcard_basic.html";
 const FTU_PREF = "extensions.formautofill.firstTimeUse";
 const ENABLED_AUTOFILL_ADDRESSES_PREF = "extensions.formautofill.addresses.enabled";
+const AUTOFILL_CREDITCARDS_AVAILABLE_PREF = "extensions.formautofill.creditCards.available";
 const ENABLED_AUTOFILL_CREDITCARDS_PREF = "extensions.formautofill.creditCards.enabled";
 const SYNC_USERNAME_PREF = "services.sync.username";
 const SYNC_ADDRESSES_PREF = "services.sync.engine.addresses";
 
 const TEST_ADDRESS_1 = {
   "given-name": "John",
   "additional-name": "R.",
   "family-name": "Smith",
--- a/browser/extensions/onboarding/content/onboarding.css
+++ b/browser/extensions/onboarding/content/onboarding.css
@@ -20,17 +20,17 @@
 }
 
 #onboarding-overlay.onboarding-opened {
   display: block;
 }
 
 #onboarding-overlay-button {
   padding: 10px 0 0 0;
-  position: absolute;
+  position: fixed;
   cursor: pointer;
   top: 4px;
   offset-inline-start: 12px;
   border: none;
   /* Set to none so no grey contrast background in the high-contrast mode */
   background: none;
   /* make sure the icon stay above the activity-stream searchbar */
   /* We want this always under #onboarding-overlay */
@@ -90,17 +90,17 @@
   box-shadow: -2px 0 5px 0 rgba(74, 74, 79, 0.25);
 }
 
 #onboarding-overlay-button:dir(rtl)::after {
   box-shadow: 2px 0 5px 0 rgba(74, 74, 79, 0.25);
 }
 
 #onboarding-overlay-button-watermark-icon,
-#onboarding-overlay-button.onboarding-watermark:not(:hover)::after,
+#onboarding-overlay-button.onboarding-watermark::after,
 #onboarding-overlay-button.onboarding-watermark:not(:hover) > #onboarding-overlay-button-icon {
   display: none;
 }
 
 #onboarding-overlay-button.onboarding-watermark:not(:hover) > #onboarding-overlay-button-watermark-icon {
   display: block;
 }
 
--- a/browser/extensions/onboarding/content/onboarding.js
+++ b/browser/extensions/onboarding/content/onboarding.js
@@ -231,17 +231,17 @@ var onboardingTourset = {
         button: bundle.GetStringFromName("onboarding.button.learnMore"),
       };
     },
     getPage(win) {
       let div = win.document.createElement("div");
       div.innerHTML = `
         <section class="onboarding-tour-description">
           <h1 data-l10n-id="onboarding.tour-library.title"></h1>
-          <p data-l10n-id="onboarding.tour-library.description"></p>
+          <p data-l10n-id="onboarding.tour-library.description2"></p>
         </section>
         <section class="onboarding-tour-content">
           <img src="resource://onboarding/img/figure_library.svg" role="presentation"/>
         </section>
         <aside class="onboarding-tour-button-container">
           <button id="onboarding-tour-library-button" class="onboarding-tour-action-button" data-l10n-id="onboarding.tour-library.button2"></button>
         </aside>
       `;
--- a/browser/extensions/onboarding/locales/en-US/onboarding.properties
+++ b/browser/extensions/onboarding/locales/en-US/onboarding.properties
@@ -89,18 +89,18 @@ onboarding.tour-sync.form.title=Create a
 onboarding.tour-sync.form.description=to continue to Firefox Sync
 onboarding.tour-sync.button=Next
 onboarding.tour-sync.email-input.placeholder=Email
 onboarding.notification.onboarding-tour-sync.title=Pick up where you left off.
 onboarding.notification.onboarding-tour-sync.message=Still sending yourself links to save or read on your phone? Do it the easy way: get Sync and have the things you save here show up on all of your devices.
 
 onboarding.tour-library=Library
 onboarding.tour-library.title=Keep it together.
-# LOCALIZATION NOTE (onboarding.tour-library.description): This string will be used in the library tour description. %1$S is brandShortName
-onboarding.tour-library.description=Check out the new %1$S library in the redesigned toolbar. The library puts the things you’ve seen and saved to %1$S - your browsing history, bookmarks, Pocket lists, and synced tabs - in one convenient place.
+# LOCALIZATION NOTE (onboarding.tour-library.description2): This string will be used in the library tour description. %1$S is brandShortName
+onboarding.tour-library.description2=Check out the new %1$S library in the redesigned toolbar. The library puts the things you’ve seen and saved to %1$S — your browsing history, bookmarks, Pocket list, and synced tabs — in one convenient place.
 onboarding.tour-library.button2=Show Library Menu
 onboarding.notification.onboarding-tour-library.title=Keep it together.
 # LOCALIZATION NOTE(onboarding.notification.onboarding-tour-library.message): This string will be used in the notification message for the library tour. %S is brandShortName
 onboarding.notification.onboarding-tour-library.message=The new %S library puts the great things you’ve discovered on the web in one convenient place.
 
 onboarding.tour-singlesearch=Address Bar
 onboarding.tour-singlesearch.title=Find it faster.
 # LOCALIZATION NOTE(onboarding.tour-singlesearch.description): %S is brandShortName
--- a/browser/modules/E10SUtils.jsm
+++ b/browser/modules/E10SUtils.jsm
@@ -6,18 +6,16 @@
 
 this.EXPORTED_SYMBOLS = ["E10SUtils"];
 
 const {interfaces: Ci, utils: Cu, classes: Cc} = Components;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
-XPCOMUtils.defineLazyPreferenceGetter(this, "useRemoteWebExtensions",
-                                      "extensions.webextensions.remote", false);
 XPCOMUtils.defineLazyPreferenceGetter(this, "useSeparateFileUriProcess",
                                       "browser.tabs.remote.separateFileUriProcess", false);
 XPCOMUtils.defineLazyPreferenceGetter(this, "allowLinkedWebInFileUriProcess",
                                       "browser.tabs.remote.allowLinkedWebInFileUriProcess", false);
 XPCOMUtils.defineLazyModuleGetter(this, "Utils",
                                   "resource://gre/modules/sessionstore/Utils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "console",
                                   "resource://gre/modules/Console.jsm");
@@ -180,17 +178,17 @@ this.E10SUtils = {
         if (chromeReg.canLoadURLRemotely(aURI) &&
             aPreferredRemoteType != NOT_REMOTE) {
           return DEFAULT_REMOTE_TYPE;
         }
 
         return NOT_REMOTE;
 
       case "moz-extension":
-        return useRemoteWebExtensions ? EXTENSION_REMOTE_TYPE : NOT_REMOTE;
+        return WebExtensionPolicy.useRemoteWebExtensions ? EXTENSION_REMOTE_TYPE : NOT_REMOTE;
 
       default:
         // For any other nested URIs, we use the innerURI to determine the
         // remote type. In theory we should use the innermost URI, but some URIs
         // have fake inner URIs (e.g. about URIs with inner moz-safe-about) and
         // if such URIs are wrapped in other nested schemes like view-source:,
         // we don't want to "skip" past "about:" by going straight to the
         // innermost URI. Any URIs like this will need to be handled in the
--- a/browser/modules/test/browser/browser_PageActions.js
+++ b/browser/modules/test/browser/browser_PageActions.js
@@ -21,17 +21,17 @@ add_task(async function init() {
   });
 });
 
 
 // Tests a simple non-built-in action without an iframe or subview.  Also
 // thoroughly checks most of the action's properties, methods, and DOM nodes, so
 // it's not necessary to do that in general in other test tasks.
 add_task(async function simple() {
-  let iconURL = "chrome://browser/skin/email-link.svg";
+  let iconURL = "chrome://browser/skin/mail.svg";
   let id = "test-simple";
   let nodeAttributes = {
     "test-attr": "test attr value",
   };
   let title = "Test simple";
   let tooltip = "Test simple tooltip";
 
   let onCommandCallCount = 0;
@@ -289,17 +289,17 @@ add_task(async function withSubview() {
       if (node.localName == "panel") {
         node.hidePopup();
         break;
       }
     }
   };
 
   let action = PageActions.addAction(new PageActions.Action({
-    iconURL: "chrome://browser/skin/email-link.svg",
+    iconURL: "chrome://browser/skin/mail.svg",
     id,
     shownInUrlbar: true,
     subview,
     title: "Test subview",
     onCommand(event, buttonNode) {
       onActionCommandCallCount++;
     },
     onPlacedInPanel(buttonNode) {
@@ -432,17 +432,17 @@ add_task(async function withIframe() {
   let onPlacedInPanelCallCount = 0;
   let onPlacedInUrlbarCallCount = 0;
   let onIframeShownCount = 0;
 
   let panelButtonID = BrowserPageActions._panelButtonNodeIDForActionID(id);
   let urlbarButtonID = BrowserPageActions._urlbarButtonNodeIDForActionID(id);
 
   let action = PageActions.addAction(new PageActions.Action({
-    iconURL: "chrome://browser/skin/email-link.svg",
+    iconURL: "chrome://browser/skin/mail.svg",
     id,
     shownInUrlbar: true,
     title: "Test iframe",
     wantsIframe: true,
     onCommand(event, buttonNode) {
       onCommandCallCount++;
     },
     onIframeShown(iframeNode, panelNode) {
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -17,16 +17,17 @@
   --toolbar-non-lwt-bgcolor: -moz-dialog;
   --toolbar-non-lwt-textcolor: -moz-dialogtext;
   --toolbar-non-lwt-bgimage: linear-gradient(rgba(255,255,255,.15), rgba(255,255,255,.15));
   --toolbar-bgcolor: var(--toolbar-non-lwt-bgcolor);
   --toolbar-bgimage: var(--toolbar-non-lwt-bgimage);
 
   --toolbarbutton-border-radius: 4px;
   --toolbarbutton-vertical-text-padding: calc(var(--toolbarbutton-inner-padding) - 1px);
+  --toolbarbutton-icon-fill-opacity: .85;
 
   --panel-separator-color: ThreeDShadow;
   --arrowpanel-dimmed: hsla(0,0%,80%,.3);
   --arrowpanel-dimmed-further: hsla(0,0%,80%,.45);
   --arrowpanel-dimmed-even-further: hsla(0,0%,80%,.8);
 
   --urlbar-separator-color: ThreeDShadow;
 
@@ -52,16 +53,17 @@
   -moz-appearance: none;
   background-color: transparent;
   border-top: none;
 }
 
 #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar) {
   background-color: var(--toolbar-bgcolor);
   background-image: var(--toolbar-bgimage);
+  color: var(--toolbar-color, inherit);
   -moz-appearance: none;
   border-style: none;
 }
 
 #TabsToolbar:not([collapsed="true"]) + #nav-bar {
   border-top: 1px solid var(--tabs-border) !important;
   background-clip: padding-box;
   /* Position the toolbar above the bottom of background tabs */
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -18,16 +18,17 @@
   --toolbar-non-lwt-bgcolor: #f9f9fa;
   --toolbar-non-lwt-textcolor: #0c0c0d;
   --toolbar-non-lwt-bgimage: none;
   --toolbar-bgcolor: var(--toolbar-non-lwt-bgcolor);
   --toolbar-bgimage: var(--toolbar-non-lwt-bgimage);
 
   --toolbarbutton-vertical-text-padding: calc(var(--toolbarbutton-inner-padding) + 1px);
   --toolbarbutton-border-radius: 4px;
+  --toolbarbutton-icon-fill-opacity: .7;
 
   --panel-separator-color: hsla(210,4%,10%,.14);
   --arrowpanel-dimmed: hsla(210,4%,10%,.07);
   --arrowpanel-dimmed-further: hsla(210,4%,10%,.12);
   --arrowpanel-dimmed-even-further: hsla(210,4%,10%,.17);
 
   --urlbar-separator-color: hsla(0,0%,16%,.2);
 
@@ -120,16 +121,17 @@
 
 #main-window[chromehidden~="toolbar"][chromehidden~="location"][chromehidden~="directories"] {
   border-top: 1px solid rgba(0,0,0,0.65);
 }
 
 #navigator-toolbox > toolbar:not(#TabsToolbar) {
   -moz-appearance: none;
   background: var(--toolbar-bgcolor);
+  color: var(--toolbar-color, inherit);
 }
 
 /* Draw the bottom border of the tabs toolbar when it's not using
    -moz-appearance: toolbar. */
 #main-window:-moz-any([sizemode="fullscreen"],[customize-entered]) #TabsToolbar:not([collapsed="true"]) + #nav-bar,
 #main-window:not([tabsintitlebar]) #TabsToolbar:not([collapsed="true"]) + #nav-bar,
 #TabsToolbar:not([collapsed="true"]) + #nav-bar:-moz-lwtheme {
   border-top: 1px solid var(--tabs-border);
--- a/browser/themes/shared/compacttheme.inc.css
+++ b/browser/themes/shared/compacttheme.inc.css
@@ -8,16 +8,18 @@
 
 :root:-moz-lwtheme {
   --toolbar-bgcolor: var(--chrome-secondary-background-color);
   --toolbar-gbimage: none;
   --toolbar-non-lwt-bgcolor: var(--toolbar-bgcolor);
   --toolbar-non-lwt-textcolor: var(--chrome-color);
   --toolbar-non-lwt-bgimage: none;
 
+  --toolbarbutton-icon-fill-opacity: .7;
+
   --tab-line-color: highlight;
 }
 
 :root:-moz-lwtheme-brighttext {
   /* Chrome */
   --chrome-background-color: hsl(240, 5%, 5%);
   --chrome-color: rgb(249, 249, 250);
   --chrome-secondary-background-color: hsl(240, 1%, 20%);
@@ -48,17 +50,17 @@
   --chrome-nav-bar-controls-border-color: #ccc;
   --chrome-selection-color: #f5f7fa;
   --chrome-selection-background-color: #4c9ed9;
 }
 
 .toolbarbutton-animatable-box[brighttext],
 toolbar[brighttext] .toolbarbutton-animatable-box,
 toolbar[brighttext] .toolbarbutton-1 {
-  fill: rgba(249, 249, 250, .7);
+  fill: rgb(249, 249, 250);
 }
 
 #urlbar ::-moz-selection,
 #navigator-toolbox .searchbar-textbox ::-moz-selection,
 .browserContainer > findbar ::-moz-selection {
   background-color: var(--chrome-selection-background-color);
   color: var(--chrome-selection-color);
 }
--- a/browser/themes/shared/customizableui/panelUI.inc.css
+++ b/browser/themes/shared/customizableui/panelUI.inc.css
@@ -87,24 +87,24 @@
   /* These values are adjusted for the padding and height of the panel. */
   from { margin-top: -.5em; } to { margin-top: calc(64px - .5em); }
 }
 
 @keyframes whimsyRotate {
   to { transform: perspective(5000px) rotateY(360deg); }
 }
 
-#PanelUI-button {
+:root:not([uidensity=compact]) #PanelUI-button {
   margin-inline-start: 3px;
   border-inline-start: 1px solid;
   border-image: linear-gradient(transparent 4px, rgba(0,0,0,.1) 4px, rgba(0,0,0,.1) calc(100% - 4px), transparent calc(100% - 4px));
   border-image-slice: 1;
 }
 
-#nav-bar[brighttext] > #PanelUI-button {
+:root:not([uidensity=compact]) #nav-bar[brighttext] > #PanelUI-button {
   border-image-source: linear-gradient(transparent 4px, rgba(100%,100%,100%,.2) 4px, rgba(100%,100%,100%,.2) calc(100% - 4px), transparent calc(100% - 4px));
 }
 
 #PanelUI-menu-button[badge-status] > .toolbarbutton-badge-stack > .toolbarbutton-badge {
   display: -moz-box;
   height: 10px;
   width: 10px;
   background-size: contain;
--- a/browser/themes/shared/downloads/download-icons.svg
+++ b/browser/themes/shared/downloads/download-icons.svg
@@ -8,17 +8,17 @@
       display: none;
     }
   </style>
   <defs>
     <path id="arrow-icon" d="M7.293 12.725a1 1 0 0 0 1.414 0l5-5a1 1 0 0 0-1.414-1.413L9 9.605V1.019a1 1 0 0 0-2 0v8.586L3.707 6.312a1 1 0 0 0-1.414 1.413l5 5z"/>
     <path id="short-bar-icon" d="m 13,14 a 1,1 0 1 1 0,2 h -10 a 1,1 0 1 1 0,-2 z"/>
     <path id="long-bar-icon" d="m 14,14 a 1,1 0 1 1 0,2 h -12 a 1,1 0 1 1 0,-2"/>
   </defs>
-  <use id="arrow" fill="context-fill" href="#arrow-icon"/>
-  <g id="arrow-with-bar" fill="context-fill">
+  <use id="arrow" fill="context-fill" fill-opacity="context-fill-opacity" href="#arrow-icon"/>
+  <g id="arrow-with-bar" fill="context-fill" fill-opacity="context-fill-opacity">
     <use href="#arrow-icon"/>
     <use href="#short-bar-icon"/>
   </g>
-  <use id="default-bar" fill="context-fill" href="#short-bar-icon"/>
+  <use id="default-bar" fill="context-fill" fill-opacity="context-fill-opacity" href="#short-bar-icon"/>
   <use id="progress-bar-bg" fill="context-fill" fill-opacity="0.2" href="#long-bar-icon"/>
-  <use id="progress-bar-fg" fill="context-fill" href="#long-bar-icon"/>
+  <use id="progress-bar-fg" fill="context-fill" fill-opacity="context-fill-opacity" href="#long-bar-icon"/>
 </svg>
--- a/browser/themes/shared/downloads/indicator.inc.css
+++ b/browser/themes/shared/downloads/indicator.inc.css
@@ -8,30 +8,31 @@
   min-width: 16px;
   min-height: 16px;
 }
 
 #downloads-indicator-progress-outer {
   width: 16px;
   height: 16px;
   background-size: 16px;
-  -moz-context-properties: fill;
   background: url("chrome://browser/skin/downloads/download-icons.svg#default-bar") center no-repeat;
 }
 
 #downloads-button[attention="success"] > #downloads-indicator-anchor > #downloads-indicator-icon,
 #downloads-button[attention="success"] > #downloads-indicator-anchor > #downloads-indicator-progress-outer {
+  -moz-context-properties: fill, fill-opacity;
   fill: var(--toolbarbutton-icon-fill-attention);
+  fill-opacity: 1;
 }
 #downloads-button[progress] > #downloads-indicator-anchor > #downloads-indicator-progress-outer {
   background: url("chrome://browser/skin/downloads/download-icons.svg#progress-bar-bg") center no-repeat;
 }
 
 #downloads-indicator-icon {
-  -moz-context-properties: fill;
+  -moz-context-properties: fill, fill-opacity;
   background-image: url("chrome://browser/skin/downloads/download-icons.svg#arrow");
   width: 16px;
   height: 16px;
 }
 
 #downloads-indicator-progress-inner {
   background: url("chrome://browser/skin/downloads/download-icons.svg#progress-bar-fg") left no-repeat;
   margin-right: 16px;
--- a/browser/themes/shared/icons/arrow-left.svg
+++ b/browser/themes/shared/icons/arrow-left.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
-  <path fill="context-fill" d="M6.414 8l4.293-4.293a1 1 0 0 0-1.414-1.414l-5 5a1 1 0 0 0 0 1.414l5 5a1 1 0 0 0 1.414-1.414z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M6.414 8l4.293-4.293a1 1 0 0 0-1.414-1.414l-5 5a1 1 0 0 0 0 1.414l5 5a1 1 0 0 0 1.414-1.414z"/>
 </svg>
--- a/browser/themes/shared/icons/back-12.svg
+++ b/browser/themes/shared/icons/back-12.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
-  <path fill="context-fill" d="M 4.748 6 L 7.966 2.781 C 8.367 2.365 8.169 1.672 7.609 1.532 C 7.358 1.47 7.092 1.54 6.906 1.72 L 3.158 5.47 C 2.865 5.762 2.865 6.237 3.158 6.53 L 6.906 10.279 C 7.321 10.68 8.015 10.481 8.155 9.921 C 8.217 9.67 8.146 9.405 7.966 9.219 Z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M 4.748 6 L 7.966 2.781 C 8.367 2.365 8.169 1.672 7.609 1.532 C 7.358 1.47 7.092 1.54 6.906 1.72 L 3.158 5.47 C 2.865 5.762 2.865 6.237 3.158 6.53 L 6.906 10.279 C 7.321 10.68 8.015 10.481 8.155 9.921 C 8.217 9.67 8.146 9.405 7.966 9.219 Z"/>
 </svg>
--- a/browser/themes/shared/icons/back.svg
+++ b/browser/themes/shared/icons/back.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill-opacity="context-fill-opacity" fill="context-fill" d="M15,7H3.414L7.707,2.707A1,1,0,0,0,6.293,1.293l-6,6a1,1,0,0,0,0,1.414l6,6a1,1,0,0,0,1.414-1.414L3.414,9H15a1,1,0,0,0,0-2Z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M15,7H3.414L7.707,2.707A1,1,0,0,0,6.293,1.293l-6,6a1,1,0,0,0,0,1.414l6,6a1,1,0,0,0,1.414-1.414L3.414,9H15a1,1,0,0,0,0-2Z"/>
 </svg>
--- a/browser/themes/shared/icons/bookmark-animation.svg
+++ b/browser/themes/shared/icons/bookmark-animation.svg
@@ -12,17 +12,17 @@
       </mask>
     </defs>
     <path fill="none" stroke="context-fill" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.584" d="M16.457 9.307l1.71 3.363 0.722 1.422 1.57 0.267 3.653 0.624 -2.66 2.897 -1.03 1.12 0.23 1.506 0.587 3.824 -3.32 -1.762 -1.496 -0.792 -1.49 0.8 -3.225 1.73 0.584 -3.798 0.233 -1.514 -1.043 -1.124 -2.676 -2.882 3.718 -0.624 1.613 -0.272 0.713 -1.472 1.606 -3.31"/>
     <g mask="url(#a)">
       <path fill="#FFF" d="M16.456 9.271l1.716 3.376 0.725 1.427 1.577 0.269 3.666 0.626 -2.67 2.907 -1.033 1.125 0.23 1.512 0.589 3.838 -3.333 -1.768 -1.5 -0.796 -1.496 0.803 -3.238 1.737 0.586 -3.813 0.234 -1.52 -1.047 -1.128 -2.686 -2.892 3.732 -0.627 1.619 -0.273 0.716 -1.477 1.612 -3.324"/>
       <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.59" d="M16.456 9.271l1.716 3.376 0.725 1.427 1.577 0.269 3.666 0.626 -2.67 2.907 -1.033 1.125 0.23 1.512 0.589 3.838 -3.333 -1.768 -1.5 -0.796 -1.496 0.803 -3.238 1.737 0.586 -3.813 0.234 -1.52 -1.047 -1.128 -2.686 -2.892 3.732 -0.627 1.619 -0.273 0.716 -1.477 1.612 -3.324"/>
     </g>
     <g mask="url(#b)" opacity=".08">
-      <path fill="context-fill" d="M16.502 10.083l2.255 4.57 5.044 0.734 -3.65 3.557 0.862 5.023 -4.511 -2.371 -4.512 2.371 0.862 -5.023 -3.65 -3.557 5.044 -0.733 2.256 -4.57z"/>
+      <path fill="context-fill" fill-opacity="context-fill-opacity" d="M16.502 10.083l2.255 4.57 5.044 0.734 -3.65 3.557 0.862 5.023 -4.511 -2.371 -4.512 2.371 0.862 -5.023 -3.65 -3.557 5.044 -0.733 2.256 -4.57z"/>
       <path fill="none" d="M16.502 10.083l2.255 4.57 5.044 0.734 -3.65 3.557 0.862 5.023 -4.511 -2.371 -4.512 2.371 0.862 -5.023 -3.65 -3.557 5.044 -0.733 2.256 -4.57z"/>
     </g>
   </svg>
   <svg x="33">
     <defs>
       <mask id="d" mask-type="alpha">
         <path fill="context-stroke" d="M0 0h320v240h-320z" transform="matrix(.04 0 0 .04 9.957 11.594)"/>
       </mask>
@@ -126,25 +126,25 @@
     <g mask="url(#m)">
       <path fill="#FFF" d="M16.457 9.299l1.71 3.363 0.722 1.422 1.57 0.267 3.653 0.625 -2.66 2.896 -1.03 1.12 0.23 1.506 0.587 3.824 -3.32 -1.762 -1.496 -0.792 -1.49 0.8 -3.225 1.73 0.584 -3.798 0.233 -1.514 -1.043 -1.124 -2.676 -2.882 3.718 -0.624 1.613 -0.272 0.713 -1.472 1.606 -3.31"/>
       <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.584" d="M16.457 9.299l1.71 3.363 0.722 1.422 1.57 0.267 3.653 0.625 -2.66 2.896 -1.03 1.12 0.23 1.506 0.587 3.824 -3.32 -1.762 -1.496 -0.792 -1.49 0.8 -3.225 1.73 0.584 -3.798 0.233 -1.514 -1.043 -1.124 -2.676 -2.882 3.718 -0.624 1.613 -0.272 0.713 -1.472 1.606 -3.31"/>
     </g>
     <g mask="url(#n)">
       <path fill="context-stroke" d="M16.502 10.108l2.247 4.553 5.025 0.73 -3.636 3.545 0.858 5.004 -4.494 -2.363 -4.494 2.363 0.858 -5.004 -3.636 -3.545 5.025 -0.73 2.247 -4.553z"/>
       <path fill="none" d="M16.502 10.108l2.247 4.553 5.025 0.73 -3.636 3.545 0.858 5.004 -4.494 -2.363 -4.494 2.363 0.858 -5.004 -3.636 -3.545 5.025 -0.73 2.247 -4.553z"/>
     </g>
-    <path fill="context-fill" d="M4.273 14.274l-0.235 -0.115"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M4.273 14.274l-0.235 -0.115"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M4.273 14.274l-0.235 -0.115"/>
-    <path fill="context-fill" d="M28.738 14.306l0.234 -0.115"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M28.738 14.306l0.234 -0.115"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M28.738 14.306l0.234 -0.115"/>
-    <path fill="context-fill" d="M24.168 28.806l0.168 0.2"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M24.168 28.806l0.168 0.2"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M24.168 28.806l0.168 0.2"/>
-    <path fill="context-fill" d="M8.816 28.826l-0.168 0.2"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M8.816 28.826l-0.168 0.2"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M8.816 28.826l-0.168 0.2"/>
-    <path fill="context-fill" d="M16.559 4.97v-0.26"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M16.559 4.97v-0.26"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M16.559 4.97v-0.26"/>
   </svg>
   <svg x="231">
     <defs>
       <mask id="p" mask-type="alpha">
         <path fill="context-stroke" d="M0 0h320v240h-320z" transform="matrix(.2 0 0 .2 -15.623 -12.404)"/>
       </mask>
       <mask id="o" mask-type="alpha">
@@ -154,25 +154,25 @@
     <g mask="url(#o)">
       <path fill="#FFF" d="M16.448 9.017l1.774 3.492 0.75 1.475 1.63 0.278 3.792 0.648 -2.76 3.007 -1.07 1.163 0.24 1.563 0.608 3.97 -3.447 -1.83 -1.552 -0.822 -1.546 0.83 -3.35 1.797 0.607 -3.943 0.241 -1.572 -1.082 -1.167 -2.777 -2.99 3.859 -0.65 1.674 -0.281 0.74 -1.528 1.667 -3.437"/>
       <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.644" d="M16.448 9.017l1.774 3.492 0.75 1.475 1.63 0.278 3.792 0.648 -2.76 3.007 -1.07 1.163 0.24 1.563 0.608 3.97 -3.447 -1.83 -1.552 -0.822 -1.546 0.83 -3.35 1.797 0.607 -3.943 0.241 -1.572 -1.082 -1.167 -2.777 -2.99 3.859 -0.65 1.674 -0.281 0.74 -1.528 1.667 -3.437"/>
     </g>
     <g mask="url(#p)">
       <path fill="context-stroke" d="M16.495 9.857l2.332 4.727 5.217 0.758 -3.775 3.68 0.891 5.194 -4.665 -2.453 -4.666 2.453 0.891 -5.195 -3.774 -3.68 5.216 -0.757 2.333 -4.727z"/>
       <path fill="none" d="M16.495 9.857l2.332 4.727 5.217 0.758 -3.775 3.68 0.891 5.194 -4.665 -2.453 -4.666 2.453 0.891 -5.195 -3.774 -3.68 5.216 -0.757 2.333 -4.727z"/>
     </g>
-    <path fill="context-fill" d="M4.273 14.274l-0.772 -0.377"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M4.273 14.274l-0.772 -0.377"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M4.273 14.274l-0.772 -0.377"/>
-    <path fill="context-fill" d="M28.738 14.306s0.33 -0.16 0.772 -0.377"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M28.738 14.306s0.33 -0.16 0.772 -0.377"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M28.738 14.306s0.33 -0.16 0.772 -0.377"/>
-    <path fill="context-fill" d="M24.168 28.806l0.552 0.658"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M24.168 28.806l0.552 0.658"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M24.168 28.806l0.552 0.658"/>
-    <path fill="context-fill" d="M8.816 28.826l-0.552 0.657"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M8.816 28.826l-0.552 0.657"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M8.816 28.826l-0.552 0.657"/>
-    <path fill="context-fill" d="M16.559 4.97v-0.859"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M16.559 4.97v-0.859"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M16.559 4.97v-0.859"/>
   </svg>
   <svg x="264">
     <defs>
       <mask id="r" mask-type="alpha">
         <path fill="context-stroke" d="M0 0h320v240h-320z" transform="matrix(.2 0 0 .2 -15.623 -12.404)"/>
       </mask>
       <mask id="q" mask-type="alpha">
@@ -182,25 +182,25 @@
     <g mask="url(#q)">
       <path fill="#FFF" d="M16.437 8.692l1.85 3.64 0.781 1.538 1.7 0.29 3.953 0.675 -2.878 3.133 -1.115 1.213 0.25 1.63 0.633 4.137 -3.593 -1.906 -1.617 -0.858 -1.612 0.866 -3.491 1.873 0.632 -4.11 0.252 -1.639 -1.129 -1.216 -2.895 -3.118 4.023 -0.676 1.745 -0.294 0.772 -1.593 1.737 -3.583"/>
       <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.714" d="M16.437 8.692l1.85 3.64 0.781 1.538 1.7 0.29 3.953 0.675 -2.878 3.133 -1.115 1.213 0.25 1.63 0.633 4.137 -3.593 -1.906 -1.617 -0.858 -1.612 0.866 -3.491 1.873 0.632 -4.11 0.252 -1.639 -1.129 -1.216 -2.895 -3.118 4.023 -0.676 1.745 -0.294 0.772 -1.593 1.737 -3.583"/>
     </g>
     <g mask="url(#r)">
       <path fill="context-stroke" d="M16.486 9.568l2.432 4.927 5.437 0.79 -3.935 3.835 0.93 5.415 -4.864 -2.557 -4.863 2.557 0.929 -5.415 -3.935 -3.835 5.437 -0.79 2.432 -4.927z"/>
       <path fill="none" d="M16.486 9.568l2.432 4.927 5.437 0.79 -3.935 3.835 0.93 5.415 -4.864 -2.557 -4.863 2.557 0.929 -5.415 -3.935 -3.835 5.437 -0.79 2.432 -4.927z"/>
     </g>
-    <path fill="context-fill" d="M4.273 14.274l-1.48 -0.722"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M4.273 14.274l-1.48 -0.722"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M4.273 14.274l-1.48 -0.722"/>
-    <path fill="context-fill" d="M28.738 14.306l1.48 -0.722"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M28.738 14.306l1.48 -0.722"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M28.738 14.306l1.48 -0.722"/>
-    <path fill="context-fill" d="M24.168 28.806l1.058 1.26"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M24.168 28.806l1.058 1.26"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M24.168 28.806l1.058 1.26"/>
-    <path fill="context-fill" d="M8.816 28.826l-1.059 1.26"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M8.816 28.826l-1.059 1.26"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M8.816 28.826l-1.059 1.26"/>
-    <path fill="context-fill" d="M16.559 4.97v-1.646"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M16.559 4.97v-1.646"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M16.559 4.97v-1.646"/>
   </svg>
   <svg x="297">
     <defs>
       <mask id="t" mask-type="alpha">
         <path fill="context-stroke" d="M0 0h320v240h-320z" transform="matrix(.2 0 0 .2 -15.623 -12.404)"/>
       </mask>
       <mask id="s" mask-type="alpha">
@@ -210,25 +210,25 @@
     <g mask="url(#s)">
       <path fill="#FFF" d="M16.426 8.351l1.928 3.795 0.815 1.603 1.772 0.302 4.121 0.705 -3 3.267 -1.162 1.264 0.26 1.7 0.66 4.313 -3.746 -1.987 -1.686 -0.895 -1.68 0.903 -3.64 1.952 0.659 -4.285 0.262 -1.708 -1.176 -1.268 -3.018 -3.251 4.194 -0.705 1.819 -0.306 0.805 -1.66 1.811 -3.736"/>
       <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.787" d="M16.426 8.351l1.928 3.795 0.815 1.603 1.772 0.302 4.121 0.705 -3 3.267 -1.162 1.264 0.26 1.7 0.66 4.313 -3.746 -1.987 -1.686 -0.895 -1.68 0.903 -3.64 1.952 0.659 -4.285 0.262 -1.708 -1.176 -1.268 -3.018 -3.251 4.194 -0.705 1.819 -0.306 0.805 -1.66 1.811 -3.736"/>
     </g>
     <g mask="url(#t)">
       <path fill="context-stroke" d="M16.477 9.264l2.535 5.137 5.669 0.824 -4.102 3.998 0.968 5.646 -5.07 -2.666 -5.07 2.666 0.968 -5.646 -4.102 -3.998 5.669 -0.824 2.535 -5.137z"/>
       <path fill="none" d="M16.477 9.264l2.535 5.137 5.669 0.824 -4.102 3.998 0.968 5.646 -5.07 -2.666 -5.07 2.666 0.968 -5.646 -4.102 -3.998 5.669 -0.824 2.535 -5.137z"/>
     </g>
-    <path fill="context-fill" d="M4.273 14.274l-2.281 -1.113"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M4.273 14.274l-2.281 -1.113"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M4.273 14.274l-2.281 -1.113"/>
-    <path fill="context-fill" d="M28.738 14.306l2.28 -1.112"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M28.738 14.306l2.28 -1.112"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M28.738 14.306l2.28 -1.112"/>
-    <path fill="context-fill" d="M24.168 28.806l1.631 1.944"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M24.168 28.806l1.631 1.944"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M24.168 28.806l1.631 1.944"/>
-    <path fill="context-fill" d="M8.816 28.826l-1.631 1.943"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M8.816 28.826l-1.631 1.943"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M8.816 28.826l-1.631 1.943"/>
-    <path fill="context-fill" d="M16.559 4.97v-2.537"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M16.559 4.97v-2.537"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M16.559 4.97v-2.537"/>
   </svg>
   <svg x="330">
     <defs>
       <mask id="v" mask-type="alpha">
         <g clip-path="url(#f10_BkV3WrqkR1)" transform="matrix(.2 0 0 .2 -15.623 -12.404)">
           <path fill="context-stroke" d="M0 0h320v240h-320z"/>
         </g>
@@ -242,25 +242,25 @@
     <g mask="url(#u)">
       <path fill="#FFF" d="M16.415 8.021l2.005 3.945 0.847 1.667 1.842 0.314 4.284 0.732 -3.119 3.397 -1.208 1.314 0.27 1.766 0.687 4.484 -3.894 -2.065 -1.753 -0.93 -1.747 0.938 -3.784 2.03 0.685 -4.455 0.273 -1.776 -1.223 -1.318 -3.138 -3.38 4.36 -0.732 1.891 -0.318 0.837 -1.727 1.883 -3.883"/>
       <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.858" d="M16.415 8.021l2.005 3.945 0.847 1.667 1.842 0.314 4.284 0.732 -3.119 3.397 -1.208 1.314 0.27 1.766 0.687 4.484 -3.894 -2.065 -1.753 -0.93 -1.747 0.938 -3.784 2.03 0.685 -4.455 0.273 -1.776 -1.223 -1.318 -3.138 -3.38 4.36 -0.732 1.891 -0.318 0.837 -1.727 1.883 -3.883"/>
     </g>
     <g mask="url(#v)">
       <path fill="context-stroke" d="M16.468 8.97l2.636 5.34 5.893 0.857 -4.265 4.156 1.007 5.87 -5.27 -2.771 -5.272 2.77 1.007 -5.869 -4.265 -4.156 5.894 -0.857 2.635 -5.34z"/>
       <path fill="none" d="M16.468 8.97l2.636 5.34 5.893 0.857 -4.265 4.156 1.007 5.87 -5.27 -2.771 -5.272 2.77 1.007 -5.869 -4.265 -4.156 5.894 -0.857 2.635 -5.34z"/>
     </g>
-    <path fill="context-fill" d="M4.273 14.274l-3.056 -1.49"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M4.273 14.274l-3.056 -1.49"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M4.273 14.274l-3.056 -1.49"/>
-    <path fill="context-fill" d="M28.738 14.306l3.056 -1.49"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M28.738 14.306l3.056 -1.49"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M28.738 14.306l3.056 -1.49"/>
-    <path fill="context-fill" d="M24.168 28.806l2.186 2.605"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M24.168 28.806l2.186 2.605"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M24.168 28.806l2.186 2.605"/>
-    <path fill="context-fill" d="M8.816 28.826l-2.186 2.604"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M8.816 28.826l-2.186 2.604"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M8.816 28.826l-2.186 2.604"/>
-    <path fill="context-fill" d="M16.559 4.97v-3.4"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M16.559 4.97v-3.4"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M16.559 4.97v-3.4"/>
   </svg>
   <svg x="363">
     <defs>
       <mask id="x" mask-type="alpha">
         <g clip-path="url(#f11_BkV3WrqkR1)" transform="matrix(.2 0 0 .2 -15.623 -12.404)">
           <path fill="context-stroke" d="M0 0h320v240h-320z"/>
         </g>
@@ -274,25 +274,25 @@
     <g mask="url(#w)">
       <path fill="#FFF" d="M16.406 7.738l2.07 4.074 0.875 1.721 1.902 0.324 4.424 0.756 -3.221 3.508 -1.248 1.357 0.28 1.824 0.709 4.63 -4.022 -2.133 -1.81 -0.96 -1.804 0.97 -3.907 2.095 0.707 -4.6 0.282 -1.834 -1.263 -1.361 -3.24 -3.49 4.502 -0.757 1.953 -0.328 0.864 -1.783 1.945 -4.01"/>
       <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.918" d="M16.406 7.738l2.07 4.074 0.875 1.721 1.902 0.324 4.424 0.756 -3.221 3.508 -1.248 1.357 0.28 1.824 0.709 4.63 -4.022 -2.133 -1.81 -0.96 -1.804 0.97 -3.907 2.095 0.707 -4.6 0.282 -1.834 -1.263 -1.361 -3.24 -3.49 4.502 -0.757 1.953 -0.328 0.864 -1.783 1.945 -4.01"/>
     </g>
     <g mask="url(#x)">
       <path fill="context-stroke" d="M16.46 8.718l2.722 5.515 6.086 0.884 -4.404 4.292 1.04 6.061 -5.443 -2.861 -5.444 2.861 1.04 -6.06 -4.404 -4.293 6.086 -0.884 2.722 -5.515z"/>
       <path fill="none" d="M16.46 8.718l2.722 5.515 6.086 0.884 -4.404 4.292 1.04 6.061 -5.443 -2.861 -5.444 2.861 1.04 -6.06 -4.404 -4.293 6.086 -0.884 2.722 -5.515z"/>
     </g>
-    <path fill="context-fill" d="M4.145 14.211l-2.928 -1.428"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M4.145 14.211l-2.928 -1.428"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M4.145 14.211l-2.928 -1.428"/>
-    <path fill="context-fill" d="M28.866 14.243l2.928 -1.428"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M28.866 14.243l2.928 -1.428"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M28.866 14.243l2.928 -1.428"/>
-    <path fill="context-fill" d="M24.26 28.915l2.094 2.496"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M24.26 28.915l2.094 2.496"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M24.26 28.915l2.094 2.496"/>
-    <path fill="context-fill" d="M8.724 28.935l-2.094 2.495"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M8.724 28.935l-2.094 2.495"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M8.724 28.935l-2.094 2.495"/>
-    <path fill="context-fill" d="M16.559 4.828v-3.258"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M16.559 4.828v-3.258"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M16.559 4.828v-3.258"/>
   </svg>
   <svg x="396">
     <defs>
       <mask id="z" mask-type="alpha">
         <g clip-path="url(#f12_BkV3WrqkR1)" transform="matrix(.2 0 0 .2 -15.623 -12.404)">
           <path fill="context-stroke" d="M0 0h320v240h-320z"/>
         </g>
@@ -306,25 +306,25 @@
     <g mask="url(#y)">
       <path fill="#FFF" d="M16.401 7.59l2.104 4.141 0.89 1.75 1.933 0.33 4.497 0.768 -3.274 3.565 -1.269 1.38 0.284 1.854 0.721 4.707 -4.087 -2.169 -1.84 -0.975 -1.834 0.984 -3.972 2.131 0.72 -4.676 0.286 -1.864 -1.284 -1.384 -3.293 -3.547 4.576 -0.77 1.985 -0.333 0.878 -1.812 1.977 -4.077"/>
       <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.95" d="M16.401 7.59l2.104 4.141 0.89 1.75 1.933 0.33 4.497 0.768 -3.274 3.565 -1.269 1.38 0.284 1.854 0.721 4.707 -4.087 -2.169 -1.84 -0.975 -1.834 0.984 -3.972 2.131 0.72 -4.676 0.286 -1.864 -1.284 -1.384 -3.293 -3.547 4.576 -0.77 1.985 -0.333 0.878 -1.812 1.977 -4.077"/>
     </g>
     <g mask="url(#z)">
       <path fill="context-stroke" d="M16.457 8.587l2.766 5.605 6.186 0.899 -4.476 4.363 1.056 6.16 -5.532 -2.908 -5.533 2.909 1.057 -6.161 -4.476 -4.363 6.185 -0.899 2.767 -5.605z"/>
       <path fill="none" d="M16.457 8.587l2.766 5.605 6.186 0.899 -4.476 4.363 1.056 6.16 -5.532 -2.908 -5.533 2.909 1.057 -6.161 -4.476 -4.363 6.185 -0.899 2.767 -5.605z"/>
     </g>
-    <path fill="context-fill" d="M3.835 14.06l-2.618 -1.277"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M3.835 14.06l-2.618 -1.277"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M3.835 14.06l-2.618 -1.277"/>
-    <path fill="context-fill" d="M29.176 14.092l2.618 -1.277"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M29.176 14.092l2.618 -1.277"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M29.176 14.092l2.618 -1.277"/>
-    <path fill="context-fill" d="M24.481 29.18l1.873 2.23"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M24.481 29.18l1.873 2.23"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M24.481 29.18l1.873 2.23"/>
-    <path fill="context-fill" d="M8.502 29.199l-1.872 2.231"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M8.502 29.199l-1.872 2.231"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M8.502 29.199l-1.872 2.231"/>
-    <path fill="context-fill" d="M16.559 4.483v-2.913"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M16.559 4.483v-2.913"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M16.559 4.483v-2.913"/>
   </svg>
   <svg x="429">
     <defs>
       <mask id="B" mask-type="alpha">
         <g clip-path="url(#f13_BkV3WrqkR1)" transform="matrix(.2 0 0 .2 -15.623 -12.404)">
           <path fill="context-stroke" d="M0 0h320v240h-320z"/>
         </g>
@@ -338,25 +338,25 @@
     <g mask="url(#A)">
       <path fill="#FFF" d="M16.406 7.738l2.07 4.074 0.875 1.721 1.902 0.324 4.424 0.756 -3.221 3.508 -1.248 1.357 0.28 1.824 0.709 4.63 -4.022 -2.133 -1.81 -0.96 -1.804 0.97 -3.907 2.096 0.707 -4.6 0.282 -1.835 -1.263 -1.361 -3.24 -3.49 4.502 -0.757 1.953 -0.328 0.864 -1.783 1.945 -4.01"/>
       <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.918" d="M16.406 7.738l2.07 4.074 0.875 1.721 1.902 0.324 4.424 0.756 -3.221 3.508 -1.248 1.357 0.28 1.824 0.709 4.63 -4.022 -2.133 -1.81 -0.96 -1.804 0.97 -3.907 2.096 0.707 -4.6 0.282 -1.835 -1.263 -1.361 -3.24 -3.49 4.502 -0.757 1.953 -0.328 0.864 -1.783 1.945 -4.01"/>
     </g>
     <g mask="url(#B)">
       <path fill="context-stroke" d="M16.46 8.718l2.722 5.515 6.086 0.884 -4.404 4.292 1.04 6.061 -5.444 -2.861 -5.443 2.861 1.04 -6.06 -4.404 -4.293 6.086 -0.884 2.721 -5.515z"/>
       <path fill="none" d="M16.46 8.718l2.722 5.515 6.086 0.884 -4.404 4.292 1.04 6.061 -5.444 -2.861 -5.443 2.861 1.04 -6.06 -4.404 -4.293 6.086 -0.884 2.721 -5.515z"/>
     </g>
-    <path fill="context-fill" d="M3.408 13.852l-2.191 -1.069"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M3.408 13.852l-2.191 -1.069"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M3.408 13.852l-2.191 -1.069"/>
-    <path fill="context-fill" d="M29.602 13.884l2.192 -1.069"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M29.602 13.884l2.192 -1.069"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M29.602 13.884l2.192 -1.069"/>
-    <path fill="context-fill" d="M24.786 29.543l1.568 1.868"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M24.786 29.543l1.568 1.868"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M24.786 29.543l1.568 1.868"/>
-    <path fill="context-fill" d="M8.197 29.563l-1.567 1.867"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M8.197 29.563l-1.567 1.867"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M8.197 29.563l-1.567 1.867"/>
-    <path fill="context-fill" d="M16.559 4.008v-2.438"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M16.559 4.008v-2.438"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M16.559 4.008v-2.438"/>
   </svg>
   <svg x="462">
     <defs>
       <mask id="D" mask-type="alpha">
         <g clip-path="url(#f14_BkV3WrqkR1)" transform="matrix(.2 0 0 .2 -15.623 -12.404)">
           <path fill="context-stroke" d="M0 0h320v240h-320z"/>
         </g>
@@ -370,25 +370,25 @@
     <g mask="url(#C)">
       <path fill="#FFF" d="M16.413 7.97l2.017 3.968 0.852 1.677 1.853 0.316 4.31 0.736 -3.138 3.417 -1.216 1.322 0.272 1.777 0.691 4.51 -3.917 -2.078 -1.763 -0.935 -1.758 0.944 -3.805 2.042 0.688 -4.482 0.275 -1.786 -1.23 -1.326 -3.156 -3.4 4.386 -0.736 1.902 -0.32 0.841 -1.737 1.895 -3.906"/>
       <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.869" d="M16.413 7.97l2.017 3.968 0.852 1.677 1.853 0.316 4.31 0.736 -3.138 3.417 -1.216 1.322 0.272 1.777 0.691 4.51 -3.917 -2.078 -1.763 -0.935 -1.758 0.944 -3.805 2.042 0.688 -4.482 0.275 -1.786 -1.23 -1.326 -3.156 -3.4 4.386 -0.736 1.902 -0.32 0.841 -1.737 1.895 -3.906"/>
     </g>
     <g mask="url(#D)">
       <path fill="context-stroke" d="M16.467 8.925l2.65 5.371 5.928 0.862 -4.289 4.18 1.013 5.905 -5.302 -2.788 -5.302 2.788 1.012 -5.904 -4.289 -4.181 5.928 -0.862 2.65 -5.371z"/>
       <path fill="none" d="M16.467 8.925l2.65 5.371 5.928 0.862 -4.289 4.18 1.013 5.905 -5.302 -2.788 -5.302 2.788 1.012 -5.904 -4.289 -4.181 5.928 -0.862 2.65 -5.371z"/>
     </g>
-    <path fill="context-fill" d="M2.901 13.605l-1.684 -0.822"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M2.901 13.605l-1.684 -0.822"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M2.901 13.605l-1.684 -0.822"/>
-    <path fill="context-fill" d="M30.109 13.637l1.685 -0.822"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M30.109 13.637l1.685 -0.822"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M30.109 13.637l1.685 -0.822"/>
-    <path fill="context-fill" d="M25.149 29.975l1.205 1.436"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M25.149 29.975l1.205 1.436"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M25.149 29.975l1.205 1.436"/>
-    <path fill="context-fill" d="M7.835 29.994l-1.205 1.436"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M7.835 29.994l-1.205 1.436"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M7.835 29.994l-1.205 1.436"/>
-    <path fill="context-fill" d="M16.559 3.445v-1.875"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M16.559 3.445v-1.875"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M16.559 3.445v-1.875"/>
   </svg>
   <svg x="495">
     <defs>
       <mask id="F" mask-type="alpha">
         <g clip-path="url(#f15_BkV3WrqkR1)" transform="matrix(.2 0 0 .2 -15.623 -12.404)">
           <path fill="context-stroke" d="M0 0h320v240h-320z"/>
         </g>
@@ -402,25 +402,25 @@
     <g mask="url(#E)">
       <path fill="#FFF" d="M16.422 8.223l1.958 3.853 0.827 1.628 1.8 0.307 4.184 0.715 -3.047 3.317 -1.18 1.284 0.264 1.725 0.671 4.38 -3.804 -2.018 -1.712 -0.908 -1.706 0.917 -3.696 1.982 0.67 -4.35 0.266 -1.736 -1.195 -1.287 -3.064 -3.3 4.258 -0.716 1.848 -0.311 0.817 -1.686 1.839 -3.793"/>
       <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.814" d="M16.422 8.223l1.958 3.853 0.827 1.628 1.8 0.307 4.184 0.715 -3.047 3.317 -1.18 1.284 0.264 1.725 0.671 4.38 -3.804 -2.018 -1.712 -0.908 -1.706 0.917 -3.696 1.982 0.67 -4.35 0.266 -1.736 -1.195 -1.287 -3.064 -3.3 4.258 -0.716 1.848 -0.311 0.817 -1.686 1.839 -3.793"/>
     </g>
     <g mask="url(#F)">
       <path fill="context-stroke" d="M16.473 9.15l2.575 5.216 5.755 0.836 -4.165 4.06 0.984 5.733 -5.149 -2.707 -5.148 2.707 0.984 -5.733 -4.165 -4.06 5.755 -0.836 2.574 -5.216z"/>
       <path fill="none" d="M16.473 9.15l2.575 5.216 5.755 0.836 -4.165 4.06 0.984 5.733 -5.149 -2.707 -5.148 2.707 0.984 -5.733 -4.165 -4.06 5.755 -0.836 2.574 -5.216z"/>
     </g>
-    <path fill="context-fill" d="M2.342 13.332l-1.125 -0.549"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M2.342 13.332l-1.125 -0.549"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M2.342 13.332l-1.125 -0.549"/>
-    <path fill="context-fill" d="M30.668 13.364l1.126 -0.549"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M30.668 13.364l1.126 -0.549"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M30.668 13.364l1.126 -0.549"/>
-    <path fill="context-fill" d="M25.549 30.451l0.805 0.96"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M25.549 30.451l0.805 0.96"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M25.549 30.451l0.805 0.96"/>
-    <path fill="context-fill" d="M7.435 30.47l-0.805 0.96"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M7.435 30.47l-0.805 0.96"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M7.435 30.47l-0.805 0.96"/>
-    <path fill="context-fill" d="M16.559 2.822v-1.252"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M16.559 2.822v-1.252"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M16.559 2.822v-1.252"/>
   </svg>
   <svg x="528">
     <defs>
       <mask id="H" mask-type="alpha">
         <g clip-path="url(#f16_BkV3WrqkR1)" transform="matrix(.2 0 0 .2 -15.623 -12.404)">
           <path fill="context-stroke" d="M0 0h320v240h-320z"/>
         </g>
@@ -434,25 +434,25 @@
     <g mask="url(#G)">
       <path fill="#FFF" d="M16.43 8.48l1.899 3.736 0.802 1.579 1.745 0.297 4.057 0.693 -2.954 3.217 -1.144 1.245 0.255 1.673 0.651 4.247 -3.688 -1.957 -1.66 -0.88 -1.655 0.888 -3.583 1.923 0.649 -4.22 0.258 -1.681 -1.158 -1.249 -2.972 -3.2 4.13 -0.694 1.79 -0.301 0.793 -1.636 1.783 -3.677"/>
       <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.759" d="M16.43 8.48l1.899 3.736 0.802 1.579 1.745 0.297 4.057 0.693 -2.954 3.217 -1.144 1.245 0.255 1.673 0.651 4.247 -3.688 -1.957 -1.66 -0.88 -1.655 0.888 -3.583 1.923 0.649 -4.22 0.258 -1.681 -1.158 -1.249 -2.972 -3.2 4.13 -0.694 1.79 -0.301 0.793 -1.636 1.783 -3.677"/>
     </g>
     <g mask="url(#H)">
       <path fill="context-stroke" d="M16.48 9.38l2.496 5.056 5.581 0.811 -4.038 3.937 0.953 5.559 -4.992 -2.625 -4.992 2.625 0.954 -5.559 -4.039 -3.937 5.581 -0.81 2.496 -5.058z"/>
       <path fill="none" d="M16.48 9.38l2.496 5.056 5.581 0.811 -4.038 3.937 0.953 5.559 -4.992 -2.625 -4.992 2.625 0.954 -5.559 -4.039 -3.937 5.581 -0.81 2.496 -5.058z"/>
     </g>
-    <path fill="context-fill" d="M1.758 13.047l-0.541 -0.264"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M1.758 13.047l-0.541 -0.264"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M1.758 13.047l-0.541 -0.264"/>
-    <path fill="context-fill" d="M31.253 13.08l0.54 -0.265"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M31.253 13.08l0.54 -0.265"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M31.253 13.08l0.54 -0.265"/>
-    <path fill="context-fill" d="M25.967 30.95l0.387 0.46"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M25.967 30.95l0.387 0.46"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M25.967 30.95l0.387 0.46"/>
-    <path fill="context-fill" d="M7.017 30.97l-0.387 0.46"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M7.017 30.97l-0.387 0.46"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M7.017 30.97l-0.387 0.46"/>
-    <path fill="context-fill" d="M16.559 2.172v-0.602"/>
+    <path fill="context-fill" fill-opacity="context-fill-opacity" d="M16.559 2.172v-0.602"/>
     <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-width="1.6" d="M16.559 2.172v-0.602"/>
   </svg>
   <svg x="561">
     <defs>
       <mask id="J" mask-type="alpha">
         <g clip-path="url(#f17_BkV3WrqkR1)" transform="matrix(.2 0 0 .2 -15.623 -12.404)">
           <path fill="context-stroke" d="M0 0h320v240h-320z"/>
         </g>
@@ -530,13 +530,13 @@
       </mask>
     </defs>
     <path fill="none" stroke="context-fill" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.584" d="M16.457 9.307l1.71 3.363 0.722 1.422 1.57 0.267 3.653 0.624 -2.66 2.897 -1.03 1.12 0.23 1.506 0.587 3.824 -3.32 -1.762 -1.496 -0.792 -1.49 0.8 -3.225 1.73 0.584 -3.798 0.233 -1.514 -1.043 -1.124 -2.676 -2.882 3.718 -0.624 1.613 -0.272 0.713 -1.472 1.606 -3.31" display="block"/>
     <g mask="url(#O)">
       <path fill="#FFF" d="M16.456 9.271l1.716 3.376 0.725 1.427 1.577 0.269 3.666 0.626 -2.67 2.907 -1.033 1.125 0.23 1.512 0.589 3.838 -3.333 -1.768 -1.5 -0.796 -1.496 0.803 -3.238 1.737 0.586 -3.813 0.234 -1.52 -1.047 -1.128 -2.686 -2.892 3.732 -0.627 1.619 -0.273 0.716 -1.477 1.612 -3.324"/>
       <path fill="none" stroke="context-stroke" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.59" d="M16.456 9.271l1.716 3.376 0.725 1.427 1.577 0.269 3.666 0.626 -2.67 2.907 -1.033 1.125 0.23 1.512 0.589 3.838 -3.333 -1.768 -1.5 -0.796 -1.496 0.803 -3.238 1.737 0.586 -3.813 0.234 -1.52 -1.047 -1.128 -2.686 -2.892 3.732 -0.627 1.619 -0.273 0.716 -1.477 1.612 -3.324"/>
     </g>
     <g mask="url(#P)" opacity=".08">
-      <path fill="context-fill" d="M16.502 10.083l2.255 4.57 5.044 0.734 -3.65 3.557 0.862 5.023 -4.511 -2.371 -4.512 2.371 0.862 -5.023 -3.65 -3.557 5.044 -0.733 2.256 -4.57z"/>
+      <path fill="context-fill" fill-opacity="context-fill-opacity" d="M16.502 10.083l2.255 4.57 5.044 0.734 -3.65 3.557 0.862 5.023 -4.511 -2.371 -4.512 2.371 0.862 -5.023 -3.65 -3.557 5.044 -0.733 2.256 -4.57z"/>
       <path fill="none" d="M16.502 10.083l2.255 4.57 5.044 0.734 -3.65 3.557 0.862 5.023 -4.511 -2.371 -4.512 2.371 0.862 -5.023 -3.65 -3.557 5.044 -0.733 2.256 -4.57z"/>
     </g>
   </svg>
 </svg>
--- a/browser/themes/shared/icons/bookmark-hollow.svg
+++ b/browser/themes/shared/icons/bookmark-hollow.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill-opacity="context-fill-opacity" fill="context-fill" d="M3.8 15.922a1.1 1.1 0 0 1-1.09-1.253l.609-4.36L.393 7.163a1.1 1.1 0 0 1 .616-1.833l4.08-.73L7.016.734a1.1 1.1 0 0 1 1.969 0L10.911 4.6 15 5.331a1.1 1.1 0 0 1 .611 1.833L12.68 10.31l.609 4.359a1.1 1.1 0 0 1-1.6 1.127L8 13.873 4.308 15.8a1.093 1.093 0 0 1-.508.122zm-.415-1.9zm9.228 0zM2.981 7.01l2.451 2.635-.5 3.572L8 11.618l3.067 1.6-.5-3.572 2.452-2.636-3.45-.616L8 3.244l-1.569 3.15zm11.659.29zm-13.278 0zm12.78-1.5zm-12.286 0z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M3.8 15.922a1.1 1.1 0 0 1-1.09-1.253l.609-4.36L.393 7.163a1.1 1.1 0 0 1 .616-1.833l4.08-.73L7.016.734a1.1 1.1 0 0 1 1.969 0L10.911 4.6 15 5.331a1.1 1.1 0 0 1 .611 1.833L12.68 10.31l.609 4.359a1.1 1.1 0 0 1-1.6 1.127L8 13.873 4.308 15.8a1.093 1.093 0 0 1-.508.122zm-.415-1.9zm9.228 0zM2.981 7.01l2.451 2.635-.5 3.572L8 11.618l3.067 1.6-.5-3.572 2.452-2.636-3.45-.616L8 3.244l-1.569 3.15zm11.659.29zm-13.278 0zm12.78-1.5zm-12.286 0z"/>
 </svg>
--- a/browser/themes/shared/icons/bookmark-star-on-tray.svg
+++ b/browser/themes/shared/icons/bookmark-star-on-tray.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M14 16H2a1 1 0 0 1-1-1v-2a1 1 0 0 1 2 0v1h10v-1a1 1 0 0 1 2 0v2a1 1 0 0 1-1 1zM13.961 4.282a.9.9 0 0 0-.723-.609l-3.063-.445L8.805.456a.934.934 0 0 0-1.605 0L5.83 3.228l-3.063.445A.893.893 0 0 0 2.27 5.2l2.217 2.156-.523 3.044a.894.894 0 0 0 1.3.942L8 9.907l2.74 1.439a.888.888 0 0 0 .416.1.9.9 0 0 0 .526-.172.893.893 0 0 0 .355-.874l-.522-3.047 2.22-2.153a.893.893 0 0 0 .226-.918zm-4.367 2.45l.376 2.189L8 7.888 6.035 8.921l.376-2.189-1.592-1.55 2.2-.319L8 2.872l.983 1.991 2.2.319z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M14 16H2a1 1 0 0 1-1-1v-2a1 1 0 0 1 2 0v1h10v-1a1 1 0 0 1 2 0v2a1 1 0 0 1-1 1zM13.961 4.282a.9.9 0 0 0-.723-.609l-3.063-.445L8.805.456a.934.934 0 0 0-1.605 0L5.83 3.228l-3.063.445A.893.893 0 0 0 2.27 5.2l2.217 2.156-.523 3.044a.894.894 0 0 0 1.3.942L8 9.907l2.74 1.439a.888.888 0 0 0 .416.1.9.9 0 0 0 .526-.172.893.893 0 0 0 .355-.874l-.522-3.047 2.22-2.153a.893.893 0 0 0 .226-.918zm-4.367 2.45l.376 2.189L8 7.888 6.035 8.921l.376-2.189-1.592-1.55 2.2-.319L8 2.872l.983 1.991 2.2.319z"/>
 </svg>
\ No newline at end of file
--- a/browser/themes/shared/icons/bookmark.svg
+++ b/browser/themes/shared/icons/bookmark.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill-opacity="context-fill-opacity" fill="context-fill" d="M15.845 6.064A1.1 1.1 0 0 0 15 5.331L10.911 4.6 8.985.735a1.1 1.1 0 0 0-1.969 0L5.089 4.6l-4.081.729a1.1 1.1 0 0 0-.615 1.834L3.32 10.31l-.609 4.36a1.1 1.1 0 0 0 1.6 1.127L8 13.873l3.69 1.927a1.1 1.1 0 0 0 1.6-1.127l-.61-4.363 2.926-3.146a1.1 1.1 0 0 0 .239-1.1z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M15.845 6.064A1.1 1.1 0 0 0 15 5.331L10.911 4.6 8.985.735a1.1 1.1 0 0 0-1.969 0L5.089 4.6l-4.081.729a1.1 1.1 0 0 0-.615 1.834L3.32 10.31l-.609 4.36a1.1 1.1 0 0 0 1.6 1.127L8 13.873l3.69 1.927a1.1 1.1 0 0 0 1.6-1.127l-.61-4.363 2.926-3.146a1.1 1.1 0 0 0 .239-1.1z"/>
 </svg>
--- a/browser/themes/shared/icons/characterEncoding.svg
+++ b/browser/themes/shared/icons/characterEncoding.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M13 15H3a2.006 2.006 0 0 1-2-2V3a2.006 2.006 0 0 1 2-2h10a2.006 2.006 0 0 1 2 2v10a2.006 2.006 0 0 1-2 2zm0-10a2.946 2.946 0 0 0-3-3H6a2.946 2.946 0 0 0-3 3v4a2.946 2.946 0 0 0 3 3h4c1.7 0 3-.3 3-2zm-3 3.2a2.769 2.769 0 0 0 .9-.1c.3-.1.5-.2.8-.3v.8a6.89 6.89 0 0 0-.8.3 2.22 2.22 0 0 1-.9.1 2.149 2.149 0 0 1-2.1-1.2 3.819 3.819 0 0 1-.9.9 2.663 2.663 0 0 1-1.2.3 1.728 1.728 0 0 1-1.3-.5A1.248 1.248 0 0 1 4 7.3 1.486 1.486 0 0 1 4.6 6a3.312 3.312 0 0 1 1.9-.5h.9v-.4a1.327 1.327 0 0 0-.3-1c-.1-.3-.4-.4-.8-.4a3.429 3.429 0 0 0-1.6.4l-.2-.6a3.919 3.919 0 0 1 .9-.4c.3 0 .6-.1 1-.1a3.6 3.6 0 0 1 1.1.2 1.7 1.7 0 0 1 .6.8 1.575 1.575 0 0 1 .7-.7 1.689 1.689 0 0 1 1-.3 1.865 1.865 0 0 1 1.6.7 2.883 2.883 0 0 1 .6 1.9v.6H8.4c0 1.4.6 2 1.6 2zM7.5 6.1h-.8a2.42 2.42 0 0 0-1.4.3.975.975 0 0 0-.4.9.779.779 0 0 0 .3.7.844.844 0 0 0 .7.2 1.594 1.594 0 0 0 1.2-.4 1.7 1.7 0 0 0 .4-1.3zm3.6-.6a2.269 2.269 0 0 0-.3-1.3.975.975 0 0 0-.9-.4 1.284 1.284 0 0 0-1 .4 2.226 2.226 0 0 0-.5 1.3z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M13 15H3a2.006 2.006 0 0 1-2-2V3a2.006 2.006 0 0 1 2-2h10a2.006 2.006 0 0 1 2 2v10a2.006 2.006 0 0 1-2 2zm0-10a2.946 2.946 0 0 0-3-3H6a2.946 2.946 0 0 0-3 3v4a2.946 2.946 0 0 0 3 3h4c1.7 0 3-.3 3-2zm-3 3.2a2.769 2.769 0 0 0 .9-.1c.3-.1.5-.2.8-.3v.8a6.89 6.89 0 0 0-.8.3 2.22 2.22 0 0 1-.9.1 2.149 2.149 0 0 1-2.1-1.2 3.819 3.819 0 0 1-.9.9 2.663 2.663 0 0 1-1.2.3 1.728 1.728 0 0 1-1.3-.5A1.248 1.248 0 0 1 4 7.3 1.486 1.486 0 0 1 4.6 6a3.312 3.312 0 0 1 1.9-.5h.9v-.4a1.327 1.327 0 0 0-.3-1c-.1-.3-.4-.4-.8-.4a3.429 3.429 0 0 0-1.6.4l-.2-.6a3.919 3.919 0 0 1 .9-.4c.3 0 .6-.1 1-.1a3.6 3.6 0 0 1 1.1.2 1.7 1.7 0 0 1 .6.8 1.575 1.575 0 0 1 .7-.7 1.689 1.689 0 0 1 1-.3 1.865 1.865 0 0 1 1.6.7 2.883 2.883 0 0 1 .6 1.9v.6H8.4c0 1.4.6 2 1.6 2zM7.5 6.1h-.8a2.42 2.42 0 0 0-1.4.3.975.975 0 0 0-.4.9.779.779 0 0 0 .3.7.844.844 0 0 0 .7.2 1.594 1.594 0 0 0 1.2-.4 1.7 1.7 0 0 0 .4-1.3zm3.6-.6a2.269 2.269 0 0 0-.3-1.3.975.975 0 0 0-.9-.4 1.284 1.284 0 0 0-1 .4 2.226 2.226 0 0 0-.5 1.3z"/>
 </svg>
--- a/browser/themes/shared/icons/check.svg
+++ b/browser/themes/shared/icons/check.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M6 14a1 1 0 0 1-.707-.293l-3-3a1 1 0 0 1 1.414-1.414l2.157 2.157 6.316-9.023a1 1 0 0 1 1.639 1.146l-7 10a1 1 0 0 1-.732.427A.863.863 0 0 1 6 14z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M6 14a1 1 0 0 1-.707-.293l-3-3a1 1 0 0 1 1.414-1.414l2.157 2.157 6.316-9.023a1 1 0 0 1 1.639 1.146l-7 10a1 1 0 0 1-.732.427A.863.863 0 0 1 6 14z"/>
 </svg>
--- a/browser/themes/shared/icons/chevron-animation.svg
+++ b/browser/themes/shared/icons/chevron-animation.svg
@@ -1,12 +1,12 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg xmlns="http://www.w3.org/2000/svg" width="1278" height="36" fill="context-fill">
+<svg xmlns="http://www.w3.org/2000/svg" width="1278" height="36" fill="context-fill" fill-opacity="context-fill-opacity">
   <svg>
     <path d="M9.707 17.293l-5 -5a1 1 0 1 0 -1.414 1.414l4.293 4.293 -4.293 4.293a1 1 0 0 0 -0.025 1.414 1 1 0 0 0 1.414 0.025l0.025 -0.025 5 -5a1 1 0 0 0 0 -1.414zm6 0l-5 -5a1 1 0 1 0 -1.414 1.414l4.293 4.293 -4.293 4.293a1 1 0 0 0 -0.025 1.414 1 1 0 0 0 1.414 0.025l0.025 -0.025 5 -5a1 1 0 0 0 0 -1.414z"/>
   </svg>
   <svg x="18">
     <path d="M9.714 17.3l-4.948 -5.051a1 1 0 1 0 -1.429 1.4l4.25 4.336 -4.338 4.249a1 1 0 0 0 -0.04 1.413 1 1 0 0 0 1.414 0.04l0.025 -0.025 5.052 -4.948a1 1 0 0 0 0.014 -1.414zm6 0.063l-4.948 -5.052a1 1 0 1 0 -1.429 1.4l4.249 4.337 -4.338 4.248a1 1 0 0 0 -0.04 1.413 1 1 0 0 0 1.415 0.04l0.025 -0.025 5.051 -4.948a1 1 0 0 0 0.015 -1.413z"/>
   </svg>
   <svg x="36">
     <path d="M9.735 17.322l-4.796 -5.196a1 1 0 1 0 -1.47 1.356l4.118 4.461 -4.461 4.118a1 1 0 0 0 -0.082 1.412 1 1 0 0 0 1.412 0.081c0.01 -0.007 0.017 -0.016 0.026 -0.024l5.196 -4.795a1 1 0 0 0 0.057 -1.413zm5.995 0.24l-4.796 -5.196a1 1 0 1 0 -1.47 1.356l4.118 4.462 -4.461 4.117a1 1 0 0 0 -0.082 1.412 1 1 0 0 0 1.412 0.082l0.026 -0.024 5.196 -4.796a1 1 0 0 0 0.057 -1.413z"/>
--- a/browser/themes/shared/icons/chevron.svg
+++ b/browser/themes/shared/icons/chevron.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M8.707,7.293l-5-5A1,1,0,0,0,2.293,3.707L6.586,8,2.293,12.293a1,1,0,1,0,1.414,1.414l5-5A1,1,0,0,0,8.707,7.293Zm6,0-5-5A1,1,0,0,0,8.293,3.707L12.586,8,8.293,12.293a1,1,0,1,0,1.414,1.414l5-5A1,1,0,0,0,14.707,7.293Z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M8.707,7.293l-5-5A1,1,0,0,0,2.293,3.707L6.586,8,2.293,12.293a1,1,0,1,0,1.414,1.414l5-5A1,1,0,0,0,8.707,7.293Zm6,0-5-5A1,1,0,0,0,8.293,3.707L12.586,8,8.293,12.293a1,1,0,1,0,1.414,1.414l5-5A1,1,0,0,0,14.707,7.293Z"/>
 </svg>
--- a/browser/themes/shared/icons/containers.svg
+++ b/browser/themes/shared/icons/containers.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M12 4H4v4h8zm-2 2.75a.25.25 0 0 1-.25.25h-3.5A.25.25 0 0 1 6 6.75v-.5A.25.25 0 0 1 6.25 6h3.5a.25.25 0 0 1 .25.25zM12 9H4v4h8zm-2 2.75a.25.25 0 0 1-.25.25h-3.5a.25.25 0 0 1-.25-.25v-.5a.25.25 0 0 1 .25-.25h3.5a.25.25 0 0 1 .25.25zm3.854-9.9L13 1H3l-.854.853A.5.5 0 0 0 2 2.207V14a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V2.207a.5.5 0 0 0-.146-.354zM13 14H3V3h10z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M12 4H4v4h8zm-2 2.75a.25.25 0 0 1-.25.25h-3.5A.25.25 0 0 1 6 6.75v-.5A.25.25 0 0 1 6.25 6h3.5a.25.25 0 0 1 .25.25zM12 9H4v4h8zm-2 2.75a.25.25 0 0 1-.25.25h-3.5a.25.25 0 0 1-.25-.25v-.5a.25.25 0 0 1 .25-.25h3.5a.25.25 0 0 1 .25.25zm3.854-9.9L13 1H3l-.854.853A.5.5 0 0 0 2 2.207V14a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V2.207a.5.5 0 0 0-.146-.354zM13 14H3V3h10z"/>
 </svg>
--- a/browser/themes/shared/icons/customize.svg
+++ b/browser/themes/shared/icons/customize.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M4 10a1.994 1.994 0 0 0-1.911 1.44c0 .01-.014.015-.017.025-.362 1.135-.705 2.11-1.759 2.573l-.023.012-.024.012A.5.5 0 0 0 0 14.5a.5.5 0 0 0 .5.5 6.974 6.974 0 0 0 4.825-1.5c.006-.006.007-.013.013-.019A1.993 1.993 0 0 0 4 10zM15.693.307a.984.984 0 0 0-1.338-.046l-8.031 7a.982.982 0 0 0-.049 1.433l1.032 1.031a.983.983 0 0 0 .693.287h.033a.982.982 0 0 0 .706-.335l7-8.031a.982.982 0 0 0-.046-1.339z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M4 10a1.994 1.994 0 0 0-1.911 1.44c0 .01-.014.015-.017.025-.362 1.135-.705 2.11-1.759 2.573l-.023.012-.024.012A.5.5 0 0 0 0 14.5a.5.5 0 0 0 .5.5 6.974 6.974 0 0 0 4.825-1.5c.006-.006.007-.013.013-.019A1.993 1.993 0 0 0 4 10zM15.693.307a.984.984 0 0 0-1.338-.046l-8.031 7a.982.982 0 0 0-.049 1.433l1.032 1.031a.983.983 0 0 0 .693.287h.033a.982.982 0 0 0 .706-.335l7-8.031a.982.982 0 0 0-.046-1.339z"/>
 </svg>
--- a/browser/themes/shared/icons/developer.svg
+++ b/browser/themes/shared/icons/developer.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M14.555 3.2l-2.434 2.436a1.243 1.243 0 1 1-1.757-1.757L12.8 1.445A3.956 3.956 0 0 0 11 1a3.976 3.976 0 0 0-3.434 6.02l-6.273 6.273a1 1 0 1 0 1.414 1.414L8.98 8.434A3.96 3.96 0 0 0 11 9a4 4 0 0 0 4-4 3.956 3.956 0 0 0-.445-1.8z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M14.555 3.2l-2.434 2.436a1.243 1.243 0 1 1-1.757-1.757L12.8 1.445A3.956 3.956 0 0 0 11 1a3.976 3.976 0 0 0-3.434 6.02l-6.273 6.273a1 1 0 1 0 1.414 1.414L8.98 8.434A3.96 3.96 0 0 0 11 9a4 4 0 0 0 4-4 3.956 3.956 0 0 0-.445-1.8z"/>
 </svg>
--- a/browser/themes/shared/icons/device-desktop.svg
+++ b/browser/themes/shared/icons/device-desktop.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill-opacity="context-fill-opacity" fill="context-fill" d="M15.5 12H15V3a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1v9H.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h15a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5zM10 13H6v-1h4zm3-2H3V4h10z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M15.5 12H15V3a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1v9H.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h15a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5zM10 13H6v-1h4zm3-2H3V4h10z"/>
 </svg>
--- a/browser/themes/shared/icons/device-mobile.svg
+++ b/browser/themes/shared/icons/device-mobile.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill-opacity="context-fill-opacity" fill="context-fill" d="M12 0H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zM9 15H7v-1h2zm3-2.5a.5.5 0 0 1-.5.5h-7a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 .5.5z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M12 0H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zM9 15H7v-1h2zm3-2.5a.5.5 0 0 1-.5.5h-7a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 .5.5z"/>
 </svg>
--- a/browser/themes/shared/icons/device-tablet.svg
+++ b/browser/themes/shared/icons/device-tablet.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill-opacity="context-fill-opacity" fill="context-fill" d="M14 1H2C.895 1 0 1.895 0 3v10c0 1.105.895 2 2 2h12c1.105 0 2-.895 2-2V3c0-1.105-.895-2-2-2zm-1 11.5c0 .276-.224.5-.5.5h-10c-.276 0-.5-.224-.5-.5v-9c0-.276.224-.5.5-.5h10c.276 0 .5.224.5.5v9zM15 9h-1V7h1v2z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M14 1H2C.895 1 0 1.895 0 3v10c0 1.105.895 2 2 2h12c1.105 0 2-.895 2-2V3c0-1.105-.895-2-2-2zm-1 11.5c0 .276-.224.5-.5.5h-10c-.276 0-.5-.224-.5-.5v-9c0-.276.224-.5.5-.5h10c.276 0 .5.224.5.5v9zM15 9h-1V7h1v2z"/>
 </svg>
--- a/browser/themes/shared/icons/edit-copy.svg
+++ b/browser/themes/shared/icons/edit-copy.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M14.707 8.293l-3-3A1 1 0 0 0 11 5h-1V4a1 1 0 0 0-.293-.707l-3-3A1 1 0 0 0 6 0H3a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3v3a2 2 0 0 0 2 2h5a2 2 0 0 0 2-2V9a1 1 0 0 0-.293-.707zM12.586 9H11V7.414zm-5-5H6V2.414zM6 7v2H3V2h2v2.5a.5.5 0 0 0 .5.5H8a2 2 0 0 0-2 2zm2 7V7h2v2.5a.5.5 0 0 0 .5.5H13v4z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M14.707 8.293l-3-3A1 1 0 0 0 11 5h-1V4a1 1 0 0 0-.293-.707l-3-3A1 1 0 0 0 6 0H3a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3v3a2 2 0 0 0 2 2h5a2 2 0 0 0 2-2V9a1 1 0 0 0-.293-.707zM12.586 9H11V7.414zm-5-5H6V2.414zM6 7v2H3V2h2v2.5a.5.5 0 0 0 .5.5H8a2 2 0 0 0-2 2zm2 7V7h2v2.5a.5.5 0 0 0 .5.5H13v4z"/>
 </svg>
--- a/browser/themes/shared/icons/edit-cut.svg
+++ b/browser/themes/shared/icons/edit-cut.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M11.5 10a2.481 2.481 0 0 0-.379.038L3.977 1.214a2.5 2.5 0 0 0-.371 3.515l2.789 3.444-1.51 1.866A2.486 2.486 0 0 0 4.5 10a2.522 2.522 0 1 0 2.329 1.609L8 10.159 9.172 11.6A2.5 2.5 0 1 0 11.5 10zm-7 3.75a1.25 1.25 0 1 1 1.25-1.25 1.251 1.251 0 0 1-1.25 1.25zm7 0a1.25 1.25 0 1 1 1.25-1.25 1.251 1.251 0 0 1-1.25 1.25zm.9-9.021a2.5 2.5 0 0 0-.371-3.515L8.5 5.569l1.608 1.986z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M11.5 10a2.481 2.481 0 0 0-.379.038L3.977 1.214a2.5 2.5 0 0 0-.371 3.515l2.789 3.444-1.51 1.866A2.486 2.486 0 0 0 4.5 10a2.522 2.522 0 1 0 2.329 1.609L8 10.159 9.172 11.6A2.5 2.5 0 1 0 11.5 10zm-7 3.75a1.25 1.25 0 1 1 1.25-1.25 1.251 1.251 0 0 1-1.25 1.25zm7 0a1.25 1.25 0 1 1 1.25-1.25 1.251 1.251 0 0 1-1.25 1.25zm.9-9.021a2.5 2.5 0 0 0-.371-3.515L8.5 5.569l1.608 1.986z"/>
 </svg>
--- a/browser/themes/shared/icons/edit-paste.svg
+++ b/browser/themes/shared/icons/edit-paste.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M11 2H9.95a2.5 2.5 0 0 0-4.9 0H4a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h7a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm0 7a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V5h7zm0-5H4V3h1.05a1 1 0 0 0 .98-.8 1.5 1.5 0 0 1 2.939 0 1 1 0 0 0 .98.8H11zM7.5 2a.5.5 0 1 0 .5.5.5.5 0 0 0-.5-.5zm-2 5h4a.5.5 0 0 0 0-1h-4a.5.5 0 0 0 0 1zm0 2h2a.5.5 0 0 0 0-1h-2a.5.5 0 0 0 0 1z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M11 2H9.95a2.5 2.5 0 0 0-4.9 0H4a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h7a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm0 7a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V5h7zm0-5H4V3h1.05a1 1 0 0 0 .98-.8 1.5 1.5 0 0 1 2.939 0 1 1 0 0 0 .98.8H11zM7.5 2a.5.5 0 1 0 .5.5.5.5 0 0 0-.5-.5zm-2 5h4a.5.5 0 0 0 0-1h-4a.5.5 0 0 0 0 1zm0 2h2a.5.5 0 0 0 0-1h-2a.5.5 0 0 0 0 1z"/>
 </svg>
deleted file mode 100644
--- a/browser/themes/shared/icons/email-link.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill-opacity="context-fill-opacity" fill="context-fill">
-  <path d="M13 2H3a3.013 3.013 0 0 0-3 3v6a3.013 3.013 0 0 0 3 3h10a3.013 3.013 0 0 0 3-3V5a3.013 3.013 0 0 0-3-3zm1 9a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1z"/>
-  <path d="M8 9a.5.5 0 0 1-.294-.1l-5.5-4a.5.5 0 1 1 .588-.8L8 7.882 13.207 4.1a.5.5 0 0 1 .588.809l-5.5 4A.5.5 0 0 1 8 9z"/>
-</svg>
--- a/browser/themes/shared/icons/feed.svg
+++ b/browser/themes/shared/icons/feed.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M3.5 10A2.5 2.5 0 1 0 6 12.5 2.5 2.5 0 0 0 3.5 10zM2 1a1 1 0 0 0 0 2 10.883 10.883 0 0 1 11 11 1 1 0 0 0 2 0A12.862 12.862 0 0 0 2 1zm0 4a1 1 0 0 0 0 2 6.926 6.926 0 0 1 7 7 1 1 0 0 0 2 0 8.9 8.9 0 0 0-9-9z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M3.5 10A2.5 2.5 0 1 0 6 12.5 2.5 2.5 0 0 0 3.5 10zM2 1a1 1 0 0 0 0 2 10.883 10.883 0 0 1 11 11 1 1 0 0 0 2 0A12.862 12.862 0 0 0 2 1zm0 4a1 1 0 0 0 0 2 6.926 6.926 0 0 1 7 7 1 1 0 0 0 2 0 8.9 8.9 0 0 0-9-9z"/>
 </svg>
--- a/browser/themes/shared/icons/find.svg
+++ b/browser/themes/shared/icons/find.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M15.707 14.293l-4.822-4.822a6.019 6.019 0 1 0-1.414 1.414l4.822 4.822a1 1 0 0 0 1.414-1.414zM6 10a4 4 0 1 1 4-4 4 4 0 0 1-4 4z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M15.707 14.293l-4.822-4.822a6.019 6.019 0 1 0-1.414 1.414l4.822 4.822a1 1 0 0 0 1.414-1.414zM6 10a4 4 0 1 1 4-4 4 4 0 0 1-4 4z"/>
 </svg>
--- a/browser/themes/shared/icons/folder.svg
+++ b/browser/themes/shared/icons/folder.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M14 3H8.151L6.584 1.538A2 2 0 0 0 5.219 1H2a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2zM5.219 3l1.072 1H2V3zM14 13H2V5h6v-.014c.05 0 .1.014.151.014H14z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M14 3H8.151L6.584 1.538A2 2 0 0 0 5.219 1H2a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2zM5.219 3l1.072 1H2V3zM14 13H2V5h6v-.014c.05 0 .1.014.151.014H14z"/>
 </svg>
--- a/browser/themes/shared/icons/forget.svg
+++ b/browser/themes/shared/icons/forget.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M6.854 10.854l2-2A.5.5 0 0 0 9 8.5v-4a.5.5 0 0 0-1 0v3.793l-1.854 1.853a.5.5 0 1 0 .707.707zM8 0a8.011 8.011 0 0 0-7 4.184V1.5a.5.5 0 0 0-1 0v5a.5.5 0 0 0 .5.5h5a.5.5 0 0 0 0-1H2.344a.938.938 0 0 0 .056-.085 6 6 0 1 1 0 4.184 1 1 0 0 0-1.873.7A7.991 7.991 0 1 0 8 0z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M6.854 10.854l2-2A.5.5 0 0 0 9 8.5v-4a.5.5 0 0 0-1 0v3.793l-1.854 1.853a.5.5 0 1 0 .707.707zM8 0a8.011 8.011 0 0 0-7 4.184V1.5a.5.5 0 0 0-1 0v5a.5.5 0 0 0 .5.5h5a.5.5 0 0 0 0-1H2.344a.938.938 0 0 0 .056-.085 6 6 0 1 1 0 4.184 1 1 0 0 0-1.873.7A7.991 7.991 0 1 0 8 0z"/>
 </svg>
--- a/browser/themes/shared/icons/forward.svg
+++ b/browser/themes/shared/icons/forward.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M15.707,7.293l-6-6A1,1,0,0,0,8.293,2.707L12.586,7H1A1,1,0,0,0,1,9H12.586L8.293,13.293a1,1,0,1,0,1.414,1.414l6-6A1,1,0,0,0,15.707,7.293Z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M15.707,7.293l-6-6A1,1,0,0,0,8.293,2.707L12.586,7H1A1,1,0,0,0,1,9H12.586L8.293,13.293a1,1,0,1,0,1.414,1.414l6-6A1,1,0,0,0,15.707,7.293Z"/>
 </svg>
--- a/browser/themes/shared/icons/fullscreen-exit.svg
+++ b/browser/themes/shared/icons/fullscreen-exit.svg
@@ -1,7 +1,7 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill">
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill" fill-opacity="context-fill-opacity">
   <path d="M7,8H2a1,1,0,0,0,0,2H4.586L1.293,13.293a1,1,0,1,0,1.414,1.414L6,11.414V14a1,1,0,0,0,2,0V9A1,1,0,0,0,7,8Z"/>
   <path d="M14,6H11.414l3.293-3.293a1,1,0,0,0-1.414-1.414L10,4.586V2A1,1,0,0,0,8,2V7A1,1,0,0,0,9,8h5a1,1,0,0,0,0-2Z"/>
 </svg>
--- a/browser/themes/shared/icons/fullscreen.svg
+++ b/browser/themes/shared/icons/fullscreen.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M7.707 8.293a1 1 0 0 0-1.414 0L3 11.586V9a1 1 0 0 0-2 0v5a1 1 0 0 0 1 1h5a1 1 0 1 0 0-2H4.414l3.293-3.293a1 1 0 0 0 0-1.414zM14 1H9a1 1 0 0 0 0 2h2.586L8.293 6.293a1 1 0 1 0 1.414 1.414L13 4.414V7a1 1 0 0 0 2 0V2a1 1 0 0 0-1-1z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M7.707 8.293a1 1 0 0 0-1.414 0L3 11.586V9a1 1 0 0 0-2 0v5a1 1 0 0 0 1 1h5a1 1 0 1 0 0-2H4.414l3.293-3.293a1 1 0 0 0 0-1.414zM14 1H9a1 1 0 0 0 0 2h2.586L8.293 6.293a1 1 0 1 0 1.414 1.414L13 4.414V7a1 1 0 0 0 2 0V2a1 1 0 0 0-1-1z"/>
 </svg>
--- a/browser/themes/shared/icons/history.svg
+++ b/browser/themes/shared/icons/history.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M8 0a8 8 0 1 0 8 8 8.009 8.009 0 0 0-8-8zm0 14a6 6 0 1 1 6-6 6.007 6.007 0 0 1-6 6zm3.5-6H8V4.5a.5.5 0 0 0-1 0v4a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 0-1z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M8 0a8 8 0 1 0 8 8 8.009 8.009 0 0 0-8-8zm0 14a6 6 0 1 1 6-6 6.007 6.007 0 0 1-6 6zm3.5-6H8V4.5a.5.5 0 0 0-1 0v4a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 0-1z"/>
 </svg>
--- a/browser/themes/shared/icons/home.svg
+++ b/browser/themes/shared/icons/home.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M15.707,7.293l-7-7a1,1,0,0,0-1.414,0l-7,7A1,1,0,0,0,1.707,8.707L2,8.414V14a2,2,0,0,0,2,2h8a2,2,0,0,0,2-2V8.414l.293.293a1,1,0,0,0,1.414-1.414ZM8,11.5a.5.5,0,1,1,.5.5A.5.5,0,0,1,8,11.5ZM12,13a1,1,0,0,1-1,1H10V9A1,1,0,0,0,9,8H7A1,1,0,0,0,6,9v5H5a1,1,0,0,1-1-1V6.414l4-4,4,4Z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M15.707,7.293l-7-7a1,1,0,0,0-1.414,0l-7,7A1,1,0,0,0,1.707,8.707L2,8.414V14a2,2,0,0,0,2,2h8a2,2,0,0,0,2-2V8.414l.293.293a1,1,0,0,0,1.414-1.414ZM8,11.5a.5.5,0,1,1,.5.5A.5.5,0,0,1,8,11.5ZM12,13a1,1,0,0,1-1,1H10V9A1,1,0,0,0,9,8H7A1,1,0,0,0,6,9v5H5a1,1,0,0,1-1-1V6.414l4-4,4,4Z"/>
 </svg>
--- a/browser/themes/shared/icons/library-bookmark-animation.svg
+++ b/browser/themes/shared/icons/library-bookmark-animation.svg
@@ -1,12 +1,12 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg xmlns="http://www.w3.org/2000/svg" width="1078" height="54" fill="context-fill">
+<svg xmlns="http://www.w3.org/2000/svg" width="1078" height="54" fill="context-fill" fill-opacity="context-fill-opacity">
   <svg>
     <path d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z"/>
   </svg>
   <svg x="22">
     <defs>
       <mask id="a" mask-type="alpha">
         <path fill="context-stroke" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 4.641 5.5 0.109 0.75 -2.141 3.25 -0.015 6.787 0.009 9.339 25.4 4.124 -39.128 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.108 28.313)"/>
         <path fill-opacity="0" stroke="rgb(135,17,17)" stroke-width="0" d="M-1.454 -10.124l-7.75 24.312 10.687 6 2.75 -0.375 1.5 -0.125 1.125 2.32 2.75 0.055 0.375 -1.07 1.625 -0.008 3.393 0.005 4.67 12.7 2.062 -19.564 3 -12.625 -0.375 -11.125 -25.813 -0.5z"/>
--- a/browser/themes/shared/icons/library.svg
+++ b/browser/themes/shared/icons/library.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M5 3a1 1 0 0 0-1 1v10a1 1 0 0 0 2 0V4a1 1 0 0 0-1-1zm3-1a1 1 0 0 0-1 1v11a1 1 0 0 0 2 0V3a1 1 0 0 0-1-1zm7.939 11.658l-4-11a1 1 0 1 0-1.879.684l4 11a1 1 0 1 0 1.879-.684zM2 1a1 1 0 0 0-1 1v12a1 1 0 0 0 2 0V2a1 1 0 0 0-1-1z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M5 3a1 1 0 0 0-1 1v10a1 1 0 0 0 2 0V4a1 1 0 0 0-1-1zm3-1a1 1 0 0 0-1 1v11a1 1 0 0 0 2 0V3a1 1 0 0 0-1-1zm7.939 11.658l-4-11a1 1 0 1 0-1.879.684l4 11a1 1 0 1 0 1.879-.684zM2 1a1 1 0 0 0-1 1v12a1 1 0 0 0 2 0V2a1 1 0 0 0-1-1z"/>
 </svg>
--- a/browser/themes/shared/icons/link.svg
+++ b/browser/themes/shared/icons/link.svg
@@ -1,8 +1,8 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <rect fill-opacity="context-fill-opacity" fill="context-fill" x="7" y="3.286" width="2" height="9.429" rx="1" ry="1" transform="rotate(-45 8 8)"/>
-  <path fill-opacity="context-fill-opacity" fill="context-fill" d="M2.354 4.522L4.485 2.39a.5.5 0 0 1 .711 0l3.19 3.19.014-.015a2 2 0 0 0 0-2.821L6.272.616a2 2 0 0 0-2.821 0L.616 3.451a2 2 0 0 0 0 2.821L2.744 8.4a1.993 1.993 0 0 0 2.8.02l-3.19-3.186a.5.5 0 0 1 0-.712z"/>
-  <path fill-opacity="context-fill-opacity" fill="context-fill" d="M15.416 9.759L13.287 7.63a2 2 0 0 0-2.821 0l-.015.015 3.189 3.189a.5.5 0 0 1 0 .711l-2.132 2.132a.5.5 0 0 1-.711 0L7.61 10.49a1.993 1.993 0 0 0 .02 2.8l2.128 2.128a2 2 0 0 0 2.821 0l2.835-2.835a2 2 0 0 0 .002-2.824z"/>
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill" fill-opacity="context-fill-opacity">
+  <rect x="7" y="3.286" width="2" height="9.429" rx="1" ry="1" transform="rotate(-45 8 8)"/>
+  <path d="M2.354 4.522L4.485 2.39a.5.5 0 0 1 .711 0l3.19 3.19.014-.015a2 2 0 0 0 0-2.821L6.272.616a2 2 0 0 0-2.821 0L.616 3.451a2 2 0 0 0 0 2.821L2.744 8.4a1.993 1.993 0 0 0 2.8.02l-3.19-3.186a.5.5 0 0 1 0-.712z"/>
+  <path d="M15.416 9.759L13.287 7.63a2 2 0 0 0-2.821 0l-.015.015 3.189 3.189a.5.5 0 0 1 0 .711l-2.132 2.132a.5.5 0 0 1-.711 0L7.61 10.49a1.993 1.993 0 0 0 .02 2.8l2.128 2.128a2 2 0 0 0 2.821 0l2.835-2.835a2 2 0 0 0 .002-2.824z"/>
 </svg>
--- a/browser/themes/shared/icons/mail.svg
+++ b/browser/themes/shared/icons/mail.svg
@@ -1,7 +1,7 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill">
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill" fill-opacity="context-fill-opacity">
   <path d="M13 2H3a3.013 3.013 0 0 0-3 3v6a3.013 3.013 0 0 0 3 3h10a3.013 3.013 0 0 0 3-3V5a3.013 3.013 0 0 0-3-3zm1 9a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1z"/>
   <path d="M8 9a.5.5 0 0 1-.294-.1l-5.5-4a.5.5 0 1 1 .588-.8L8 7.882 13.207 4.1a.5.5 0 0 1 .588.809l-5.5 4A.5.5 0 0 1 8 9z"/>
 </svg>
--- a/browser/themes/shared/icons/menu.svg
+++ b/browser/themes/shared/icons/menu.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M3,4H13a1,1,0,0,0,0-2H3A1,1,0,0,0,3,4ZM13,7H3A1,1,0,0,0,3,9H13a1,1,0,0,0,0-2Zm0,5H3a1,1,0,0,0,0,2H13a1,1,0,0,0,0-2Z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M3,4H13a1,1,0,0,0,0-2H3A1,1,0,0,0,3,4ZM13,7H3A1,1,0,0,0,3,9H13a1,1,0,0,0,0-2Zm0,5H3a1,1,0,0,0,0,2H13a1,1,0,0,0,0-2Z"/>
 </svg>
--- a/browser/themes/shared/icons/new-tab.svg
+++ b/browser/themes/shared/icons/new-tab.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M11 11V9a1 1 0 0 1 1-1h1a1 1 0 0 1 1 1V5a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v6H1a1 1 0 0 0 0 2h7v-1a1 1 0 0 1 1-1zm4.5 1H13V9.5a.5.5 0 0 0-1 0V12H9.5a.5.5 0 0 0 0 1H12v2.5a.5.5 0 0 0 1 0V13h2.5a.5.5 0 0 0 0-1z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M11 11V9a1 1 0 0 1 1-1h1a1 1 0 0 1 1 1V5a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v6H1a1 1 0 0 0 0 2h7v-1a1 1 0 0 1 1-1zm4.5 1H13V9.5a.5.5 0 0 0-1 0V12H9.5a.5.5 0 0 0 0 1H12v2.5a.5.5 0 0 0 1 0V13h2.5a.5.5 0 0 0 0-1z"/>
 </svg>
--- a/browser/themes/shared/icons/new-window.svg
+++ b/browser/themes/shared/icons/new-window.svg
@@ -1,7 +1,7 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill">
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill" fill-opacity="context-fill-opacity">
   <path d="M15.5 12H13V9.5a.5.5 0 0 0-1 0V12H9.5a.5.5 0 0 0 0 1H12v2.5a.5.5 0 0 0 1 0V13h2.5a.5.5 0 0 0 0-1z"/>
   <path d="M16 4a3 3 0 0 0-3-3H3a3 3 0 0 0-3 3v8a3 3 0 0 0 3 3h4.03v-.006a.994.994 0 0 0 0-1.987V13H3a1 1 0 0 1-1-1V6h12v1.952h.01c0 .017-.01.031-.01.048a1 1 0 0 0 2 0c0-.017-.009-.031-.01-.048H16zM2 5V4a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v1z"/>
 </svg>
--- a/browser/themes/shared/icons/open.svg
+++ b/browser/themes/shared/icons/open.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M14.859 3.2a1.335 1.335 0 0 1-1.217.8H13v1h1v8H2V5h8V4h-.642a1.365 1.365 0 0 1-1.325-1.11L6.584 1.538A2 2 0 0 0 5.219 1H2a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V5a2 2 0 0 0-1.141-1.8zM2 3h3.219l1.072 1H2zm7.854-.146L11 1.707V8.5a.5.5 0 0 0 1 0V1.707l1.146 1.146a.5.5 0 1 0 .707-.707l-2-2a.5.5 0 0 0-.707 0l-2 2a.5.5 0 0 0 .707.707z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M14.859 3.2a1.335 1.335 0 0 1-1.217.8H13v1h1v8H2V5h8V4h-.642a1.365 1.365 0 0 1-1.325-1.11L6.584 1.538A2 2 0 0 0 5.219 1H2a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V5a2 2 0 0 0-1.141-1.8zM2 3h3.219l1.072 1H2zm7.854-.146L11 1.707V8.5a.5.5 0 0 0 1 0V1.707l1.146 1.146a.5.5 0 1 0 .707-.707l-2-2a.5.5 0 0 0-.707 0l-2 2a.5.5 0 0 0 .707.707z"/>
 </svg>
--- a/browser/themes/shared/icons/page-action.svg
+++ b/browser/themes/shared/icons/page-action.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill-opacity="context-fill-opacity" fill="context-fill" d="M2 6a2 2 0 1 0 2 2 2 2 0 0 0-2-2zm6 0a2 2 0 1 0 2 2 2 2 0 0 0-2-2zm6 0a2 2 0 1 0 2 2 2 2 0 0 0-2-2z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M2 6a2 2 0 1 0 2 2 2 2 0 0 0-2-2zm6 0a2 2 0 1 0 2 2 2 2 0 0 0-2-2zm6 0a2 2 0 1 0 2 2 2 2 0 0 0-2-2z"/>
 </svg>
--- a/browser/themes/shared/icons/print.svg
+++ b/browser/themes/shared/icons/print.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M14 5h-1V1a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v4H2a2 2 0 0 0-2 2v5h3v3a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-3h3V7a2 2 0 0 0-2-2zM2.5 8a.5.5 0 1 1 .5-.5.5.5 0 0 1-.5.5zm9.5 7H4v-5h8zm0-10H4V1h8zm-6.5 7h4a.5.5 0 0 0 0-1h-4a.5.5 0 1 0 0 1zm0 2h5a.5.5 0 0 0 0-1h-5a.5.5 0 1 0 0 1z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M14 5h-1V1a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v4H2a2 2 0 0 0-2 2v5h3v3a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-3h3V7a2 2 0 0 0-2-2zM2.5 8a.5.5 0 1 1 .5-.5.5.5 0 0 1-.5.5zm9.5 7H4v-5h8zm0-10H4V1h8zm-6.5 7h4a.5.5 0 0 0 0-1h-4a.5.5 0 1 0 0 1zm0 2h5a.5.5 0 0 0 0-1h-5a.5.5 0 1 0 0 1z"/>
 </svg>
--- a/browser/themes/shared/icons/privateBrowsing.svg
+++ b/browser/themes/shared/icons/privateBrowsing.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M12.408 11.992c-1.663 0-2.813-2-4.408-2s-2.844 2-4.408 2C1.54 11.992.025 10.048 0 6.719c-.015-2.068.6-2.727 3.265-2.727S6.709 5.082 8 5.082s2.071-1.091 4.735-1.091 3.28.66 3.265 2.727c-.025 3.33-1.54 5.274-3.592 5.274zM4.572 6.537c-1.619.07-2.286 1.035-2.286 1.273s1.073.909 2.122.909 2.286-.384 2.286-.727a1.9 1.9 0 0 0-2.122-1.455zm6.857 0a1.9 1.9 0 0 0-2.123 1.455c0 .343 1.236.727 2.286.727s2.122-.671 2.122-.909-.667-1.203-2.286-1.273z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M12.408 11.992c-1.663 0-2.813-2-4.408-2s-2.844 2-4.408 2C1.54 11.992.025 10.048 0 6.719c-.015-2.068.6-2.727 3.265-2.727S6.709 5.082 8 5.082s2.071-1.091 4.735-1.091 3.28.66 3.265 2.727c-.025 3.33-1.54 5.274-3.592 5.274zM4.572 6.537c-1.619.07-2.286 1.035-2.286 1.273s1.073.909 2.122.909 2.286-.384 2.286-.727a1.9 1.9 0 0 0-2.122-1.455zm6.857 0a1.9 1.9 0 0 0-2.123 1.455c0 .343 1.236.727 2.286.727s2.122-.671 2.122-.909-.667-1.203-2.286-1.273z"/>
 </svg>
--- a/browser/themes/shared/icons/quit.svg
+++ b/browser/themes/shared/icons/quit.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M8 6a1 1 0 0 0 1-1V1a1 1 0 0 0-2 0v4a1 1 0 0 0 1 1zm3.5-4.032a1 1 0 0 0-1 1.732A4.946 4.946 0 0 1 13 8 5 5 0 0 1 3 8a4.946 4.946 0 0 1 2.5-4.3 1 1 0 0 0-1-1.732 7 7 0 1 0 7.006 0z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M8 6a1 1 0 0 0 1-1V1a1 1 0 0 0-2 0v4a1 1 0 0 0 1 1zm3.5-4.032a1 1 0 0 0-1 1.732A4.946 4.946 0 0 1 13 8 5 5 0 0 1 3 8a4.946 4.946 0 0 1 2.5-4.3 1 1 0 0 0-1-1.732 7 7 0 1 0 7.006 0z"/>
 </svg>
--- a/browser/themes/shared/icons/reload-to-stop.svg
+++ b/browser/themes/shared/icons/reload-to-stop.svg
@@ -1,12 +1,12 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg xmlns="http://www.w3.org/2000/svg" width="468" height="20" fill="context-fill">
+<svg xmlns="http://www.w3.org/2000/svg" width="468" height="20" fill="context-fill" fill-opacity="context-fill-opacity">
   <path d="M10.414 10l5.293-5.293a1 1 0 0 0-1.414-1.414L9 8.586 3.707 3.293a1 1 0 0 0-1.414 1.414L7.586 10l-5.293 5.293a1 1 0 1 0 1.414 1.414L9 11.414l5.293 5.293a1 1 0 0 0 1.414-1.414z"/>
   <svg x="18">
     <path d="M10.414 10l5.293-5.293a1 1 0 0 0-1.414-1.414L9 8.586 3.707 3.293a1 1 0 0 0-1.414 1.414L7.586 10l-5.293 5.293a1 1 0 1 0 1.414 1.414L9 11.414l5.293 5.293a1 1 0 0 0 1.414-1.414z"/>
   </svg>
   <svg x="36">
     <path d="M10.414 10l5.293-5.293a1 1 0 0 0-1.414-1.414L9 8.586 3.707 3.293a1 1 0 0 0-1.414 1.414L7.586 10l-5.293 5.293a1 1 0 1 0 1.414 1.414L9 11.414l5.293 5.293a1 1 0 0 0 1.414-1.414z"/>
   </svg>
   <svg x="54">
--- a/browser/themes/shared/icons/reload.svg
+++ b/browser/themes/shared/icons/reload.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M15,1a1,1,0,0,0-1,1V4.418A6.995,6.995,0,1,0,8,15a6.954,6.954,0,0,0,4.95-2.05,1,1,0,0,0-1.414-1.414A5.019,5.019,0,1,1,12.549,6H10a1,1,0,0,0,0,2h5a1,1,0,0,0,1-1V2A1,1,0,0,0,15,1Z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M15,1a1,1,0,0,0-1,1V4.418A6.995,6.995,0,1,0,8,15a6.954,6.954,0,0,0,4.95-2.05,1,1,0,0,0-1.414-1.414A5.019,5.019,0,1,1,12.549,6H10a1,1,0,0,0,0,2h5a1,1,0,0,0,1-1V2A1,1,0,0,0,15,1Z"/>
 </svg>
--- a/browser/themes/shared/icons/restore-session.svg
+++ b/browser/themes/shared/icons/restore-session.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill">
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill" fill-opacity="context-fill-opacity">
   <path d="M13 0H3a3 3 0 0 0-3 3v8a3 3 0 0 0 3 3h4l-.3.4a1 1 0 1 0 1.6 1.2l1.5-2a1 1 0 0 0 0-1.2l-1.5-2a1 1 0 0 0-1.6 1.2l.3.4H3a1 1 0 0 1-1-1V5h12v6a1 1 0 0 1-1 1 1 1 0 0 0 0 2 3 3 0 0 0 3-3V3a3 3 0 0 0-3-3zM2 4V3a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v1z"/>
 </svg>
--- a/browser/themes/shared/icons/save.svg
+++ b/browser/themes/shared/icons/save.svg
@@ -1,7 +1,7 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill">
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill" fill-opacity="context-fill-opacity">
   <path d="M14 3h-2v2h2v8H2V5h7V3h-.849L6.584 1.538A2 2 0 0 0 5.219 1H2a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2zM2 3h3.219l1.072 1H2z"/>
   <path d="M8.146 6.146a.5.5 0 0 0 0 .707l2 2a.5.5 0 0 0 .707 0l2-2a.5.5 0 1 0-.707-.707L11 7.293V.5a.5.5 0 0 0-1 0v6.793L8.854 6.146a.5.5 0 0 0-.708 0z"/>
 </svg>
--- a/browser/themes/shared/icons/settings.svg
+++ b/browser/themes/shared/icons/settings.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M15 7h-2.1a4.967 4.967 0 0 0-.732-1.753l1.49-1.49a1 1 0 0 0-1.414-1.414l-1.49 1.49A4.968 4.968 0 0 0 9 3.1V1a1 1 0 0 0-2 0v2.1a4.968 4.968 0 0 0-1.753.732l-1.49-1.49a1 1 0 0 0-1.414 1.415l1.49 1.49A4.967 4.967 0 0 0 3.1 7H1a1 1 0 0 0 0 2h2.1a4.968 4.968 0 0 0 .737 1.763c-.014.013-.032.017-.045.03l-1.45 1.45a1 1 0 1 0 1.414 1.414l1.45-1.45c.013-.013.018-.031.03-.045A4.968 4.968 0 0 0 7 12.9V15a1 1 0 0 0 2 0v-2.1a4.968 4.968 0 0 0 1.753-.732l1.49 1.49a1 1 0 0 0 1.414-1.414l-1.49-1.49A4.967 4.967 0 0 0 12.9 9H15a1 1 0 0 0 0-2zM5 8a3 3 0 1 1 3 3 3 3 0 0 1-3-3z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M15 7h-2.1a4.967 4.967 0 0 0-.732-1.753l1.49-1.49a1 1 0 0 0-1.414-1.414l-1.49 1.49A4.968 4.968 0 0 0 9 3.1V1a1 1 0 0 0-2 0v2.1a4.968 4.968 0 0 0-1.753.732l-1.49-1.49a1 1 0 0 0-1.414 1.415l1.49 1.49A4.967 4.967 0 0 0 3.1 7H1a1 1 0 0 0 0 2h2.1a4.968 4.968 0 0 0 .737 1.763c-.014.013-.032.017-.045.03l-1.45 1.45a1 1 0 1 0 1.414 1.414l1.45-1.45c.013-.013.018-.031.03-.045A4.968 4.968 0 0 0 7 12.9V15a1 1 0 0 0 2 0v-2.1a4.968 4.968 0 0 0 1.753-.732l1.49 1.49a1 1 0 0 0 1.414-1.414l-1.49-1.49A4.967 4.967 0 0 0 12.9 9H15a1 1 0 0 0 0-2zM5 8a3 3 0 1 1 3 3 3 3 0 0 1-3-3z"/>
 </svg>
--- a/browser/themes/shared/icons/sidebars-right.svg
+++ b/browser/themes/shared/icons/sidebars-right.svg
@@ -1,7 +1,7 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill">
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill" fill-opacity="context-fill-opacity">
   <path d="M13 1H3a3.007 3.007 0 0 0-3 3v8a3.009 3.009 0 0 0 3 3h10a3.005 3.005 0 0 0 3-3V4a3.012 3.012 0 0 0-3-3zM2 12V4a1 1 0 0 1 1-1h5v10H3a1 1 0 0 1-1-1zm12 0a1 1 0 0 1-1 1H9V3h4a1 1 0 0 1 1 1z"/>
   <path d="M12.5 5h-2a.5.5 0 0 1 0-1h2a.5.5 0 0 1 0 1zm0 2h-2a.5.5 0 0 1 0-1h2a.5.5 0 0 1 0 1zm-1 2h-1a.5.5 0 0 1 0-1h1a.5.5 0 0 1 0 1z"/>
 </svg>
--- a/browser/themes/shared/icons/sidebars.svg
+++ b/browser/themes/shared/icons/sidebars.svg
@@ -1,7 +1,7 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill">
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill" fill-opacity="context-fill-opacity">
   <path d="M3 1h10c1.655.004 2.996 1.345 3 3v8c-.005 1.655-1.345 2.995-3 3H3c-1.656-.003-2.997-1.344-3-3V4c.007-1.654 1.346-2.993 3-3zm11 11V4c0-.552-.448-1-1-1H8v10h5c.552 0 1-.448 1-1zM2 12c0 .552.448 1 1 1h4V3H3c-.552 0-1 .448-1 1v8z"/>
   <path d="M3.5 5h2c.276 0 .5-.224.5-.5S5.776 4 5.5 4h-2c-.276 0-.5.224-.5.5s.224.5.5.5zm0 2h2c.276 0 .5-.224.5-.5S5.776 6 5.5 6h-2c-.276 0-.5.224-.5.5s.224.5.5.5zm1 2h1c.276 0 .5-.224.5-.5S5.776 8 5.5 8h-1c-.276 0-.5.224-.5.5s.224.5.5.5z"/>
 </svg>
--- a/browser/themes/shared/icons/stop-to-reload.svg
+++ b/browser/themes/shared/icons/stop-to-reload.svg
@@ -1,12 +1,12 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg xmlns="http://www.w3.org/2000/svg" width="468" height="20" fill="context-fill">
+<svg xmlns="http://www.w3.org/2000/svg" width="468" height="20" fill="context-fill" fill-opacity="context-fill-opacity">
   <path d="M13.55 8H11a1 1 0 0 0 0 2h5a1 1 0 0 0 1-1V4a1 1 0 0 0-2 0v2.418"/>
   <path d="M15 6.418C13.02 3.1 8.724 2.018 5.408 4c-3.317 1.98-4.4 6.275-2.42 9.592A6.997 6.997 0 0 0 9 17a6.954 6.954 0 0 0 4.95-2.05 1 1 0 1 0-1.414-1.414A5.02 5.02 0 1 1 13.55 8"/>
   <svg x="18">
     <path d="M13.735 8.606l-1.72-.78a.74.74 0 0 0-.61 1.35l3.37 1.53a.74.74 0 0 0 .98-.37l1.532-3.372a.74.74 0 0 0-1.35-.612l-.74 1.63"/>
     <path d="M15.91 8.954c-.58-3.82-4.146-6.446-7.965-5.867-3.82.58-6.447 4.144-5.868 7.964a6.997 6.997 0 0 0 4.275 5.43 6.954 6.954 0 0 0 5.357-.025 1 1 0 1 0-.775-1.844 5.02 5.02 0 1 1 3.032-4.74"/>
   </svg>
   <svg x="36">
     <path d="M14.088 9.318l-.89-.845a.482.482 0 0 0-.663.7l1.747 1.656a.482.482 0 0 0 .68-.02l1.657-1.746a.482.482 0 0 0-.7-.662l-.8.844"/>
--- a/browser/themes/shared/icons/stop.svg
+++ b/browser/themes/shared/icons/stop.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M9.414 8l5.293-5.293a1 1 0 0 0-1.414-1.414L8 6.586 2.707 1.293a1 1 0 0 0-1.414 1.414L6.586 8l-5.293 5.293a1 1 0 1 0 1.414 1.414L8 9.414l5.293 5.293a1 1 0 0 0 1.414-1.414z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M9.414 8l5.293-5.293a1 1 0 0 0-1.414-1.414L8 6.586 2.707 1.293a1 1 0 0 0-1.414 1.414L6.586 8l-5.293 5.293a1 1 0 1 0 1.414 1.414L8 9.414l5.293 5.293a1 1 0 0 0 1.414-1.414z"/>
 </svg>
--- a/browser/themes/shared/icons/sync.svg
+++ b/browser/themes/shared/icons/sync.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M14 1a1 1 0 0 0-1 1v1.146A6.948 6.948 0 0 0 1.227 6.307a1 1 0 1 0 1.94.484A4.983 4.983 0 0 1 8 3a4.919 4.919 0 0 1 3.967 2H10a1 1 0 0 0 0 2h4a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1zm.046 7.481a1 1 0 0 0-1.213.728A4.983 4.983 0 0 1 8 13a4.919 4.919 0 0 1-3.967-2H6a1 1 0 0 0 0-2H2a1 1 0 0 0-1 1v4a1 1 0 0 0 2 0v-1.146a6.948 6.948 0 0 0 11.773-3.161 1 1 0 0 0-.727-1.212z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M14 1a1 1 0 0 0-1 1v1.146A6.948 6.948 0 0 0 1.227 6.307a1 1 0 1 0 1.94.484A4.983 4.983 0 0 1 8 3a4.919 4.919 0 0 1 3.967 2H10a1 1 0 0 0 0 2h4a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1zm.046 7.481a1 1 0 0 0-1.213.728A4.983 4.983 0 0 1 8 13a4.919 4.919 0 0 1-3.967-2H6a1 1 0 0 0 0-2H2a1 1 0 0 0-1 1v4a1 1 0 0 0 2 0v-1.146a6.948 6.948 0 0 0 11.773-3.161 1 1 0 0 0-.727-1.212z"/>
 </svg>
--- a/browser/themes/shared/icons/synced-tabs.svg
+++ b/browser/themes/shared/icons/synced-tabs.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M15 11h-1V5a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v6H1a1 1 0 0 0 0 2h14a1 1 0 1 0 0-2z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M15 11h-1V5a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v6H1a1 1 0 0 0 0 2h14a1 1 0 1 0 0-2z"/>
 </svg>
--- a/browser/themes/shared/icons/toolbar.svg
+++ b/browser/themes/shared/icons/toolbar.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M13 1H3a3.007 3.007 0 0 0-3 3v8a3.009 3.009 0 0 0 3 3h10a3.005 3.005 0 0 0 3-3V4a3.012 3.012 0 0 0-3-3zM3 3h10a1 1 0 0 1 1 1v1H2V4a1 1 0 0 1 1-1zm11 3v1H2V6zm-1 7H3a1 1 0 0 1-1-1V8h12v4a1 1 0 0 1-1 1z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M13 1H3a3.007 3.007 0 0 0-3 3v8a3.009 3.009 0 0 0 3 3h10a3.005 3.005 0 0 0 3-3V4a3.012 3.012 0 0 0-3-3zM3 3h10a1 1 0 0 1 1 1v1H2V4a1 1 0 0 1 1-1zm11 3v1H2V6zm-1 7H3a1 1 0 0 1-1-1V8h12v4a1 1 0 0 1-1 1z"/>
 </svg>
--- a/browser/themes/shared/icons/webIDE.svg
+++ b/browser/themes/shared/icons/webIDE.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M9.884 13.209l-2.121-2.122 6.176-6.148L16.06 7.06zM11.46 5c.02.1.019.217.037.32l-.875.9A10.929 10.929 0 0 0 10.456 5H8v2h1.856L8.88 8H8v.9L7 9.925V8H4.322a12.382 12.382 0 0 0 .222 2h2.383l-.977 1H4.808a7.92 7.92 0 0 0 .342.887l-.837 2.379A7.486 7.486 0 1 1 13.6 3.164L11.809 5zm-6.832 7.966A8.619 8.619 0 0 1 3.79 11H2.362a6.111 6.111 0 0 0 2.266 1.966zM1.813 10H3.54a12.64 12.64 0 0 1-.23-2H1.332a6.184 6.184 0 0 0 .481 2zm0-5a6.184 6.184 0 0 0-.481 2H3.31a12.64 12.64 0 0 1 .23-2zm.549-1H3.79a8.619 8.619 0 0 1 .838-1.966A6.111 6.111 0 0 0 2.362 4zM7 1.332a6.216 6.216 0 0 0-.669.13A5.269 5.269 0 0 0 4.808 4H7zM7 5H4.544a12.382 12.382 0 0 0-.222 2H7zm1.669-3.538A6.209 6.209 0 0 0 8 1.332V4h2.192a5.268 5.268 0 0 0-1.523-2.538zm1.7.573A8.619 8.619 0 0 1 11.21 4h1.428a6.111 6.111 0 0 0-2.266-1.966zM9.034 14.148L5 16l1.863-4.024zm1.8.039l3.239-3.14a7.483 7.483 0 0 1-3.241 3.14z" fill-rule="evenodd"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M9.884 13.209l-2.121-2.122 6.176-6.148L16.06 7.06zM11.46 5c.02.1.019.217.037.32l-.875.9A10.929 10.929 0 0 0 10.456 5H8v2h1.856L8.88 8H8v.9L7 9.925V8H4.322a12.382 12.382 0 0 0 .222 2h2.383l-.977 1H4.808a7.92 7.92 0 0 0 .342.887l-.837 2.379A7.486 7.486 0 1 1 13.6 3.164L11.809 5zm-6.832 7.966A8.619 8.619 0 0 1 3.79 11H2.362a6.111 6.111 0 0 0 2.266 1.966zM1.813 10H3.54a12.64 12.64 0 0 1-.23-2H1.332a6.184 6.184 0 0 0 .481 2zm0-5a6.184 6.184 0 0 0-.481 2H3.31a12.64 12.64 0 0 1 .23-2zm.549-1H3.79a8.619 8.619 0 0 1 .838-1.966A6.111 6.111 0 0 0 2.362 4zM7 1.332a6.216 6.216 0 0 0-.669.13A5.269 5.269 0 0 0 4.808 4H7zM7 5H4.544a12.382 12.382 0 0 0-.222 2H7zm1.669-3.538A6.209 6.209 0 0 0 8 1.332V4h2.192a5.268 5.268 0 0 0-1.523-2.538zm1.7.573A8.619 8.619 0 0 1 11.21 4h1.428a6.111 6.111 0 0 0-2.266-1.966zM9.034 14.148L5 16l1.863-4.024zm1.8.039l3.239-3.14a7.483 7.483 0 0 1-3.241 3.14z" fill-rule="evenodd"/>
 </svg>
--- a/browser/themes/shared/icons/window.svg
+++ b/browser/themes/shared/icons/window.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M13 1H3a3 3 0 0 0-3 3v8a3 3 0 0 0 3 3h11a2 2 0 0 0 2-2V4a3 3 0 0 0-3-3zm1 11a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V6h12zm0-7H2V4a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M13 1H3a3 3 0 0 0-3 3v8a3 3 0 0 0 3 3h11a2 2 0 0 0 2-2V4a3 3 0 0 0-3-3zm1 11a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V6h12zm0-7H2V4a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1z"/>
 </svg>
--- a/browser/themes/shared/icons/zoom-in.svg
+++ b/browser/themes/shared/icons/zoom-in.svg
@@ -1,7 +1,7 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="context-fill">
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="context-fill" fill-opacity="context-fill-opacity">
   <path d="M14 7H9V2a1 1 0 0 0-2 0v5H2a1 1 0 0 0 0 2h5v5a1 1 0 0 0 2 0V9h5a1 1 0 0 0 0-2z"/>
 </svg>
 
--- a/browser/themes/shared/icons/zoom-out.svg
+++ b/browser/themes/shared/icons/zoom-out.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="context-fill">
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="context-fill" fill-opacity="context-fill-opacity">
   <rect x="2" y="7" width="12" height="2" rx="1"/>
 </svg>
--- a/browser/themes/shared/jar.inc.mn
+++ b/browser/themes/shared/jar.inc.mn
@@ -130,17 +130,16 @@
   skin/classic/browser/customize.svg                  (../shared/icons/customize.svg)
   skin/classic/browser/developer.svg                  (../shared/icons/developer.svg)
   skin/classic/browser/device-mobile.svg              (../shared/icons/device-mobile.svg)
   skin/classic/browser/device-tablet.svg              (../shared/icons/device-tablet.svg)
   skin/classic/browser/device-desktop.svg             (../shared/icons/device-desktop.svg)
   skin/classic/browser/edit-copy.svg                  (../shared/icons/edit-copy.svg)
   skin/classic/browser/edit-cut.svg                   (../shared/icons/edit-cut.svg)
   skin/classic/browser/edit-paste.svg                 (../shared/icons/edit-paste.svg)
-  skin/classic/browser/email-link.svg                 (../shared/icons/email-link.svg)
   skin/classic/browser/feed.svg                       (../shared/icons/feed.svg)
   skin/classic/browser/find.svg                       (../shared/icons/find.svg)
   skin/classic/browser/folder.svg                     (../shared/icons/folder.svg)
   skin/classic/browser/forget.svg                     (../shared/icons/forget.svg)
   skin/classic/browser/forward.svg                    (../shared/icons/forward.svg)
   skin/classic/browser/fullscreen.svg                 (../shared/icons/fullscreen.svg)
   skin/classic/browser/fullscreen-exit.svg            (../shared/icons/fullscreen-exit.svg)
   skin/classic/browser/history.svg                    (../shared/icons/history.svg)
--- a/browser/themes/shared/tabbrowser/newtab.svg
+++ b/browser/themes/shared/tabbrowser/newtab.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill">
+<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
   <path d="M14 7H9V2a1 1 0 0 0-2 0v5H2a1 1 0 1 0 0 2h5v5a1 1 0 0 0 2 0V9h5a1 1 0 0 0 0-2z"/>
 </svg>
--- a/browser/themes/shared/tabs.inc.css
+++ b/browser/themes/shared/tabs.inc.css
@@ -391,16 +391,20 @@
   transition: opacity 150ms ease;
 }
 
 .tabbrowser-tab:not([visuallyselected=true]),
 .tabbrowser-tab:-moz-lwtheme {
   color: inherit;
 }
 
+.tabbrowser-tab[visuallyselected=true]:-moz-lwtheme {
+  color: var(--toolbar-color, inherit);
+}
+
 .tab-line {
   height: 2px;
 }
 
 /* Selected tab */
 
 .tab-background {
   border: 1px none transparent;
@@ -545,18 +549,19 @@
   display: -moz-box;
 }
 
 /* Tab bar scroll arrows */
 
 .tabbrowser-arrowscrollbox > .scrollbutton-up,
 .tabbrowser-arrowscrollbox > .scrollbutton-down {
   list-style-image: url(chrome://browser/skin/arrow-left.svg);
-  -moz-context-properties: fill;
+  -moz-context-properties: fill, fill-opacity;
   fill: currentColor;
+  fill-opacity: .8;
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-up:-moz-locale-dir(rtl),
 .tabbrowser-arrowscrollbox > .scrollbutton-down:-moz-locale-dir(ltr) {
   transform: scaleX(-1);
 }
 
 /* New tab button */
--- a/browser/themes/shared/toolbarbutton-icons.inc.css
+++ b/browser/themes/shared/toolbarbutton-icons.inc.css
@@ -1,26 +1,26 @@
 :root {
   --toolbarbutton-icon-fill-attention: #0a84ff;
 }
 
+:root:-moz-lwtheme {
+  --toolbarbutton-icon-fill-opacity: 1;
+}
+
 toolbar[brighttext] {
   --toolbarbutton-icon-fill-attention: #45a1ff;
 }
 
 .toolbarbutton-animatable-box,
 .toolbarbutton-1 {
-  -moz-context-properties: fill;
-  fill: #4c4c4c;
-}
-
-.toolbarbutton-animatable-box[brighttext],
-toolbar[brighttext] .toolbarbutton-animatable-box,
-toolbar[brighttext] .toolbarbutton-1 {
-  fill: #fff;
+  color: inherit;
+  -moz-context-properties: fill, fill-opacity;
+  fill: currentColor;
+  fill-opacity: var(--toolbarbutton-icon-fill-opacity);
 }
 
 #back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
 #forward-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
 #reload-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
 #nav-bar-overflow-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
 #PlacesChevron:-moz-locale-dir(rtl) > .toolbarbutton-icon,
 #panic-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
@@ -305,45 +305,51 @@ toolbar[brighttext] .toolbarbutton-1 {
 }
 
 @keyframes overflow-animation {
   from {
     transform: translateX(0);
   }
   50% {
     fill: var(--toolbarbutton-icon-fill-attention);
+    fill-opacity: 1;
   }
   to {
     transform: translateX(-1260px);
     fill: var(--toolbarbutton-icon-fill-attention);
+    fill-opacity: 1;
   }
 }
 
 @keyframes overflow-animation-rtl {
   from {
     transform: scaleX(-1) translateX(0);
   }
   50% {
     fill: var(--toolbarbutton-icon-fill-attention);
+    fill-opacity: 1;
   }
   to {
     transform: scaleX(-1) translateX(-1260px);
     fill: var(--toolbarbutton-icon-fill-attention);
+    fill-opacity: 1;
   }
 }
 
 /* The animation is supposed to show the blue fill color for 520ms, then the
    fade to the toolbarbutton-fill color for the remaining 210ms. Thus with an
    animation-duration of 730ms, 71% is the point where we start the fade out. */
 @keyframes overflow-fade {
   from {
     fill: var(--toolbarbutton-icon-fill-attention);
+    fill-opacity: 1;
   }
   71% {
     fill: var(--toolbarbutton-icon-fill-attention);
+    fill-opacity: 1;
   }
   to {
     fill: inherit;
   }
 }
 
 #nav-bar-overflow-button > .toolbarbutton-animatable-box {
   position: absolute;
@@ -420,43 +426,48 @@ toolbar[brighttext] .toolbarbutton-1 {
     transform: translateX(0);
     fill: inherit;
   }
   25% {
     fill: inherit;
   }
   50% {
     fill: var(--toolbarbutton-icon-fill-attention);
+    fill-opacity: 1;
   }
   to {
     transform: translateX(-1056px);
     fill: var(--toolbarbutton-icon-fill-attention);
+    fill-opacity: 1;
   }
 }
 
 @keyframes library-bookmark-animation-rtl {
   from {
     transform: translateX(1056px);
     fill: inherit;
   }
   25% {
     fill: inherit;
   }
   50% {
     fill: var(--toolbarbutton-icon-fill-attention);
+    fill-opacity: 1;
   }
   to {
     transform: translateX(0);
     fill: var(--toolbarbutton-icon-fill-attention);
+    fill-opacity: 1;
   }
 }
 
 @keyframes library-bookmark-fade {
   from {
     fill: var(--toolbarbutton-icon-fill-attention);
+    fill-opacity: 1;
   }
   to {
     fill: inherit;
   }
 }
 
 #library-button[animate] > .toolbarbutton-icon {
   fill: transparent;
@@ -489,17 +500,17 @@ toolbar[brighttext] .toolbarbutton-1 {
 }
 
 .toolbarbutton-animatable-box[animate="bookmark"] > .toolbarbutton-animatable-image {
   background-image: url("chrome://browser/skin/library-bookmark-animation.svg");
   width: 1078px;
   animation-name: library-bookmark-animation;
   animation-duration: 800ms;
   animation-timing-function: steps(48);
-  -moz-context-properties: fill, stroke;
+  -moz-context-properties: fill, fill-opacity, stroke;
   stroke: var(--toolbarbutton-icon-fill-attention);
 }
 
 .toolbarbutton-animatable-box[animate="bookmark"]:-moz-locale-dir(rtl) > .toolbarbutton-animatable-image {
   animation-name: library-bookmark-animation-rtl;
 }
 
 .toolbarbutton-animatable-box[animate="bookmark"][fade] > .toolbarbutton-animatable-image {
--- a/browser/themes/shared/urlbar-searchbar.inc.css
+++ b/browser/themes/shared/urlbar-searchbar.inc.css
@@ -84,17 +84,17 @@
 
 #pageAction-panel-copyURL,
 #pageAction-urlbar-copyURL {
   list-style-image: url("chrome://browser/skin/link.svg");
 }
 
 #pageAction-panel-emailLink,
 #pageAction-urlbar-emailLink {
-  list-style-image: url("chrome://browser/skin/email-link.svg");
+  list-style-image: url("chrome://browser/skin/mail.svg");
 }
 
 #pageAction-panel-sendToDevice,
 #pageAction-urlbar-sendToDevice {
   list-style-image: url("chrome://browser/skin/device-mobile.svg");
 }
 
 .pageAction-sendToDevice-device[clientType=mobile] {
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -17,16 +17,17 @@
   --toolbar-non-lwt-bgcolor: -moz-dialog;
   --toolbar-non-lwt-textcolor: -moz-dialogtext;
   --toolbar-non-lwt-bgimage: linear-gradient(rgba(255,255,255,.15), rgba(255,255,255,.15));
   --toolbar-bgcolor: var(--toolbar-non-lwt-bgcolor);
   --toolbar-bgimage: var(--toolbar-non-lwt-bgimage);
 
   --toolbarbutton-vertical-text-padding: calc(var(--toolbarbutton-inner-padding) - 1px);
   --toolbarbutton-border-radius: 2px;
+  --toolbarbutton-icon-fill-opacity: 1;
 
   --panel-separator-color: ThreeDLightShadow;
   --arrowpanel-dimmed: hsla(0,0%,80%,.3);
   --arrowpanel-dimmed-further: hsla(0,0%,80%,.45);
   --arrowpanel-dimmed-even-further: hsla(0,0%,80%,.8);
 
   --urlbar-separator-color: ThreeDLightShadow;
 
@@ -36,16 +37,18 @@
 @media (-moz-windows-default-theme) {
   :root {
     --tabs-border: rgba(0,0,0,.3);
 
     --toolbar-non-lwt-bgcolor: #f9f9fa;
     --toolbar-non-lwt-textcolor: #0c0c0d;
     --toolbar-non-lwt-bgimage: none;
 
+    --toolbarbutton-icon-fill-opacity: .7;
+
     --panel-separator-color: hsla(210,4%,10%,.14);
 
     --toolbox-border-bottom-color: #e1e1e2;
   }
 }
 
 :root:-moz-lwtheme {
   --tabs-border: rgba(0,0,0,.3);
@@ -79,16 +82,17 @@
 #navigator-toolbox > toolbar {
   -moz-appearance: none;
 }
 
 #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar) {
   background-color: var(--toolbar-bgcolor);
   background-image: var(--toolbar-bgimage);
   background-clip: padding-box;
+  color: var(--toolbar-color, inherit);
 }
 
 #toolbar-menubar,
 #TabsToolbar {
   color: var(--titlebar-text-color);
 }
 
 @media (-moz-windows-compositor: 0),
--- a/devtools/client/netmonitor/src/assets/styles/netmonitor.css
+++ b/devtools/client/netmonitor/src/assets/styles/netmonitor.css
@@ -780,16 +780,21 @@ body,
 .panel-container,
 .properties-view {
   display: flex;
   flex-direction: column;
   overflow-x: hidden;
   overflow-y: auto;
 }
 
+.panel-container .tree-container .objectBox {
+  white-space: normal;
+  word-wrap: break-word;
+}
+
 .properties-view {
   flex-grow: 1;
 }
 
 .properties-view .searchbox-section {
   flex: 0 1 auto;
 }
 
--- a/devtools/client/netmonitor/src/components/properties-view.js
+++ b/devtools/client/netmonitor/src/components/properties-view.js
@@ -45,25 +45,27 @@ const PropertiesView = createClass({
 
   propTypes: {
     object: PropTypes.object,
     enableInput: PropTypes.bool,
     expandableStrings: PropTypes.bool,
     filterPlaceHolder: PropTypes.string,
     sectionNames: PropTypes.array,
     openLink: PropTypes.func,
+    cropLimit: PropTypes.number
   },
 
   getDefaultProps() {
     return {
       enableInput: true,
       enableFilter: true,
       expandableStrings: false,
       filterPlaceHolder: "",
       sectionNames: [],
+      cropLimit: 1024
     };
   },
 
   getInitialState() {
     return {
       filterText: "",
     };
   },
@@ -116,20 +118,20 @@ const PropertiesView = createClass({
     // Put 2 here to not dup this method
     if (member.level === 0 && member.type === "object" ||
       (typeof member.value === "object" && member.value && member.value.value)) {
       return null;
     }
 
     return Rep(Object.assign(props, {
       // FIXME: A workaround for the issue in StringRep
-      // Force StringRep to crop the text everytime
+      // Force StringRep to crop the text every time
       member: Object.assign({}, member, { open: false }),
       mode: MODE.TINY,
-      cropLimit: 60,
+      cropLimit: this.props.cropLimit,
     }));
   },
 
   shouldRenderSearchBox(object) {
     return this.props.enableFilter && object && Object.keys(object)
       .filter((section) => !object[section][EDITOR_CONFIG_ID]).length > 0;
   },
 
--- a/devtools/client/shared/components/reps/reps.css
+++ b/devtools/client/shared/components/reps/reps.css
@@ -1,24 +1,25 @@
 /* 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/. */
 
 .theme-dark,
 .theme-light {
   --number-color: var(--theme-highlight-green);
-  --string-color: var(--theme-highlight-orange);
+  --string-color: var(--theme-highlight-red);
   --null-color: var(--theme-comment);
-  --object-color: var(--theme-body-color);
+  --object-color: var(--theme-highlight-blue);
   --caption-color: var(--theme-highlight-blue);
-  --location-color: var(--theme-content-color1);
+  --location-color: var(--theme-comment);
   --source-link-color: var(--theme-highlight-blue);
-  --node-color: var(--theme-highlight-bluegrey);
-  --reference-color: var(--theme-highlight-purple);
+  --node-color: var(--theme-highlight-purple);
+  --reference-color: var(--theme-highlight-blue);
+  --comment-node-color: var(--theme-comment);
 }
 
 .theme-firebug {
   --number-color: #000088;
   --string-color: #FF0000;
   --null-color: #787878;
   --object-color: DarkGreen;
   --caption-color: #444444;
@@ -68,26 +69,26 @@
 }
 
 .objectBox-function,
 .objectBox-stackTrace,
 .objectBox-profile {
   color: var(--object-color);
 }
 
-.objectBox-Location {
-  font-style: italic;
+.objectBox-Location,
+.location {
   color: var(--location-color);
 }
 
 .objectBox-null,
 .objectBox-undefined,
 .objectBox-hint,
+.objectBox-nan,
 .logRowHint {
-  font-style: italic;
   color: var(--null-color);
 }
 
 .objectBox-sourceLink {
   position: absolute;
   right: 4px;
   top: 2px;
   padding-left: 8px;
@@ -104,62 +105,77 @@
   padding: 0 2px;
 }
 
 /******************************************************************************/
 
 .objectBox-event,
 .objectBox-eventLog,
 .objectBox-regexp,
-.objectBox-object,
-.objectBox-Date {
-  font-weight: bold;
+.objectBox-object {
   color: var(--object-color);
   white-space: pre-wrap;
 }
 
+.objectBox .Date {
+  color: var(--string-color);
+  white-space: pre-wrap;
+}
+
 /******************************************************************************/
 
-.objectBox-object .nodeName,
-.objectBox-NamedNodeMap .nodeName,
-.objectBox-NamedNodeMap .objectEqual,
-.objectBox-Attr .attrEqual,
-.objectBox-Attr .attrTitle {
+.objectBox.theme-comment {
+  color: var(--comment-node-color);
+}
+
+.tag-name {
+  color: var(--object-color);
+}
+
+.attrName {
+  color: var(--string-color);
+}
+
+.attrEqual,
+.objectEqual {
+  color: var(--comment-node-color);
+}
+
+.attrValue,
+.attrValue.objectBox-string {
   color: var(--node-color);
 }
 
-.objectBox-object .nodeName {
-  font-weight: normal;
+.angleBracket {
+  color: var(--theme-body-color);
 }
 
 /******************************************************************************/
 
 .objectLeftBrace,
 .objectRightBrace,
 .arrayLeftBracket,
 .arrayRightBracket {
-  color: var(--theme-highlight-blue);
+  color: var(--object-color);
 }
 
 /******************************************************************************/
 /* Cycle reference*/
 
 .objectBox-Reference {
   font-weight: bold;
   color: var(--reference-color);
 }
 
-[class*="objectBox-"] > .objectTitle {
-  color: var(--theme-highlight-blue);
-  font-style: italic;
+[class*="objectBox"] > .objectTitle {
+  color: var(--object-color);
 }
 
 .caption {
-  font-weight: bold;
-  color:  var(--caption-color);
+  color: var(--caption-color);
 }
 
 /******************************************************************************/
 /* Themes */
 
 .theme-dark .objectBox-null,
 .theme-dark .objectBox-undefined,
 .theme-light .objectBox-null,
@@ -177,40 +193,50 @@
 .theme-light .caption {
   font-weight: normal;
 }
 
 /******************************************************************************/
 /* Open DOMNode in inspector button */
 
 .open-inspector svg {
-  fill: rgb(215, 215, 215);
+  fill: var(--comment-node-color);
   height: 16px;
   width: 16px;
   margin-left: .25em;
   cursor: pointer;
   vertical-align: middle;
 }
 
 .objectBox-node:hover .open-inspector svg,
 .objectBox-textNode:hover .open-inspector svg,
 .open-inspector svg:hover {
-  fill: rgb(65, 175, 230);
+  fill: var(--theme-highlight-blue);
 }
 
 /******************************************************************************/
 /* "more…" ellipsis */
 .more-ellipsis {
-  color: var(--theme-comment);
+  color: var(--comment-node-color);
 }
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 .tree {
+  --arrow-width: 10px;
+  --arrow-single-margin: 5px;
+  --arrow-total-width: calc(var(--arrow-width) + var(--arrow-single-margin));
+  --arrow-fill-color: var(--theme-splitter-color, #9B9B9B);
+  --tree-indent-width: 1em;
+  --tree-indent-border-color: #A2D1FF;
+  --tree-indent-border-width: 1px;
+  --tree-node-hover-background-color: #F0F9FE;
+  --tree-node-focus-color: white;
+  --tree-node-focus-background-color: var(--theme-selection-background, #0a84ff);
   overflow: auto;
 }
 
 .tree.inline {
   display: inline-block;
 }
 
 .tree.nowrap {
@@ -224,49 +250,62 @@
   -o-user-select: none;
   user-select: none;
 }
 
 .tree button {
   display: block;
 }
 
-.tree .node {
-  padding: 0 0.25em;
-  position: relative;
+.tree .tree-node {
   cursor: pointer;
 }
 
-.tree .node.focused {
-  color: white;
-  background-color: var(--theme-selection-background);
+.tree .tree-node:not(.focused):hover {
+  background-color: var(--tree-node-hover-background-color);
+}
+
+.tree .tree-node.focused {
+  color: var(--tree-node-focus-color);
+  background-color: var(--tree-node-focus-background-color);
+  --arrow-fill-color: currentColor;
 }
 
 .arrow svg {
-  fill: var(--theme-splitter-color);
+  fill: var(--arrow-fill-color);
   transition: transform 0.125s ease;
-  width: 10px;
-  margin-inline-end: 5px;
+  width: var(--arrow-width);
+  margin-inline-end: var(--arrow-single-margin);
   transform: rotate(-90deg);
 }
 
 html[dir="rtl"] .arrow svg,
 .arrow svg:dir(rtl),
 .arrow svg:-moz-locale-dir(rtl) {
   transform: rotate(90deg);
 }
 
 .arrow.expanded.expanded svg {
   transform: rotate(0deg);
 }
+/* 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/. */
 
-.object-label, .object-label * {
+.tree.object-inspector .object-label,
+.tree.object-inspector .object-label * {
   color: var(--theme-highlight-blue);
 }
 
-.tree .node .unavailable {
-  color: var(--theme-content-color3);
+.tree.object-inspector .node .unavailable {
+  color: var(--theme-comment);
 }
 
-.lessen {
-  opacity: 0.6;
+.tree.object-inspector .lessen,
+.tree.object-inspector .lessen *,
+.tree.object-inspector .lessen .object-label,
+.tree.object-inspector .lessen .object-label * {
+  color: var(--theme-comment);
 }
 
+.object-inspector .object-delimiter {
+  color: var(--theme-comment);
+}
--- a/devtools/client/shared/components/reps/reps.js
+++ b/devtools/client/shared/components/reps/reps.js
@@ -1,18 +1,18 @@
 (function webpackUniversalModuleDefinition(root, factory) {
 	if(typeof exports === 'object' && typeof module === 'object')
-		module.exports = factory(require("devtools/client/shared/vendor/react"));
+		module.exports = factory(require("devtools/client/shared/vendor/react"), require("devtools/client/shared/vendor/lodash"));
 	else if(typeof define === 'function' && define.amd)
-		define(["devtools/client/shared/vendor/react"], factory);
+		define(["devtools/client/shared/vendor/react", "devtools/client/shared/vendor/lodash"], factory);
 	else {
-		var a = typeof exports === 'object' ? factory(require("devtools/client/shared/vendor/react")) : factory(root["devtools/client/shared/vendor/react"]);
+		var a = typeof exports === 'object' ? factory(require("devtools/client/shared/vendor/react"), require("devtools/client/shared/vendor/lodash")) : factory(root["devtools/client/shared/vendor/react"], root["devtools/client/shared/vendor/lodash"]);
 		for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
 	}
-})(this, function(__WEBPACK_EXTERNAL_MODULE_0__) {
+})(this, function(__WEBPACK_EXTERNAL_MODULE_0__, __WEBPACK_EXTERNAL_MODULE_49__) {
 return /******/ (function(modules) { // webpackBootstrap
 /******/ 	// The module cache
 /******/ 	var installedModules = {};
 /******/
 /******/ 	// The require function
 /******/ 	function __webpack_require__(moduleId) {
 /******/
 /******/ 		// Check if module is in cache
@@ -65,29 +65,32 @@ return /******/ (function(modules) { // 
 /******/
 /******/ 	// Object.prototype.hasOwnProperty.call
 /******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
 /******/
 /******/ 	// __webpack_public_path__
 /******/ 	__webpack_require__.p = "/assets/build";
 /******/
 /******/ 	// Load entry module and return exports
-/******/ 	return __webpack_require__(__webpack_require__.s = 26);
+/******/ 	return __webpack_require__(__webpack_require__.s = 15);
 /******/ })
 /************************************************************************/
 /******/ ([
 /* 0 */
 /***/ (function(module, exports) {
 
 module.exports = __WEBPACK_EXTERNAL_MODULE_0__;
 
 /***/ }),
 /* 1 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Dependencies
 const React = __webpack_require__(0);
 const validProtocols = /^(http|https|ftp|data|javascript|resource|chrome):/i;
 const tokenSplitRegex = /(\s|\'|\"|\\)+/;
@@ -486,17 +489,20 @@ module.exports = {
   maybeEscapePropertyName,
   getGripPreviewItems,
   getGripType,
   tokenSplitRegex
 };
 
 /***/ }),
 /* 2 */
-/***/ (function(module, exports) {
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
 
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 module.exports = {
   MODE: {
     TINY: Symbol("TINY"),
@@ -504,55 +510,58 @@ module.exports = {
     LONG: Symbol("LONG")
   }
 };
 
 /***/ }),
 /* 3 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-__webpack_require__(27);
+__webpack_require__(16);
 
 // Load all existing rep templates
-const Undefined = __webpack_require__(28);
-const Null = __webpack_require__(29);
-const StringRep = __webpack_require__(16);
-const LongStringRep = __webpack_require__(30);
-const Number = __webpack_require__(31);
-const ArrayRep = __webpack_require__(17);
-const Obj = __webpack_require__(32);
-const SymbolRep = __webpack_require__(33);
-const InfinityRep = __webpack_require__(34);
-const NaNRep = __webpack_require__(35);
-const Accessor = __webpack_require__(36);
+const Undefined = __webpack_require__(17);
+const Null = __webpack_require__(18);
+const StringRep = __webpack_require__(5);
+const LongStringRep = __webpack_require__(19);
+const Number = __webpack_require__(20);
+const ArrayRep = __webpack_require__(7);
+const Obj = __webpack_require__(21);
+const SymbolRep = __webpack_require__(22);
+const InfinityRep = __webpack_require__(23);
+const NaNRep = __webpack_require__(24);
+const Accessor = __webpack_require__(25);
 
 // DOM types (grips)
-const Attribute = __webpack_require__(37);
-const DateTime = __webpack_require__(38);
-const Document = __webpack_require__(39);
-const Event = __webpack_require__(40);
-const Func = __webpack_require__(41);
-const PromiseRep = __webpack_require__(42);
-const RegExp = __webpack_require__(43);
-const StyleSheet = __webpack_require__(44);
-const CommentNode = __webpack_require__(45);
-const ElementNode = __webpack_require__(46);
-const TextNode = __webpack_require__(50);
-const ErrorRep = __webpack_require__(51);
-const Window = __webpack_require__(52);
-const ObjectWithText = __webpack_require__(53);
-const ObjectWithURL = __webpack_require__(54);
-const GripArray = __webpack_require__(19);
-const GripMap = __webpack_require__(55);
-const GripMapEntry = __webpack_require__(20);
-const Grip = __webpack_require__(9);
+const Attribute = __webpack_require__(26);
+const DateTime = __webpack_require__(27);
+const Document = __webpack_require__(28);
+const Event = __webpack_require__(29);
+const Func = __webpack_require__(30);
+const PromiseRep = __webpack_require__(31);
+const RegExp = __webpack_require__(32);
+const StyleSheet = __webpack_require__(33);
+const CommentNode = __webpack_require__(34);
+const ElementNode = __webpack_require__(35);
+const TextNode = __webpack_require__(37);
+const ErrorRep = __webpack_require__(38);
+const Window = __webpack_require__(39);
+const ObjectWithText = __webpack_require__(40);
+const ObjectWithURL = __webpack_require__(41);
+const GripArray = __webpack_require__(11);
+const GripMap = __webpack_require__(12);
+const GripMapEntry = __webpack_require__(13);
+const Grip = __webpack_require__(6);
 
 // List of all registered template.
 // XXX there should be a way for extensions to register a new
 // or modify an existing rep.
 let reps = [RegExp, StyleSheet, Event, DateTime, CommentNode, ElementNode, TextNode, Attribute, LongStringRep, Func, PromiseRep, ArrayRep, Document, Window, ObjectWithText, ObjectWithURL, ErrorRep, GripArray, GripMap, GripMapEntry, Grip, Undefined, Null, StringRep, Number, SymbolRep, InfinityRep, NaNRep, Accessor];
 
 /**
  * Generic rep that is using for rendering native JS types or an object.
@@ -640,16 +649,19 @@ module.exports = {
   // Exporting for tests
   getRep
 };
 
 /***/ }),
 /* 4 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Dependencies
 const React = __webpack_require__(0);
 const {
   maybeEscapePropertyName,
@@ -683,17 +695,17 @@ PropRep.propTypes = {
 /**
  * Function that given a name, a delimiter and an object returns an array
  * of React elements representing an object property (e.g. `name: value`)
  *
  * @param {Object} props
  * @return {Array} Array of React elements.
  */
 function PropRep(props) {
-  const Grip = __webpack_require__(9);
+  const Grip = __webpack_require__(6);
   const { Rep } = __webpack_require__(3);
 
   let {
     name,
     mode,
     equal,
     suppressQuotes
   } = props;
@@ -720,112 +732,139 @@ function PropRep(props) {
   }, equal), Rep(Object.assign({}, props))];
 }
 
 // Exports from this module
 module.exports = wrapRender(PropRep);
 
 /***/ }),
 /* 5 */
-/***/ (function(module, exports) {
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Dependencies
+const React = __webpack_require__(0);
+
+const {
+  containsURL,
+  isURL,
+  escapeString,
+  getGripType,
+  rawCropString,
+  sanitizeString,
+  wrapRender,
+  tokenSplitRegex
+} = __webpack_require__(1);
+
+// Shortcuts
+const { a, span } = React.DOM;
 
 /**
- * Checks if `value` is classified as an `Array` object.
- *
- * @static
- * @memberOf _
- * @since 0.1.0
- * @category Lang
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is an array, else `false`.
- * @example
- *
- * _.isArray([1, 2, 3]);
- * // => true
- *
- * _.isArray(document.body.children);
- * // => false
- *
- * _.isArray('abc');
- * // => false
- *
- * _.isArray(_.noop);
- * // => false
+ * Renders a string. String value is enclosed within quotes.
  */
-var isArray = Array.isArray;
-
-module.exports = isArray;
-
+StringRep.propTypes = {
+  useQuotes: React.PropTypes.bool,
+  escapeWhitespace: React.PropTypes.bool,
+  style: React.PropTypes.object,
+  object: React.PropTypes.string.isRequired,
+  member: React.PropTypes.any,
+  cropLimit: React.PropTypes.number,
+  openLink: React.PropTypes.func,
+  className: React.PropTypes.string
+};
+
+function StringRep(props) {
+  let {
+    className,
+    cropLimit,
+    object: text,
+    member,
+    style,
+    useQuotes = true,
+    escapeWhitespace = true,
+    openLink
+  } = props;
+
+  const classNames = ["objectBox", "objectBox-string"];
+  if (className) {
+    classNames.push(className);
+  }
+  let config = { className: classNames.join(" ") };
+  if (style) {
+    config.style = style;
+  }
+
+  if (useQuotes) {
+    text = escapeString(text, escapeWhitespace);
+  } else {
+    text = sanitizeString(text);
+  }
+
+  if ((!member || !member.open) && cropLimit) {
+    text = rawCropString(text, cropLimit);
+  }
+
+  if (!containsURL(text)) {
+    return span(config, text);
+  }
+
+  const items = [];
+
+  // As we walk through the tokens of the source string, we make sure to preserve
+  // the original whitespace that separated the tokens.
+  let tokens = text.split(tokenSplitRegex);
+  let textIndex = 0;
+  let tokenStart;
+  tokens.forEach((token, i) => {
+    tokenStart = text.indexOf(token, textIndex);
+    if (isURL(token)) {
+      items.push(text.slice(textIndex, tokenStart));
+      textIndex = tokenStart + token.length;
+
+      items.push(a({
+        className: "url",
+        title: token,
+        href: token,
+        draggable: false,
+        onClick: openLink ? e => {
+          e.preventDefault();
+          openLink(token);
+        } : null
+      }, token));
+    }
+  });
+
+  // Clean up any non-URL text at the end of the source string.
+  items.push(text.slice(textIndex, text.length));
+  return span(config, ...items);
+}
+
+function supportsObject(object, noGrip = false) {
+  return getGripType(object, noGrip) == "string";
+}
+
+// Exports from this module
+
+module.exports = {
+  rep: wrapRender(StringRep),
+  supportsObject
+};
 
 /***/ }),
 /* 6 */
 /***/ (function(module, exports, __webpack_require__) {
 
-var getNative = __webpack_require__(23);
-
-/* Built-in method references that are verified to be native. */
-var nativeCreate = getNative(Object, 'create');
-
-module.exports = nativeCreate;
-
-
-/***/ }),
-/* 7 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var eq = __webpack_require__(88);
-
-/**
- * Gets the index at which the `key` is found in `array` of key-value pairs.
- *
- * @private
- * @param {Array} array The array to inspect.
- * @param {*} key The key to search for.
- * @returns {number} Returns the index of the matched value, else `-1`.
- */
-function assocIndexOf(array, key) {
-  var length = array.length;
-  while (length--) {
-    if (eq(array[length][0], key)) {
-      return length;
-    }
-  }
-  return -1;
-}
-
-module.exports = assocIndexOf;
-
-
-/***/ }),
-/* 8 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var isKeyable = __webpack_require__(94);
-
-/**
- * Gets the data for `map`.
- *
- * @private
- * @param {Object} map The map to query.
- * @param {string} key The reference key.
- * @returns {*} Returns the map data.
- */
-function getMapData(map, key) {
-  var data = map.__data__;
-  return isKeyable(key)
-    ? data[typeof key == 'string' ? 'string' : 'hash']
-    : data.map;
-}
-
-module.exports = getMapData;
-
-
-/***/ }),
-/* 9 */
-/***/ (function(module, exports, __webpack_require__) {
+"use strict";
+
 
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // ReactJS
 const React = __webpack_require__(0);
 // Dependencies
@@ -1127,296 +1166,21 @@ let Grip = {
   supportsObject,
   maxLengthMap
 };
 
 // Exports from this module
 module.exports = Grip;
 
 /***/ }),
-/* 10 */
-/***/ (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/. */
-
-const React = __webpack_require__(0);
-const InlineSVG = __webpack_require__(47);
-
-const svg = {
-  "arrow": __webpack_require__(48),
-  "open-inspector": __webpack_require__(49)
-};
-
-Svg.propTypes = {
-  className: React.PropTypes.string
-};
-
-function Svg(name, props) {
-  if (!svg[name]) {
-    throw new Error("Unknown SVG: " + name);
-  }
-  let className = name;
-  if (props && props.className) {
-    className = `${name} ${props.className}`;
-  }
-  if (name === "subSettings") {
-    className = "";
-  }
-  props = Object.assign({}, props, { className, src: svg[name] });
-  return React.createElement(InlineSVG, props);
-}
-
-module.exports = Svg;
-
-/***/ }),
-/* 11 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var baseGetTag = __webpack_require__(12),
-    isObjectLike = __webpack_require__(15);
-
-/** `Object#toString` result references. */
-var symbolTag = '[object Symbol]';
-
-/**
- * Checks if `value` is classified as a `Symbol` primitive or object.
- *
- * @static
- * @memberOf _
- * @since 4.0.0
- * @category Lang
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
- * @example
- *
- * _.isSymbol(Symbol.iterator);
- * // => true
- *
- * _.isSymbol('abc');
- * // => false
- */
-function isSymbol(value) {
-  return typeof value == 'symbol' ||
-    (isObjectLike(value) && baseGetTag(value) == symbolTag);
-}
-
-module.exports = isSymbol;
-
-
-/***/ }),
-/* 12 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var Symbol = __webpack_require__(13),
-    getRawTag = __webpack_require__(66),
-    objectToString = __webpack_require__(67);
-
-/** `Object#toString` result references. */
-var nullTag = '[object Null]',
-    undefinedTag = '[object Undefined]';
-
-/** Built-in value references. */
-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;
-
-
-/***/ }),
-/* 13 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var root = __webpack_require__(14);
-
-/** Built-in value references. */
-var Symbol = root.Symbol;
-
-module.exports = Symbol;
-
-
-/***/ }),
-/* 14 */
+/* 7 */
 /***/ (function(module, exports, __webpack_require__) {
 
-var freeGlobal = __webpack_require__(64);
-
-/** 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;
-
-
-/***/ }),
-/* 15 */
-/***/ (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 _
- * @since 4.0.0
- * @category Lang
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
- * @example
- *
- * _.isObjectLike({});
- * // => true
- *
- * _.isObjectLike([1, 2, 3]);
- * // => true
- *
- * _.isObjectLike(_.noop);
- * // => false
- *
- * _.isObjectLike(null);
- * // => false
- */
-function isObjectLike(value) {
-  return value != null && typeof value == 'object';
-}
-
-module.exports = isObjectLike;
-
-
-/***/ }),
-/* 16 */
-/***/ (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/. */
-
-// Dependencies
-const React = __webpack_require__(0);
-
-const {
-  containsURL,
-  isURL,
-  escapeString,
-  getGripType,
-  rawCropString,
-  sanitizeString,
-  wrapRender,
-  tokenSplitRegex
-} = __webpack_require__(1);
-
-// Shortcuts
-const { a, span } = React.DOM;
-
-/**
- * Renders a string. String value is enclosed within quotes.
- */
-StringRep.propTypes = {
-  useQuotes: React.PropTypes.bool,
-  escapeWhitespace: React.PropTypes.bool,
-  style: React.PropTypes.object,
-  object: React.PropTypes.string.isRequired,
-  member: React.PropTypes.any,
-  cropLimit: React.PropTypes.number,
-  openLink: React.PropTypes.func
-};
-
-function StringRep(props) {
-  let {
-    cropLimit,
-    object: text,
-    member,
-    style,
-    useQuotes = true,
-    escapeWhitespace = true,
-    openLink
-  } = props;
-
-  let config = { className: "objectBox objectBox-string" };
-  if (style) {
-    config.style = style;
-  }
-
-  if (useQuotes) {
-    text = escapeString(text, escapeWhitespace);
-  } else {
-    text = sanitizeString(text);
-  }
-
-  if ((!member || !member.open) && cropLimit) {
-    text = rawCropString(text, cropLimit);
-  }
-
-  if (!containsURL(text)) {
-    return span(config, text);
-  }
-
-  const items = [];
-
-  // As we walk through the tokens of the source string, we make sure to preserve
-  // the original whitespace that separated the tokens.
-  let tokens = text.split(tokenSplitRegex);
-  let textIndex = 0;
-  let tokenStart;
-  tokens.forEach((token, i) => {
-    tokenStart = text.indexOf(token, textIndex);
-    if (isURL(token)) {
-      items.push(text.slice(textIndex, tokenStart));
-      textIndex = tokenStart + token.length;
-
-      items.push(a({
-        className: "url",
-        title: token,
-        href: token,
-        draggable: false,
-        onClick: openLink ? e => {
-          e.preventDefault();
-          openLink(token);
-        } : null
-      }, token));
-    }
-  });
-
-  // Clean up any non-URL text at the end of the source string.
-  items.push(text.slice(textIndex, text.length));
-  return span(config, ...items);
-}
-
-function supportsObject(object, noGrip = false) {
-  return getGripType(object, noGrip) == "string";
-}
-
-// Exports from this module
-
-module.exports = {
-  rep: wrapRender(StringRep),
-  supportsObject
-};
-
-/***/ }),
-/* 17 */
-/***/ (function(module, exports, __webpack_require__) {
+"use strict";
+
 
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Dependencies
 const React = __webpack_require__(0);
 const {
@@ -1528,34 +1292,42 @@ function ItemRep(props) {
     mode
   } = props;
   return DOM.span({}, Rep(Object.assign({}, props, {
     object: object,
     mode: mode
   })), delim);
 }
 
+function getLength(object) {
+  return object.length;
+}
+
 function supportsObject(object) {
   return Array.isArray(object) || Object.prototype.toString.call(object) === "[object Arguments]";
 }
 
 const maxLengthMap = new Map();
 maxLengthMap.set(MODE.SHORT, 3);
 maxLengthMap.set(MODE.LONG, 10);
 
 // Exports from this module
 module.exports = {
   rep: wrapRender(ArrayRep),
   supportsObject,
-  maxLengthMap
+  maxLengthMap,
+  getLength
 };
 
 /***/ }),
-/* 18 */
-/***/ (function(module, exports) {
+/* 8 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
 
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 module.exports = {
   ELEMENT_NODE: 1,
   ATTRIBUTE_NODE: 2,
@@ -1575,19 +1347,214 @@ module.exports = {
   DOCUMENT_POSITION_PRECEDING: 0x02,
   DOCUMENT_POSITION_FOLLOWING: 0x04,
   DOCUMENT_POSITION_CONTAINS: 0x08,
   DOCUMENT_POSITION_CONTAINED_BY: 0x10,
   DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: 0x20
 };
 
 /***/ }),
-/* 19 */
+/* 9 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const React = __webpack_require__(0);
+const InlineSVG = __webpack_require__(10);
+
+const svg = {
+  "open-inspector": __webpack_require__(36)
+};
+
+Svg.propTypes = {
+  className: React.PropTypes.string
+};
+
+function Svg(name, props) {
+  if (!svg[name]) {
+    throw new Error("Unknown SVG: " + name);
+  }
+  let className = name;
+  if (props && props.className) {
+    className = `${name} ${props.className}`;
+  }
+  if (name === "subSettings") {
+    className = "";
+  }
+  props = Object.assign({}, props, { className, src: svg[name] });
+  return React.createElement(InlineSVG, props);
+}
+
+module.exports = Svg;
+
+/***/ }),
+/* 10 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
+Object.defineProperty(exports, '__esModule', {
+    value: 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; };
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+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 _react = __webpack_require__(0);
+
+var _react2 = _interopRequireDefault(_react);
+
+var DOMParser = typeof window !== 'undefined' && window.DOMParser;
+var process = process || {};
+process.env = process.env || {};
+var parserAvailable = typeof DOMParser !== 'undefined' && DOMParser.prototype != null && DOMParser.prototype.parseFromString != null;
+
+function isParsable(src) {
+    // kinda naive but meh, ain't gonna use full-blown parser for this
+    return parserAvailable && typeof src === 'string' && src.trim().substr(0, 4) === '<svg';
+}
+
+// parse SVG string using `DOMParser`
+function parseFromSVGString(src) {
+    var parser = new DOMParser();
+    return parser.parseFromString(src, "image/svg+xml");
+}
+
+// Transform DOM prop/attr names applicable to `<svg>` element but react-limited
+function switchSVGAttrToReactProp(propName) {
+    switch (propName) {
+        case 'class':
+            return 'className';
+        default:
+            return propName;
+    }
+}
+
+var InlineSVG = (function (_React$Component) {
+    _inherits(InlineSVG, _React$Component);
+
+    _createClass(InlineSVG, null, [{
+        key: 'defaultProps',
+        value: {
+            element: 'i',
+            raw: false,
+            src: ''
+        },
+        enumerable: true
+    }, {
+        key: 'propTypes',
+        value: {
+            src: _react2['default'].PropTypes.string.isRequired,
+            element: _react2['default'].PropTypes.string,
+            raw: _react2['default'].PropTypes.bool
+        },
+        enumerable: true
+    }]);
+
+    function InlineSVG(props) {
+        _classCallCheck(this, InlineSVG);
+
+        _get(Object.getPrototypeOf(InlineSVG.prototype), 'constructor', this).call(this, props);
+        this._extractSVGProps = this._extractSVGProps.bind(this);
+    }
+
+    // Serialize `Attr` objects in `NamedNodeMap`
+
+    _createClass(InlineSVG, [{
+        key: '_serializeAttrs',
+        value: function _serializeAttrs(map) {
+            var ret = {};
+            var prop = undefined;
+            for (var i = 0; i < map.length; i++) {
+                prop = switchSVGAttrToReactProp(map[i].name);
+                ret[prop] = map[i].value;
+            }
+            return ret;
+        }
+
+        // get <svg /> element props
+    }, {
+        key: '_extractSVGProps',
+        value: function _extractSVGProps(src) {
+            var map = parseFromSVGString(src).documentElement.attributes;
+            return map.length > 0 ? this._serializeAttrs(map) : null;
+        }
+
+        // get content inside <svg> element.
+    }, {
+        key: '_stripSVG',
+        value: function _stripSVG(src) {
+            return parseFromSVGString(src).documentElement.innerHTML;
+        }
+    }, {
+        key: 'componentWillReceiveProps',
+        value: function componentWillReceiveProps(_ref) {
+            var children = _ref.children;
+
+            if ("production" !== process.env.NODE_ENV && children != null) {
+                console.info('<InlineSVG />: `children` prop will be ignored.');
+            }
+        }
+    }, {
+        key: 'render',
+        value: function render() {
+            var Element = undefined,
+                __html = undefined,
+                svgProps = undefined;
+            var _props = this.props;
+            var element = _props.element;
+            var raw = _props.raw;
+            var src = _props.src;
+
+            var otherProps = _objectWithoutProperties(_props, ['element', 'raw', 'src']);
+
+            if (raw === true && isParsable(src)) {
+                Element = 'svg';
+                svgProps = this._extractSVGProps(src);
+                __html = this._stripSVG(src);
+            }
+            __html = __html || src;
+            Element = Element || element;
+            svgProps = svgProps || {};
+
+            return _react2['default'].createElement(Element, _extends({}, svgProps, otherProps, { src: null, children: null,
+                dangerouslySetInnerHTML: { __html: __html } }));
+        }
+    }]);
+
+    return InlineSVG;
+})(_react2['default'].Component);
+
+exports['default'] = InlineSVG;
+module.exports = exports['default'];
+
+/***/ }),
+/* 11 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Dependencies
 const React = __webpack_require__(0);
 const {
   getGripType,
@@ -1775,23 +1742,234 @@ function supportsObject(grip, noGrip = f
 const maxLengthMap = new Map();
 maxLengthMap.set(MODE.SHORT, 3);
 maxLengthMap.set(MODE.LONG, 10);
 
 // Exports from this module
 module.exports = {
   rep: wrapRender(GripArray),
   supportsObject,
-  maxLengthMap
+  maxLengthMap,
+  getLength
 };
 
 /***/ }),
-/* 20 */
+/* 12 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Dependencies
+const React = __webpack_require__(0);
+const {
+  isGrip,
+  wrapRender
+} = __webpack_require__(1);
+const PropRep = __webpack_require__(4);
+const { MODE } = __webpack_require__(2);
+// Shortcuts
+const { span } = React.DOM;
+
+/**
+ * Renders an map. A map is represented by a list of its
+ * entries enclosed in curly brackets.
+ */
+GripMap.propTypes = {
+  object: React.PropTypes.object,
+  // @TODO Change this to Object.values once it's supported in Node's version of V8
+  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
+  isInterestingEntry: React.PropTypes.func,
+  onDOMNodeMouseOver: React.PropTypes.func,
+  onDOMNodeMouseOut: React.PropTypes.func,
+  onInspectIconClick: React.PropTypes.func,
+  title: React.PropTypes.string
+};
+
+function GripMap(props) {
+  let {
+    mode,
+    object
+  } = props;
+
+  const config = {
+    "data-link-actor-id": object.actor,
+    className: "objectBox objectBox-object"
+  };
+
+  if (mode === MODE.TINY) {
+    return span(config, getTitle(props, object));
+  }
+
+  let propsArray = safeEntriesIterator(props, object, maxLengthMap.get(mode));
+
+  return span(config, getTitle(props, object), span({
+    className: "objectLeftBrace"
+  }, " { "), ...propsArray, span({
+    className: "objectRightBrace"
+  }, " }"));
+}
+
+function getTitle(props, object) {
+  let title = props.title || (object && object.class ? object.class : "Map");
+  return span({
+    className: "objectTitle"
+  }, title);
+}
+
+function safeEntriesIterator(props, object, max) {
+  max = typeof max === "undefined" ? 3 : max;
+  try {
+    return entriesIterator(props, object, max);
+  } catch (err) {
+    console.error(err);
+  }
+  return [];
+}
+
+function entriesIterator(props, object, max) {
+  // Entry filter. Show only interesting entries to the user.
+  let isInterestingEntry = props.isInterestingEntry || ((type, value) => {
+    return type == "boolean" || type == "number" || type == "string" && value.length != 0;
+  });
+
+  let mapEntries = object.preview && object.preview.entries ? object.preview.entries : [];
+
+  let indexes = 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(getEntriesIndexes(mapEntries, max - indexes.length, (t, value, name) => {
+      return !isInterestingEntry(t, value, name);
+    }));
+  }
+
+  let entries = getEntries(props, mapEntries, indexes);
+  if (entries.length < getLength(object)) {
+    // There are some undisplayed entries. Then display "…".
+    entries.push(span({
+      key: "more",
+      className: "more-ellipsis",
+      title: "more…"
+    }, "…"));
+  }
+
+  return unfoldEntries(entries);
+}
+
+function unfoldEntries(items) {
+  return items.reduce((res, item, index) => {
+    if (Array.isArray(item)) {
+      res = res.concat(item);
+    } else {
+      res.push(item);
+    }
+
+    // Interleave commas between elements
+    if (index !== items.length - 1) {
+      res.push(", ");
+    }
+    return res;
+  }, []);
+}
+
+/**
+ * Get entries ordered by index.
+ *
+ * @param {Object} props Component props.
+ * @param {Array} entries Entries array.
+ * @param {Array} indexes Indexes of entries.
+ * @return {Array} Array of PropRep.
+ */
+function getEntries(props, entries, indexes) {
+  let {
+    onDOMNodeMouseOver,
+    onDOMNodeMouseOut,
+    onInspectIconClick
+  } = props;
+
+  // Make indexes ordered by ascending.
+  indexes.sort(function (a, b) {
+    return a - b;
+  });
+
+  return indexes.map((index, i) => {
+    let [key, entryValue] = entries[index];
+    let value = entryValue.value !== undefined ? entryValue.value : entryValue;
+
+    return PropRep({
+      name: key,
+      equal: " \u2192 ",
+      object: value,
+      mode: MODE.TINY,
+      onDOMNodeMouseOver,
+      onDOMNodeMouseOut,
+      onInspectIconClick
+    });
+  });
+}
+
+/**
+ * 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.
+ */
+function getEntriesIndexes(entries, max, filter) {
+  return entries.reduce((indexes, [key, entry], i) => {
+    if (indexes.length < max) {
+      let value = entry && entry.value !== undefined ? entry.value : entry;
+      // Type is specified in grip's "class" field and for primitive
+      // values use typeof.
+      let type = (value && value.class ? value.class : typeof value).toLowerCase();
+
+      if (filter(type, value, key)) {
+        indexes.push(i);
+      }
+    }
+
+    return indexes;
+  }, []);
+}
+
+function getLength(grip) {
+  return grip.preview.size || 0;
+}
+
+function supportsObject(grip, noGrip = false) {
+  if (noGrip === true || !isGrip(grip)) {
+    return false;
+  }
+  return grip.preview && grip.preview.kind == "MapLike";
+}
+
+const maxLengthMap = new Map();
+maxLengthMap.set(MODE.SHORT, 3);
+maxLengthMap.set(MODE.LONG, 10);
+
+// Exports from this module
+module.exports = {
+  rep: wrapRender(GripMap),
+  supportsObject,
+  maxLengthMap,
+  getLength
+};
+
+/***/ }),
+/* 13 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Dependencies
 const React = __webpack_require__(0);
 // Shortcuts
 const { span } = React.DOM;
@@ -1853,41 +2031,48 @@ function createGripMapEntry(key, value) 
 // Exports from this module
 module.exports = {
   rep: wrapRender(GripMapEntry),
   createGripMapEntry,
   supportsObject
 };
 
 /***/ }),
-/* 21 */
+/* 14 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-const get = __webpack_require__(61);
-const has = __webpack_require__(101);
+const { get, has } = __webpack_require__(49);
 const { maybeEscapePropertyName } = __webpack_require__(1);
-const ArrayRep = __webpack_require__(17);
-const GripArrayRep = __webpack_require__(19);
-const GripMapEntryRep = __webpack_require__(20);
+const ArrayRep = __webpack_require__(7);
+const GripArrayRep = __webpack_require__(11);
+const GripMap = __webpack_require__(12);
+const GripMapEntryRep = __webpack_require__(13);
+
+const MAX_NUMERICAL_PROPERTIES = 100;
 
 const NODE_TYPES = {
   BUCKET: Symbol("[n…n]"),
   DEFAULT_PROPERTIES: Symbol("[default properties]"),
   ENTRIES: Symbol("<entries>"),
   GET: Symbol("<get>"),
   GRIP: Symbol("GRIP"),
   MAP_ENTRY_KEY: Symbol("<key>"),
   MAP_ENTRY_VALUE: Symbol("<value>"),
   PROMISE_REASON: Symbol("<reason>"),
   PROMISE_STATE: Symbol("<state>"),
   PROMISE_VALUE: Symbol("<value>"),
+  PROXY_HANDLER: Symbol("<handler>"),
+  PROXY_TARGET: Symbol("<target>"),
   SET: Symbol("<set>"),
   PROTOTYPE: Symbol("__proto__")
 };
 
 let WINDOW_PROPERTIES = {};
 
 if (typeof window === "object") {
   WINDOW_PROPERTIES = Object.getOwnPropertyNames(window);
@@ -1923,17 +2108,17 @@ function nodeIsEntries(item) {
   return getType(item) === NODE_TYPES.ENTRIES;
 }
 
 function nodeIsMapEntry(item) {
   return GripMapEntryRep.supportsObject(getValue(item));
 }
 
 function nodeHasChildren(item) {
-  return Array.isArray(item.contents) || nodeIsBucket(item);
+  return Array.isArray(item.contents);
 }
 
 function nodeIsObject(item) {
   const value = getValue(item);
   return value && value.type === "object";
 }
 
 function nodeIsArrayLike(item) {
@@ -1956,17 +2141,17 @@ function nodeIsMissingArguments(item) {
   return !nodeHasChildren(item) && value && value.missingArguments;
 }
 
 function nodeHasProperties(item) {
   return !nodeHasChildren(item) && nodeIsObject(item);
 }
 
 function nodeIsPrimitive(item) {
-  return !nodeHasChildren(item) && !nodeHasProperties(item) && !nodeIsEntries(item) && !nodeIsMapEntry(item) && !nodeHasAccessors(item);
+  return !nodeHasChildren(item) && !nodeHasProperties(item) && !nodeIsEntries(item) && !nodeIsMapEntry(item) && !nodeHasAccessors(item) && !nodeIsBucket(item);
 }
 
 function nodeIsDefaultProperties(item) {
   return getType(item) === NODE_TYPES.DEFAULT_PROPERTIES;
 }
 
 function isDefaultWindowProperty(name) {
   return WINDOW_PROPERTIES.includes(name);
@@ -1976,16 +2161,25 @@ function nodeIsPromise(item) {
   const value = getValue(item);
   if (!value) {
     return false;
   }
 
   return value.class == "Promise";
 }
 
+function nodeIsProxy(item) {
+  const value = getValue(item);
+  if (!value) {
+    return false;
+  }
+
+  return value.class == "Proxy";
+}
+
 function nodeIsPrototype(item) {
   return getType(item) === NODE_TYPES.PROTOTYPE;
 }
 
 function nodeIsWindow(item) {
   const value = getValue(item);
   if (!value) {
     return false;
@@ -2001,18 +2195,20 @@ function nodeIsGetter(item) {
 function nodeIsSetter(item) {
   return getType(item) === NODE_TYPES.SET;
 }
 
 function nodeHasAccessors(item) {
   return !!getNodeGetter(item) || !!getNodeSetter(item);
 }
 
-function nodeSupportsBucketing(item) {
-  return nodeIsArrayLike(item) || nodeIsEntries(item);
+function nodeSupportsNumericalBucketing(item) {
+  // We exclude elements with entries since it's the <entries> node
+  // itself that can have buckets.
+  return nodeIsArrayLike(item) && !nodeHasEntries(item) || nodeIsEntries(item) || nodeIsBucket(item);
 }
 
 function nodeHasEntries(item) {
   const value = getValue(item);
   if (!value) {
     return false;
   }
 
@@ -2030,16 +2226,20 @@ function nodeHasAllEntriesInPreview(item
     items,
     length,
     size
   } = preview;
 
   return entries ? entries.length === size : items.length === length;
 }
 
+function nodeNeedsNumericalBuckets(item) {
+  return nodeSupportsNumericalBucketing(item) && getNumericalPropertiesCount(item) > MAX_NUMERICAL_PROPERTIES;
+}
+
 function makeNodesForPromiseProperties(item) {
   const { promiseState: { reason, value, state } } = getValue(item);
 
   const properties = [];
 
   if (state) {
     properties.push(createNode(item, "<state>", `${item.path}/${SAFE_PATH_PREFIX}state`, { value: state }, NODE_TYPES.PROMISE_STATE));
   }
@@ -2050,24 +2250,33 @@ function makeNodesForPromiseProperties(i
 
   if (value) {
     properties.push(createNode(item, "<value>", `${item.path}/${SAFE_PATH_PREFIX}value`, { value: value }, NODE_TYPES.PROMISE_VALUE));
   }
 
   return properties;
 }
 
+function makeNodesForProxyProperties(item) {
+  const {
+    proxyHandler,
+    proxyTarget
+  } = getValue(item);
+
+  return [createNode(item, "<target>", `${item.path}/${SAFE_PATH_PREFIX}target`, { value: proxyTarget }, NODE_TYPES.PROXY_TARGET), createNode(item, "<handler>", `${item.path}/${SAFE_PATH_PREFIX}handler`, { value: proxyHandler }, NODE_TYPES.PROXY_HANDLER)];
+}
+
 function makeNodesForEntries(item) {
   const { path } = item;
-  const { preview } = getValue(item);
   const nodeName = "<entries>";
   const entriesPath = `${path}/${SAFE_PATH_PREFIX}entries`;
 
   if (nodeHasAllEntriesInPreview(item)) {
     let entriesNodes = [];
+    const { preview } = getValue(item);
     if (preview.entries) {
       entriesNodes = preview.entries.map(([key, value], index) => {
         return createNode(item, index, `${entriesPath}/${index}`, {
           value: GripMapEntryRep.createGripMapEntry(key, value)
         });
       });
     } else if (preview.items) {
       entriesNodes = preview.items.map((value, index) => {
@@ -2124,50 +2333,38 @@ function sortProperties(properties) {
     if (isNaN(aInt) || isNaN(bInt)) {
       return a > b ? 1 : -1;
     }
 
     return aInt - bInt;
   });
 }
 
-function makeNumericalBuckets(propertiesNames, parent, ownProperties, startIndex = 0) {
+function makeNumericalBuckets(parent) {
   const parentPath = parent.path;
-  const numProperties = propertiesNames.length;
+  const numProperties = getNumericalPropertiesCount(parent);
 
   // We want to have at most a hundred slices.
   const bucketSize = 10 ** Math.max(2, Math.ceil(Math.log10(numProperties)) - 2);
   const numBuckets = Math.ceil(numProperties / bucketSize);
 
   let buckets = [];
   for (let i = 1; i <= numBuckets; i++) {
     const minKey = (i - 1) * bucketSize;
     const maxKey = Math.min(i * bucketSize - 1, numProperties - 1);
-
-    if (maxKey === minKey) {
-      const name = propertiesNames[maxKey];
-      buckets.push(createNode(parent, name, `${parentPath}/${name}`, ownProperties[name]));
-    } else {
-      const minIndex = startIndex + minKey;
-      const maxIndex = startIndex + maxKey;
-      const bucketKey = `${SAFE_PATH_PREFIX}bucket_${minIndex}-${maxIndex}`;
-      const bucketName = `[${minIndex}…${maxIndex}]`;
-
-      const bucketRoot = createNode(parent, bucketName, `${parentPath}/${bucketKey}`, [], NODE_TYPES.BUCKET);
-
-      const bucketProperties = propertiesNames.slice(minKey, maxKey + 1);
-      let bucketNodes;
-      if (bucketProperties.length <= 100) {
-        bucketNodes = bucketProperties.map(name => createNode(bucketRoot, name, `${parentPath}/${bucketKey}/${name}`, ownProperties[name]));
-      } else {
-        bucketNodes = makeNumericalBuckets(bucketProperties, bucketRoot, ownProperties, minIndex);
-      }
-      setNodeChildren(bucketRoot, bucketNodes);
-      buckets.push(bucketRoot);
-    }
+    const startIndex = nodeIsBucket(parent) ? parent.meta.startIndex : 0;
+    const minIndex = startIndex + minKey;
+    const maxIndex = startIndex + maxKey;
+    const bucketKey = `${SAFE_PATH_PREFIX}bucket_${minIndex}-${maxIndex}`;
+    const bucketName = `[${minIndex}…${maxIndex}]`;
+
+    buckets.push(createNode(parent, bucketName, `${parentPath}/${bucketKey}`, null, NODE_TYPES.BUCKET, {
+      startIndex: minIndex,
+      endIndex: maxIndex
+    }));
   }
   return buckets;
 }
 
 function makeDefaultPropsBucket(propertiesNames, parent, ownProperties) {
   const parentPath = parent.path;
 
   const userPropertiesNames = [];
@@ -2206,305 +2403,331 @@ function makeNodesForProperties(objProps
   } = objProps;
 
   const parentPath = parent.path;
   const parentValue = getValue(parent);
 
   let allProperties = Object.assign({}, ownProperties, safeGetterValues);
 
   // Ignore properties that are neither non-concrete nor getters/setters.
-  const propertiesNames = sortProperties(Object.keys(allProperties)).filter(name => allProperties[name].hasOwnProperty("value") || allProperties[name].hasOwnProperty("getterValue") || allProperties[name].hasOwnProperty("get") || allProperties[name].hasOwnProperty("set"));
-
-  const numProperties = propertiesNames.length;
+  const propertiesNames = sortProperties(Object.keys(allProperties)).filter(name => {
+    if (!allProperties[name]) {
+      return false;
+    }
+
+    const properties = Object.getOwnPropertyNames(allProperties[name]);
+    return properties.some(property => ["value", "getterValue", "get", "set"].includes(property));
+  });
 
   let nodes = [];
-  if (nodeSupportsBucketing(parent) && numProperties > 100) {
-    nodes = makeNumericalBuckets(propertiesNames, parent, allProperties);
-  } else if (parentValue && parentValue.class == "Window") {
+  if (parentValue && parentValue.class == "Window") {
     nodes = makeDefaultPropsBucket(propertiesNames, parent, allProperties);
   } else {
     nodes = makeNodesForOwnProps(propertiesNames, parent, allProperties);
   }
 
   if (Array.isArray(ownSymbols)) {
     ownSymbols.forEach((ownSymbol, index) => {
-      nodes.push(createNode(parent, ownSymbol.name, `${parentPath}/${SAFE_PATH_PREFIX}symbol-${index}`, ownSymbol.descriptor));
+      nodes.push(createNode(parent, ownSymbol.name, `${parentPath}/${SAFE_PATH_PREFIX}symbol-${index}`, ownSymbol.descriptor || null));
     }, this);
   }
 
   if (nodeIsPromise(parent)) {
     nodes.push(...makeNodesForPromiseProperties(parent));
   }
 
   if (nodeHasEntries(parent)) {
     nodes.push(makeNodesForEntries(parent));
   }
 
   // Add the prototype if it exists and is not null
   if (prototype && prototype.type !== "null") {
-    nodes.push(createNode(parent, "__proto__", `${parentPath}/__proto__`, { value: prototype }, NODE_TYPES.PROTOTYPE));
+    nodes.push(makeNodeForPrototype(objProps, parent));
   }
 
   return nodes;
 }
 
-function createNode(parent, name, path, contents, type = NODE_TYPES.GRIP) {
+function makeNodeForPrototype(objProps, parent) {
+  const {
+    prototype
+  } = objProps || {};
+
+  // Add the prototype if it exists and is not null
+  if (prototype && prototype.type !== "null") {
+    return createNode(parent, "__proto__", `${parent.path}/__proto__`, { value: prototype }, NODE_TYPES.PROTOTYPE);
+  }
+
+  return null;
+}
+
+function createNode(parent, name, path, contents, type = NODE_TYPES.GRIP, meta) {
   if (contents === undefined) {
     return null;
   }
 
   // The path is important to uniquely identify the item in the entire
   // tree. This helps debugging & optimizes React's rendering of large
   // lists. The path will be separated by property name,
   // i.e. `{ foo: { bar: { baz: 5 }}}` will have a path of `foo/bar/baz`
   // for the inner object.
   return {
     parent,
     name,
     path,
     contents,
-    type
+    type,
+    meta
   };
 }
 
 function setNodeChildren(node, children) {
   node.contents = children;
   return node;
 }
 
 function getChildren(options) {
   const {
-    actors = {},
-    getObjectEntries,
-    getObjectProperties,
+    cachedNodes,
+    loadedProperties = new Map(),
     item
   } = options;
-  // Nodes can either have children already, or be an object with
-  // properties that we need to go and fetch.
-  if (nodeHasAccessors(item)) {
-    return makeNodesForAccessors(item);
-  }
-
-  if (nodeIsMapEntry(item)) {
-    return makeNodesForMapEntry(item);
+
+  const key = item.path;
+  if (cachedNodes && cachedNodes.has(key)) {
+    return cachedNodes.get(key);
   }
 
-  if (nodeHasChildren(item)) {
-    return item.contents;
-  }
-
-  if (!nodeHasProperties(item) && !nodeIsEntries(item)) {
-    return [];
-  }
+  const loadedProps = loadedProperties.get(key);
+  const {
+    ownProperties,
+    ownSymbols,
+    safeGetterValues,
+    prototype
+  } = loadedProps || {};
+  const hasLoadedProps = ownProperties || ownSymbols || safeGetterValues || prototype;
 
   // Because we are dynamically creating the tree as the user
   // expands it (not precalculated tree structure), we cache child
   // arrays. This not only helps performance, but is necessary
   // because the expanded state depends on instances of nodes
   // being the same across renders. If we didn't do this, each
   // node would be a new instance every render.
-  const key = item.path;
-  if (actors && actors[key]) {
-    return actors[key];
+  // If the node needs properties, we only add children to
+  // the cache if the properties are loaded.
+  const addToCache = children => {
+    if (cachedNodes) {
+      cachedNodes.set(item.path, children);
+    }
+    return children;
+  };
+
+  // Nodes can either have children already, or be an object with
+  // properties that we need to go and fetch.
+  if (nodeHasChildren(item)) {
+    return addToCache(item.contents);
   }
 
-  if (nodeIsBucket(item)) {
-    return item.contents.children;
+  if (nodeHasAccessors(item)) {
+    return addToCache(makeNodesForAccessors(item));
+  }
+
+  if (nodeIsMapEntry(item)) {
+    return addToCache(makeNodesForMapEntry(item));
   }
 
-  let loadedProps;
-  if (nodeIsEntries(item)) {
-    // If `item` is an <entries> node, we need to get the entries
-    // matching the parent node actor.
-    const parent = getParent(item);
-    loadedProps = getObjectEntries(get(getValue(parent), "actor", undefined));
-  } else {
-    loadedProps = getObjectProperties(get(getValue(item), "actor", undefined));
+  if (nodeIsProxy(item)) {
+    const nodes = makeNodesForProxyProperties(item);
+    const protoNode = makeNodeForPrototype(loadedProps, item);
+    if (protoNode) {
+      return addToCache(nodes.concat(protoNode));
+    }
+    return nodes;
   }
 
-  const {
-    ownProperties,
-    ownSymbols,
-    safeGetterValues,
-    prototype
-  } = loadedProps || {};
-
-  if (!ownProperties && !ownSymbols && !safeGetterValues && !prototype) {
+  if (nodeNeedsNumericalBuckets(item)) {
+    const bucketNodes = makeNumericalBuckets(item);
+    // Even if we have numerical buckets, we might have loaded non indexed properties,
+    // like length for example.
+    if (hasLoadedProps) {
+      return addToCache(bucketNodes.concat(makeNodesForProperties(loadedProps, item)));
+    }
+
+    // We don't cache the result here so we can have the prototype, properties and symbols
+    // when they are loaded.
+    return bucketNodes;
+  }
+
+  if (!nodeIsEntries(item) && !nodeIsBucket(item) && !nodeHasProperties(item)) {
     return [];
   }
 
-  let children = makeNodesForProperties(loadedProps, item);
-  actors[key] = children;
-  return children;
+  if (!hasLoadedProps) {
+    return [];
+  }
+
+  return addToCache(makeNodesForProperties(loadedProps, item));
 }
 
 function getParent(item) {
   return item.parent;
 }
 
+function getNumericalPropertiesCount(item) {
+  if (nodeIsBucket(item)) {
+    return item.meta.endIndex - item.meta.startIndex + 1;
+  }
+
+  const value = getValue(getClosestGripNode(item));
+  if (!value) {
+    return 0;
+  }
+
+  if (GripArrayRep.supportsObject(value)) {
+    return GripArrayRep.getLength(value);
+  }
+
+  if (GripMap.supportsObject(value)) {
+    return GripMap.getLength(value);
+  }
+
+  // TODO: We can also have numerical properties on Objects, but at the
+  // moment we don't have a way to distinguish them from non-indexed properties,
+  // as they are all computed in a ownPropertiesLength property.
+
+  return 0;
+}
+
+function getClosestGripNode(item) {
+  const type = getType(item);
+  if (type !== NODE_TYPES.BUCKET && type !== NODE_TYPES.DEFAULT_PROPERTIES && type !== NODE_TYPES.ENTRIES) {
+    return item;
+  }
+
+  const parent = getParent(item);
+  if (!parent) {
+    return null;
+  }
+
+  return getClosestGripNode(parent);
+}
+
+function getClosestNonBucketNode(item) {
+  const type = getType(item);
+
+  if (type !== NODE_TYPES.BUCKET) {
+    return item;
+  }
+
+  const parent = getParent(item);
+  if (!parent) {
+    return null;
+  }
+
+  return getClosestNonBucketNode(parent);
+}
+
+function shouldLoadItemIndexedProperties(item, loadedProperties = new Map()) {
+  const gripItem = getClosestGripNode(item);
+  const value = getValue(gripItem);
+
+  return value && nodeHasProperties(gripItem) && !loadedProperties.has(item.path) && !nodeIsProxy(item) && !nodeNeedsNumericalBuckets(item) && !nodeIsEntries(getClosestNonBucketNode(item))
+  // The data is loaded when expanding the window node.
+  && !nodeIsDefaultProperties(item);
+}
+
+function shouldLoadItemNonIndexedProperties(item, loadedProperties = new Map()) {
+  const gripItem = getClosestGripNode(item);
+  const value = getValue(gripItem);
+
+  return value && nodeHasProperties(gripItem) && !loadedProperties.has(item.path) && !nodeIsProxy(item) && !nodeIsEntries(getClosestNonBucketNode(item)) && !nodeIsBucket(item)
+  // The data is loaded when expanding the window node.
+  && !nodeIsDefaultProperties(item);
+}
+
+function shouldLoadItemEntries(item, loadedProperties = new Map()) {
+  const gripItem = getClosestGripNode(item);
+  const value = getValue(gripItem);
+
+  return value && nodeIsEntries(getClosestNonBucketNode(item)) && !nodeHasAllEntriesInPreview(gripItem) && !loadedProperties.has(item.path) && !nodeNeedsNumericalBuckets(item);
+}
+
+function shouldLoadItemPrototype(item, loadedProperties = new Map()) {
+  const value = getValue(item);
+
+  return value && !loadedProperties.has(item.path) && !nodeIsBucket(item) && !nodeIsMapEntry(item) && !nodeIsEntries(item) && !nodeIsDefaultProperties(item) && !nodeHasAccessors(item) && !nodeIsPrimitive(item);
+}
+
+function shouldLoadItemSymbols(item, loadedProperties = new Map()) {
+  const value = getValue(item);
+
+  return value && !loadedProperties.has(item.path) && !nodeIsBucket(item) && !nodeIsMapEntry(item) && !nodeIsEntries(item) && !nodeIsDefaultProperties(item) && !nodeHasAccessors(item) && !nodeIsPrimitive(item) && !nodeIsProxy(item);
+}
+
 module.exports = {
   createNode,
   getChildren,
+  getClosestGripNode,
+  getClosestNonBucketNode,
   getParent,
+  getNumericalPropertiesCount,
   getValue,
   makeNodesForEntries,
   makeNodesForPromiseProperties,
   makeNodesForProperties,
+  makeNumericalBuckets,
   nodeHasAccessors,
   nodeHasAllEntriesInPreview,
   nodeHasChildren,
   nodeHasEntries,
   nodeHasProperties,
+  nodeIsBucket,
   nodeIsDefaultProperties,
   nodeIsEntries,
   nodeIsFunction,
   nodeIsGetter,
   nodeIsMapEntry,
   nodeIsMissingArguments,
   nodeIsObject,
   nodeIsOptimizedOut,
   nodeIsPrimitive,
   nodeIsPromise,
   nodeIsPrototype,
+  nodeIsProxy,
   nodeIsSetter,
   nodeIsWindow,
-  nodeSupportsBucketing,
+  nodeNeedsNumericalBuckets,
+  nodeSupportsNumericalBucketing,
   setNodeChildren,
+  shouldLoadItemEntries,
+  shouldLoadItemIndexedProperties,
+  shouldLoadItemNonIndexedProperties,
+  shouldLoadItemPrototype,
+  shouldLoadItemSymbols,
   sortProperties,
   NODE_TYPES,
   // Export for testing purpose.
   SAFE_PATH_PREFIX
 };
 
 /***/ }),
-/* 22 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var isArray = __webpack_require__(5),
-    isKey = __webpack_require__(63),
-    stringToPath = __webpack_require__(68),
-    toString = __webpack_require__(98);
-
-/**
- * Casts `value` to a path array if it's not one.
- *
- * @private
- * @param {*} value The value to inspect.
- * @param {Object} [object] The object to query keys on.
- * @returns {Array} Returns the cast property path array.
- */
-function castPath(value, object) {
-  if (isArray(value)) {
-    return value;
-  }
-  return isKey(value, object) ? [value] : stringToPath(toString(value));
-}
-
-module.exports = castPath;
-
-
-/***/ }),
-/* 23 */
+/* 15 */
 /***/ (function(module, exports, __webpack_require__) {
 
-var baseIsNative = __webpack_require__(75),
-    getValue = __webpack_require__(80);
-
-/**
- * Gets the native function at `key` of `object`.
- *
- * @private
- * @param {Object} object The object to query.
- * @param {string} key The key of the method to get.
- * @returns {*} Returns the function if it's native, else `undefined`.
- */
-function getNative(object, key) {
-  var value = getValue(object, key);
-  return baseIsNative(value) ? value : undefined;
-}
-
-module.exports = getNative;
-
-
-/***/ }),
-/* 24 */
-/***/ (function(module, exports) {
-
-/**
- * Checks if `value` is the
- * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
- * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
- *
- * @static
- * @memberOf _
- * @since 0.1.0
- * @category Lang
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is an object, else `false`.
- * @example
- *
- * _.isObject({});
- * // => true
- *
- * _.isObject([1, 2, 3]);
- * // => true
- *
- * _.isObject(_.noop);
- * // => true
- *
- * _.isObject(null);
- * // => false
- */
-function isObject(value) {
-  var type = typeof value;
-  return value != null && (type == 'object' || type == 'function');
-}
-
-module.exports = isObject;
-
-
-/***/ }),
-/* 25 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var isSymbol = __webpack_require__(11);
-
-/** Used as references for various `Number` constants. */
-var INFINITY = 1 / 0;
-
-/**
- * Converts `value` to a string key if it's not a string or symbol.
- *
- * @private
- * @param {*} value The value to inspect.
- * @returns {string|symbol} Returns the key.
- */
-function toKey(value) {
-  if (typeof value == 'string' || isSymbol(value)) {
-    return value;
-  }
-  var result = (value + '');
-  return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
-}
-
-module.exports = toKey;
-
-
-/***/ }),
-/* 26 */
-/***/ (function(module, exports, __webpack_require__) {
+"use strict";
+
 
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const { MODE } = __webpack_require__(2);
 const { REPS, getRep } = __webpack_require__(3);
-const ObjectInspector = __webpack_require__(56);
-const ObjectInspectorUtils = __webpack_require__(21);
+const ObjectInspector = __webpack_require__(42);
+const ObjectInspectorUtils = __webpack_require__(14);
 
 const {
   parseURLEncodedText,
   parseURLParams,
   maybeEscapePropertyName,
   getGripPreviewItems
 } = __webpack_require__(1);
 
@@ -2516,25 +2739,28 @@ module.exports = {
   parseURLEncodedText,
   parseURLParams,
   getGripPreviewItems,
   ObjectInspector,
   ObjectInspectorUtils
 };
 
 /***/ }),
-/* 27 */
+/* 16 */
 /***/ (function(module, exports) {
 
 // removed by extract-text-webpack-plugin
 
 /***/ }),
-/* 28 */
+/* 17 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Dependencies
 const React = __webpack_require__(0);
 
 const {
@@ -2549,33 +2775,36 @@ const { span } = React.DOM;
  * Renders undefined value
  */
 const Undefined = function () {
   return span({ className: "objectBox objectBox-undefined" }, "undefined");
 };
 
 function supportsObject(object, noGrip = false) {
   if (noGrip === true) {
-    return false;
+    return object === undefined;
   }
 
   return object && object.type && object.type == "undefined" || getGripType(object, noGrip) == "undefined";
 }
 
 // Exports from this module
 
 module.exports = {
   rep: wrapRender(Undefined),
   supportsObject
 };
 
 /***/ }),
-/* 29 */
+/* 18 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Dependencies
 const React = __webpack_require__(0);
 
 const { wrapRender } = __webpack_require__(1);
@@ -2587,17 +2816,17 @@ const { span } = React.DOM;
  * Renders null value
  */
 function Null(props) {
   return span({ className: "objectBox objectBox-null" }, "null");
 }
 
 function supportsObject(object, noGrip = false) {
   if (noGrip === true) {
-    return false;
+    return object === null;
   }
 
   if (object && object.type && object.type == "null") {
     return true;
   }
 
   return object == null;
 }
@@ -2605,19 +2834,22 @@ function supportsObject(object, noGrip =
 // Exports from this module
 
 module.exports = {
   rep: wrapRender(Null),
   supportsObject
 };
 
 /***/ }),
-/* 30 */
+/* 19 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Dependencies
 const React = __webpack_require__(0);
 const {
   escapeString,
@@ -2678,19 +2910,22 @@ function supportsObject(object, noGrip =
 
 // Exports from this module
 module.exports = {
   rep: wrapRender(LongStringRep),
   supportsObject
 };
 
 /***/ }),
-/* 31 */
+/* 20 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Dependencies
 const React = __webpack_require__(0);
 
 const {
@@ -2727,19 +2962,22 @@ function supportsObject(object, noGrip =
 // Exports from this module
 
 module.exports = {
   rep: wrapRender(Number),
   supportsObject
 };
 
 /***/ }),
-/* 32 */
+/* 21 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Dependencies
 const React = __webpack_require__(0);
 const {
   wrapRender
@@ -2925,19 +3163,22 @@ function supportsObject(object) {
 
 // Exports from this module
 module.exports = {
   rep: wrapRender(ObjectRep),
   supportsObject
 };
 
 /***/ }),
-/* 33 */
+/* 22 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Dependencies
 const React = __webpack_require__(0);
 
 const {
@@ -2971,19 +3212,22 @@ function supportsObject(object, noGrip =
 
 // Exports from this module
 module.exports = {
   rep: wrapRender(SymbolRep),
   supportsObject
 };
 
 /***/ }),
-/* 34 */
+/* 23 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Dependencies
 const React = __webpack_require__(0);
 
 const {
@@ -3016,19 +3260,22 @@ function supportsObject(object, noGrip =
 
 // Exports from this module
 module.exports = {
   rep: wrapRender(InfinityRep),
   supportsObject
 };
 
 /***/ }),
-/* 35 */
+/* 24 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Dependencies
 const React = __webpack_require__(0);
 
 const {
@@ -3052,19 +3299,22 @@ function supportsObject(object, noGrip =
 
 // Exports from this module
 module.exports = {
   rep: wrapRender(NaNRep),
   supportsObject
 };
 
 /***/ }),
-/* 36 */
+/* 25 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Dependencies
 const React = __webpack_require__(0);
 const {
   wrapRender
@@ -3120,33 +3370,36 @@ function supportsObject(object, noGrip =
 
 // Exports from this module
 module.exports = {
   rep: wrapRender(Accessor),
   supportsObject
 };
 
 /***/ }),
-/* 37 */
+/* 26 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // ReactJS
 const React = __webpack_require__(0);
 
 // Reps
 const {
   getGripType,
   isGrip,
   wrapRender
 } = __webpack_require__(1);
-const { rep: StringRep } = __webpack_require__(16);
+const { rep: StringRep } = __webpack_require__(5);
 
 // Shortcuts
 const { span } = React.DOM;
 
 /**
  * Renders DOM attribute
  */
 Attribute.propTypes = {
@@ -3156,18 +3409,18 @@ Attribute.propTypes = {
 function Attribute(props) {
   let {
     object
   } = props;
   let value = object.preview.value;
 
   return span({
     "data-link-actor-id": object.actor,
-    className: "objectLink-Attr"
-  }, span({ className: "attrTitle" }, getTitle(object)), span({ className: "attrEqual" }, "="), StringRep({ object: value }));
+    className: "objectBox-Attr"
+  }, span({ className: "attrName" }, getTitle(object)), span({ className: "attrEqual" }, "="), StringRep({ className: "attrValue", object: value }));
 }
 
 function getTitle(grip) {
   return grip.preview.nodeName;
 }
 
 // Registration
 function supportsObject(grip, noGrip = false) {
@@ -3179,19 +3432,22 @@ function supportsObject(grip, noGrip = f
 }
 
 module.exports = {
   rep: wrapRender(Attribute),
   supportsObject
 };
 
 /***/ }),
-/* 38 */
+/* 27 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // ReactJS
 const React = __webpack_require__(0);
 
 // Reps
@@ -3243,19 +3499,22 @@ function supportsObject(grip, noGrip = f
 
 // Exports from this module
 module.exports = {
   rep: wrapRender(DateTime),
   supportsObject
 };
 
 /***/ }),
-/* 39 */
+/* 28 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // ReactJS
 const React = __webpack_require__(0);
 
 // Reps
@@ -3276,18 +3535,18 @@ Document.propTypes = {
   object: React.PropTypes.object.isRequired
 };
 
 function Document(props) {
   let grip = props.object;
 
   return span({
     "data-link-actor-id": grip.actor,
-    className: "objectBox objectBox-object"
-  }, getTitle(grip), span({ className: "objectPropValue" }, getLocation(grip)));
+    className: "objectBox objectBox-document"
+  }, getTitle(grip), span({ className: "location" }, getLocation(grip)));
 }
 
 function getLocation(grip) {
   let location = grip.preview.location;
   return location ? getURLDisplayString(location) : "";
 }
 
 function getTitle(grip) {
@@ -3307,34 +3566,37 @@ function supportsObject(object, noGrip =
 
 // Exports from this module
 module.exports = {
   rep: wrapRender(Document),
   supportsObject
 };
 
 /***/ }),
-/* 40 */
+/* 29 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // ReactJS
 const React = __webpack_require__(0);
 
 // Reps
 const {
   isGrip,
   wrapRender
 } = __webpack_require__(1);
 
 const { MODE } = __webpack_require__(2);
-const { rep } = __webpack_require__(9);
+const { rep } = __webpack_require__(6);
 
 /**
  * Renders DOM event objects.
  */
 Event.propTypes = {
   object: React.PropTypes.object.isRequired,
   // @TODO Change this to Object.values once it's supported in Node's version of V8
   mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
@@ -3411,33 +3673,37 @@ function supportsObject(grip, noGrip = f
 
 // Exports from this module
 module.exports = {
   rep: wrapRender(Event),
   supportsObject
 };
 
 /***/ }),
-/* 41 */
+/* 30 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // ReactJS
 const React = __webpack_require__(0);
 
 // Reps
 const {
   getGripType,
   isGrip,
   cropString,
   wrapRender
 } = __webpack_require__(1);
+const { MODE } = __webpack_require__(2);
 
 // Shortcuts
 const { span } = React.DOM;
 
 /**
  * This component represents a template for Function objects.
  */
 FunctionRep.propTypes = {
@@ -3449,32 +3715,32 @@ function FunctionRep(props) {
   let grip = props.object;
 
   return span({
     "data-link-actor-id": grip.actor,
     className: "objectBox objectBox-function",
     // Set dir="ltr" to prevent function parentheses from
     // appearing in the wrong direction
     dir: "ltr"
-  }, getTitle(props, grip), getFunctionName(grip, props), "(", ...renderParams(props), ")");
-}
-
-function getTitle(props, grip) {
+  }, getTitle(grip, props), getFunctionName(grip, props), "(", ...renderParams(props), ")");
+}
+
+function getTitle(grip, props) {
   const {
-    simplified
+    mode
   } = props;
 
-  if (simplified === true && !grip.isGenerator && !grip.isAsync) {
+  if (mode === MODE.TINY && !grip.isGenerator && !grip.isAsync) {
     return null;
   }
 
-  let title = simplified === true ? "" : "function ";
+  let title = mode === MODE.TINY ? "" : "function ";
 
   if (grip.isGenerator) {
-    title = simplified === true ? "* " : "function* ";
+    title = mode === MODE.TINY ? "* " : "function* ";
   }
 
   if (grip.isAsync) {
     title = "async" + " " + title;
   }
 
   return span({
     className: "objectTitle"
@@ -3513,19 +3779,22 @@ function supportsObject(grip, noGrip = f
 // Exports from this module
 
 module.exports = {
   rep: wrapRender(FunctionRep),
   supportsObject
 };
 
 /***/ }),
-/* 42 */
+/* 31 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // ReactJS
 const React = __webpack_require__(0);
 // Dependencies
 const {
@@ -3619,19 +3888,22 @@ function supportsObject(object, noGrip =
 
 // Exports from this module
 module.exports = {
   rep: wrapRender(PromiseRep),
   supportsObject
 };
 
 /***/ }),
-/* 43 */
+/* 32 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // ReactJS
 const React = __webpack_require__(0);
 
 // Reps
@@ -3672,19 +3944,22 @@ function supportsObject(object, noGrip =
 
 // Exports from this module
 module.exports = {
   rep: wrapRender(RegExp),
   supportsObject
 };
 
 /***/ }),
-/* 44 */
+/* 33 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // ReactJS
 const React = __webpack_require__(0);
 
 // Reps
@@ -3737,33 +4012,36 @@ function supportsObject(object, noGrip =
 // Exports from this module
 
 module.exports = {
   rep: wrapRender(StyleSheet),
   supportsObject
 };
 
 /***/ }),
-/* 45 */
+/* 34 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Dependencies
 const React = __webpack_require__(0);
 const {
   isGrip,
   cropString,
   cropMultipleLines,
   wrapRender
 } = __webpack_require__(1);
 const { MODE } = __webpack_require__(2);
-const nodeConstants = __webpack_require__(18);
+const nodeConstants = __webpack_require__(8);
 
 // Shortcuts
 const { span } = React.DOM;
 
 /**
  * Renders DOM comment node.
  */
 CommentNode.propTypes = {
@@ -3801,34 +4079,38 @@ function supportsObject(object, noGrip =
 
 // Exports from this module
 module.exports = {
   rep: wrapRender(CommentNode),
   supportsObject
 };
 
 /***/ }),
-/* 46 */
+/* 35 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // ReactJS
 const React = __webpack_require__(0);
 
 // Utils
 const {
   isGrip,
   wrapRender
 } = __webpack_require__(1);
+const { rep: StringRep } = __webpack_require__(5);
 const { MODE } = __webpack_require__(2);
-const nodeConstants = __webpack_require__(18);
-const Svg = __webpack_require__(10);
+const nodeConstants = __webpack_require__(8);
+const Svg = __webpack_require__(9);
 
 // Shortcuts
 const { span } = React.DOM;
 
 /**
  * Renders DOM element node.
  */
 ElementNode.propTypes = {
@@ -3882,46 +4164,46 @@ function ElementNode(props) {
   }
 
   return span(baseConfig, ...elements, inspectIcon);
 }
 
 function getElements(grip, mode) {
   let { attributes, nodeName } = grip.preview;
   const nodeNameElement = span({
-    className: "tag-name theme-fg-color3"
+    className: "tag-name"
   }, nodeName);
 
   if (mode === MODE.TINY) {
     let elements = [nodeNameElement];
     if (attributes.id) {
-      elements.push(span({ className: "attr-name theme-fg-color2" }, `#${attributes.id}`));
+      elements.push(span({ className: "attrName" }, `#${attributes.id}`));
     }
     if (attributes.class) {
-      elements.push(span({ className: "attr-name theme-fg-color2" }, attributes.class.replace(/(^\s+)|(\s+$)/g, "").split(" ").map(cls => `.${cls}`).join("")));
+      elements.push(span({ className: "attrName" }, attributes.class.trim().split(/\s+/).map(cls => `.${cls}`).join("")));
     }
     return elements;
   }
   let attributeKeys = Object.keys(attributes);
   if (attributeKeys.includes("class")) {
     attributeKeys.splice(attributeKeys.indexOf("class"), 1);
     attributeKeys.unshift("class");
   }
   if (attributeKeys.includes("id")) {
     attributeKeys.splice(attributeKeys.indexOf("id"), 1);
     attributeKeys.unshift("id");
   }
   const attributeElements = attributeKeys.reduce((arr, name, i, keys) => {
     let value = attributes[name];
-    let attribute = span({}, span({ className: "attr-name theme-fg-color2" }, `${name}`), `="`, span({ className: "attr-value theme-fg-color6" }, `${value}`), `"`);
+    let attribute = span({}, span({ className: "attrName" }, name), span({ className: "attrEqual" }, "="), StringRep({ className: "attrValue", object: value }));
 
     return arr.concat([" ", attribute]);
   }, []);
 
-  return ["<", nodeNameElement, ...attributeElements, ">"];
+  return [span({ className: "angleBracket" }, "<"), nodeNameElement, ...attributeElements, span({ className: "angleBracket" }, ">")];
 }
 
 // Registration
 function supportsObject(object, noGrip = false) {
   if (noGrip === true || !isGrip(object)) {
     return false;
   }
   return object.preview && object.preview.nodeType === nodeConstants.ELEMENT_NODE;
@@ -3929,199 +4211,43 @@ function supportsObject(object, noGrip =
 
 // Exports from this module
 module.exports = {
   rep: wrapRender(ElementNode),
   supportsObject
 };
 
 /***/ }),
-/* 47 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-Object.defineProperty(exports, '__esModule', {
-    value: 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; };
-
-var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
-
-var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
-
-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 _react = __webpack_require__(0);
-
-var _react2 = _interopRequireDefault(_react);
-
-var DOMParser = typeof window !== 'undefined' && window.DOMParser;
-var process = process || {};
-process.env = process.env || {};
-var parserAvailable = typeof DOMParser !== 'undefined' && DOMParser.prototype != null && DOMParser.prototype.parseFromString != null;
-
-function isParsable(src) {
-    // kinda naive but meh, ain't gonna use full-blown parser for this
-    return parserAvailable && typeof src === 'string' && src.trim().substr(0, 4) === '<svg';
-}
-
-// parse SVG string using `DOMParser`
-function parseFromSVGString(src) {
-    var parser = new DOMParser();
-    return parser.parseFromString(src, "image/svg+xml");
-}
-
-// Transform DOM prop/attr names applicable to `<svg>` element but react-limited
-function switchSVGAttrToReactProp(propName) {
-    switch (propName) {
-        case 'class':
-            return 'className';
-        default:
-            return propName;
-    }
-}
-
-var InlineSVG = (function (_React$Component) {
-    _inherits(InlineSVG, _React$Component);
-
-    _createClass(InlineSVG, null, [{
-        key: 'defaultProps',
-        value: {
-            element: 'i',
-            raw: false,
-            src: ''
-        },
-        enumerable: true
-    }, {
-        key: 'propTypes',
-        value: {
-            src: _react2['default'].PropTypes.string.isRequired,
-            element: _react2['default'].PropTypes.string,
-            raw: _react2['default'].PropTypes.bool
-        },
-        enumerable: true
-    }]);
-
-    function InlineSVG(props) {
-        _classCallCheck(this, InlineSVG);
-
-        _get(Object.getPrototypeOf(InlineSVG.prototype), 'constructor', this).call(this, props);
-        this._extractSVGProps = this._extractSVGProps.bind(this);
-    }
-
-    // Serialize `Attr` objects in `NamedNodeMap`
-
-    _createClass(InlineSVG, [{
-        key: '_serializeAttrs',
-        value: function _serializeAttrs(map) {
-            var ret = {};
-            var prop = undefined;
-            for (var i = 0; i < map.length; i++) {
-                prop = switchSVGAttrToReactProp(map[i].name);
-                ret[prop] = map[i].value;
-            }
-            return ret;
-        }
-
-        // get <svg /> element props
-    }, {
-        key: '_extractSVGProps',
-        value: function _extractSVGProps(src) {
-            var map = parseFromSVGString(src).documentElement.attributes;
-            return map.length > 0 ? this._serializeAttrs(map) : null;
-        }
-
-        // get content inside <svg> element.
-    }, {
-        key: '_stripSVG',
-        value: function _stripSVG(src) {
-            return parseFromSVGString(src).documentElement.innerHTML;
-        }
-    }, {
-        key: 'componentWillReceiveProps',
-        value: function componentWillReceiveProps(_ref) {
-            var children = _ref.children;
-
-            if ("production" !== process.env.NODE_ENV && children != null) {
-                console.info('<InlineSVG />: `children` prop will be ignored.');
-            }
-        }
-    }, {
-        key: 'render',
-        value: function render() {
-            var Element = undefined,
-                __html = undefined,
-                svgProps = undefined;
-            var _props = this.props;
-            var element = _props.element;
-            var raw = _props.raw;
-            var src = _props.src;
-
-            var otherProps = _objectWithoutProperties(_props, ['element', 'raw', 'src']);
-
-            if (raw === true && isParsable(src)) {
-                Element = 'svg';
-                svgProps = this._extractSVGProps(src);
-                __html = this._stripSVG(src);
-            }
-            __html = __html || src;
-            Element = Element || element;
-            svgProps = svgProps || {};
-
-            return _react2['default'].createElement(Element, _extends({}, svgProps, otherProps, { src: null, children: null,
-                dangerouslySetInnerHTML: { __html: __html } }));
-        }
-    }]);
-
-    return InlineSVG;
-})(_react2['default'].Component);
-
-exports['default'] = InlineSVG;
-module.exports = exports['default'];
-
-/***/ }),
-/* 48 */
-/***/ (function(module, exports) {
-
-module.exports = "<!-- This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. --><svg viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M8 13.4c-.5 0-.9-.2-1.2-.6L.4 5.2C0 4.7-.1 4.3.2 3.7S1 3 1.6 3h12.8c.6 0 1.2.1 1.4.7.3.6.2 1.1-.2 1.6l-6.4 7.6c-.3.4-.7.5-1.2.5z\"></path></svg>"
-
-/***/ }),
-/* 49 */
+/* 36 */
 /***/ (function(module, exports) {
 
 module.exports = "<!-- This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. --><svg viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M8,3L12,3L12,7L14,7L14,8L12,8L12,12L8,12L8,14L7,14L7,12L3,12L3,8L1,8L1,7L3,7L3,3L7,3L7,1L8,1L8,3ZM10,10L10,5L5,5L5,10L10,10Z\"></path></svg>"
 
 /***/ }),
-/* 50 */
+/* 37 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // ReactJS
 const React = __webpack_require__(0);
 
 // Reps
 const {
   isGrip,
   cropString,
   wrapRender
 } = __webpack_require__(1);
 const { MODE } = __webpack_require__(2);
-const Svg = __webpack_require__(10);
+const Svg = __webpack_require__(9);
 
 // Shortcuts
 const DOM = React.DOM;
 
 /**
  * Renders DOM #text node.
  */
 TextNode.propTypes = {
@@ -4200,19 +4326,22 @@ function supportsObject(grip, noGrip = f
 
 // Exports from this module
 module.exports = {
   rep: wrapRender(TextNode),
   supportsObject
 };
 
 /***/ }),
-/* 51 */
+/* 38 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // ReactJS
 const React = __webpack_require__(0);
 // Utils
 const {
@@ -4266,19 +4395,22 @@ function supportsObject(object, noGrip =
 
 // Exports from this module
 module.exports = {
   rep: wrapRender(ErrorRep),
   supportsObject
 };
 
 /***/ }),
-/* 52 */
+/* 39 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // ReactJS
 const React = __webpack_require__(0);
 
 // Reps
@@ -4313,22 +4445,22 @@ function WindowRep(props) {
     "data-link-actor-id": object.actor,
     className: "objectBox objectBox-Window"
   };
 
   if (mode === MODE.TINY) {
     return span(config, getTitle(object));
   }
 
-  return span(config, getTitle(object), " ", span({ className: "objectPropValue" }, getLocation(object)));
+  return span(config, getTitle(object), " ", span({ className: "location" }, getLocation(object)));
 }
 
 function getTitle(object) {
   let title = object.displayClass || object.class || "Window";
-  return span({ className: "objectBoxTitle" }, title);
+  return span({ className: "objectTitle" }, title);
 }
 
 function getLocation(object) {
   return getURLDisplayString(object.preview.url);
 }
 
 // Registration
 function supportsObject(object, noGrip = false) {
@@ -4341,19 +4473,22 @@ function supportsObject(object, noGrip =
 
 // Exports from this module
 module.exports = {
   rep: wrapRender(WindowRep),
   supportsObject
 };
 
 /***/ }),
-/* 53 */
+/* 40 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // ReactJS
 const React = __webpack_require__(0);
 
 // Reps
@@ -4399,19 +4534,22 @@ function supportsObject(grip, noGrip = f
 
 // Exports from this module
 module.exports = {
   rep: wrapRender(ObjectWithText),
   supportsObject
 };
 
 /***/ }),
-/* 54 */
+/* 41 */
 /***/ (function(module, exports, __webpack_require__) {
 
+"use strict";
+
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // ReactJS
 const React = __webpack_require__(0);
 
 // Reps
@@ -4462,263 +4600,87 @@ function supportsObject(grip, noGrip = f
 
 // Exports from this module
 module.exports = {
   rep: wrapRender(ObjectWithURL),
   supportsObject
 };
 
 /***/ }),
-/* 55 */
+/* 42 */
 /***/ (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/. */
-
-// Dependencies
-const React = __webpack_require__(0);
-const {
-  isGrip,
-  wrapRender
-} = __webpack_require__(1);
-const PropRep = __webpack_require__(4);
-const { MODE } = __webpack_require__(2);
-// Shortcuts
-const { span } = React.DOM;
-
-/**
- * Renders an map. A map is represented by a list of its
- * entries enclosed in curly brackets.
- */
-GripMap.propTypes = {
-  object: React.PropTypes.object,
-  // @TODO Change this to Object.values once it's supported in Node's version of V8
-  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
-  isInterestingEntry: React.PropTypes.func,
-  onDOMNodeMouseOver: React.PropTypes.func,
-  onDOMNodeMouseOut: React.PropTypes.func,
-  onInspectIconClick: React.PropTypes.func,
-  title: React.PropTypes.string
-};
-
-function GripMap(props) {
-  let {
-    mode,
-    object
-  } = props;
-
-  const config = {
-    "data-link-actor-id": object.actor,
-    className: "objectBox objectBox-object"
-  };
-
-  if (mode === MODE.TINY) {
-    return span(config, getTitle(props, object));
-  }
-
-  let propsArray = safeEntriesIterator(props, object, maxLengthMap.get(mode));
-
-  return span(config, getTitle(props, object), span({
-    className: "objectLeftBrace"
-  }, " { "), ...propsArray, span({
-    className: "objectRightBrace"
-  }, " }"));
-}
-
-function getTitle(props, object) {
-  let title = props.title || (object && object.class ? object.class : "Map");
-  return span({
-    className: "objectTitle"
-  }, title);
-}
-
-function safeEntriesIterator(props, object, max) {
-  max = typeof max === "undefined" ? 3 : max;
-  try {
-    return entriesIterator(props, object, max);
-  } catch (err) {
-    console.error(err);
-  }
-  return [];
-}
-
-function entriesIterator(props, object, max) {
-  // Entry filter. Show only interesting entries to the user.
-  let isInterestingEntry = props.isInterestingEntry || ((type, value) => {
-    return type == "boolean" || type == "number" || type == "string" && value.length != 0;
-  });
-
-  let mapEntries = object.preview && object.preview.entries ? object.preview.entries : [];
-
-  let indexes = 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(getEntriesIndexes(mapEntries, max - indexes.length, (t, value, name) => {
-      return !isInterestingEntry(t, value, name);
-    }));
-  }
-
-  let entries = getEntries(props, mapEntries, indexes);
-  if (entries.length < object.preview.size) {
-    // There are some undisplayed entries. Then display "…".
-    entries.push(span({
-      key: "more",
-      className: "more-ellipsis",
-      title: "more…"
-    }, "…"));
-  }
-
-  return unfoldEntries(entries);
-}
-
-function unfoldEntries(items) {
-  return items.reduce((res, item, index) => {
-    if (Array.isArray(item)) {
-      res = res.concat(item);
-    } else {
-      res.push(item);
-    }
-
-    // Interleave commas between elements
-    if (index !== items.length - 1) {
-      res.push(", ");
-    }
-    return res;
-  }, []);
-}
-
-/**
- * Get entries ordered by index.
- *
- * @param {Object} props Component props.
- * @param {Array} entries Entries array.
- * @param {Array} indexes Indexes of entries.
- * @return {Array} Array of PropRep.
- */
-function getEntries(props, entries, indexes) {
-  let {
-    onDOMNodeMouseOver,
-    onDOMNodeMouseOut,
-    onInspectIconClick
-  } = props;
-
-  // Make indexes ordered by ascending.
-  indexes.sort(function (a, b) {
-    return a - b;
-  });
-
-  return indexes.map((index, i) => {
-    let [key, entryValue] = entries[index];
-    let value = entryValue.value !== undefined ? entryValue.value : entryValue;
-
-    return PropRep({
-      name: key,
-      equal: " \u2192 ",
-      object: value,
-      mode: MODE.TINY,
-      onDOMNodeMouseOver,
-      onDOMNodeMouseOut,
-      onInspectIconClick
-    });
-  });
-}
-
-/**
- * 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.
- */
-function getEntriesIndexes(entries, max, filter) {
-  return entries.reduce((indexes, [key, entry], i) => {
-    if (indexes.length < max) {
-      let value = entry && entry.value !== undefined ? entry.value : entry;
-      // Type is specified in grip's "class" field and for primitive
-      // values use typeof.
-      let type = (value && value.class ? value.class : typeof value).toLowerCase();
-
-      if (filter(type, value, key)) {
-        indexes.push(i);
-      }
-    }
-
-    return indexes;
-  }, []);
-}
-
-function supportsObject(grip, noGrip = false) {
-  if (noGrip === true || !isGrip(grip)) {
-    return false;
-  }
-  return grip.preview && grip.preview.kind == "MapLike";
-}
-
-const maxLengthMap = new Map();
-maxLengthMap.set(MODE.SHORT, 3);
-maxLengthMap.set(MODE.LONG, 10);
-
-// Exports from this module
-module.exports = {
-  rep: wrapRender(GripMap),
-  supportsObject,
-  maxLengthMap
-};
-
-/***/ }),
-/* 56 */
-/***/ (function(module, exports, __webpack_require__) {
+"use strict";
+
+
+var _devtoolsComponents = __webpack_require__(43);
+
+var _devtoolsComponents2 = _interopRequireDefault(_devtoolsComponents);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
 
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const {
   Component,
   createFactory,
   DOM: dom,
   PropTypes
 } = __webpack_require__(0);
 
-const Tree = createFactory(__webpack_require__(57).Tree);
-__webpack_require__(59);
-
-const classnames = __webpack_require__(60);
-const Svg = __webpack_require__(10);
+const Tree = createFactory(_devtoolsComponents2.default.Tree);
+__webpack_require__(47);
+
+const classnames = __webpack_require__(48);
+
 const {
   REPS: {
     Rep,
     Grip
   }
 } = __webpack_require__(3);
 const {
   MODE
 } = __webpack_require__(2);
 
 const {
   getChildren,
+  getClosestGripNode,
   getParent,
   getValue,
   nodeHasAccessors,
-  nodeHasAllEntriesInPreview,
   nodeHasProperties,
   nodeIsDefaultProperties,
-  nodeIsEntries,
+  nodeIsFunction,
   nodeIsGetter,
   nodeIsMapEntry,
-  nodeIsFunction,
   nodeIsMissingArguments,
   nodeIsOptimizedOut,
   nodeIsPrimitive,
   nodeIsPrototype,
   nodeIsSetter,
-  nodeIsWindow
-} = __webpack_require__(21);
+  nodeIsWindow,
+  shouldLoadItemEntries,
+  shouldLoadItemIndexedProperties,
+  shouldLoadItemNonIndexedProperties,
+  shouldLoadItemPrototype,
+  shouldLoadItemSymbols
+} = __webpack_require__(14);
+
+const {
+  enumEntries,
+  enumIndexedProperties,
+  enumNonIndexedProperties,
+  getPrototype,
+  enumSymbols
+} = __webpack_require__(50);
 
 // This implements a component that renders an interactive inspector
 // for looking at JavaScript objects. It expects descriptions of
 // objects from the protocol, and will dynamically fetch child
 // properties as objects are expanded.
 //
 // If you want to inspect a single object, pass the name and the
 // protocol descriptor of it:
@@ -4738,90 +4700,194 @@ const {
 //  });
 
 // There are 3 types of nodes: a simple node with a children array, an
 // object that has properties that should be children when they are
 // fetched, and a primitive value that should be displayed with no
 // children.
 
 class ObjectInspector extends Component {
-  constructor() {
+  constructor(props) {
     super();
-
-    this.actors = {};
+    this.cachedNodes = new Map();
+
     this.state = {
-      expandedKeys: new Set(),
-      focusedItem: null
+      actors: new Set(),
+      expandedPaths: new Set(),
+      focusedItem: null,
+      loadedProperties: props.loadedProperties || new Map(),
+      loading: new Map()
     };
 
     const self = this;
 
     self.getChildren = this.getChildren.bind(this);
     self.renderTreeItem = this.renderTreeItem.bind(this);
     self.setExpanded = this.setExpanded.bind(this);
     self.focusItem = this.focusItem.bind(this);
     self.getRoots = this.getRoots.bind(this);
   }
 
+  shouldComponentUpdate(nextProps, nextState) {
+    const {
+      expandedPaths,
+      loadedProperties
+    } = this.state;
+
+    return expandedPaths.size !== nextState.expandedPaths.size || loadedProperties.size !== nextState.loadedProperties.size || [...expandedPaths].some(key => !nextState.expandedPaths.has(key));
+  }
+
+  componentWillUnmount() {
+    const { releaseActor } = this.props;
+    if (typeof releaseActor !== "function") {
+      return;
+    }
+
+    const { actors } = this.state;
+    for (let actor of actors) {
+      releaseActor(actor);
+    }
+  }
+
   getChildren(item) {
     const {
-      getObjectEntries,
-      getObjectProperties
-    } = this.props;
-    const { actors } = this;
+      loadedProperties
+    } = this.state;
+    const { cachedNodes } = this;
 
     return getChildren({
-      getObjectEntries,
-      getObjectProperties,
-      actors,
+      loadedProperties,
+      cachedNodes,
       item
     });
   }
 
   getRoots() {
     return this.props.roots;
   }
 
   getKey(item) {
     return item.path;
   }
 
+  /**
+   * This function is responsible for expanding/collapsing a given node,
+   * which also means that it will check if we need to fetch properties,
+   * entries, prototype and symbols for the said node. If we do, it will call
+   * the appropriate ObjectClient functions, and change the state of the component
+   * with the results it gets from those functions.
+   */
   setExpanded(item, expand) {
-    const { expandedKeys } = this.state;
-    const key = this.getKey(item);
-
-    if (expand === true) {
-      expandedKeys.add(key);
-    } else {
-      expandedKeys.delete(key);
-    }
-
-    this.setState({ expandedKeys });
-
-    if (expand === true) {
+    var _this = this;
+
+    return _asyncToGenerator(function* () {
+      if (nodeIsPrimitive(item)) {
+        return;
+      }
+
       const {
-        getObjectProperties,
-        getObjectEntries,
-        loadObjectProperties,
-        loadObjectEntries
-      } = this.props;
-
-      const value = getValue(item);
-      const parent = getParent(item);
-      const parentValue = getValue(parent);
-      const parentActor = parentValue ? parentValue.actor : null;
-
-      if (nodeHasProperties(item) && value && !getObjectProperties(value.actor)) {
-        loadObjectProperties(value);
+        loadedProperties
+      } = _this.state;
+
+      const key = _this.getKey(item);
+
+      _this.setState(function (prevState, props) {
+        const newPaths = new Set(prevState.expandedPaths);
+        if (expand === true) {
+          newPaths.add(key);
+        } else {
+          newPaths.delete(key);
+        }
+        return {
+          expandedPaths: newPaths
+        };
+      });
+
+      if (expand === true) {
+        const gripItem = getClosestGripNode(item);
+        const value = getValue(gripItem);
+
+        const path = item.path;
+        const [start, end] = item.meta ? [item.meta.startIndex, item.meta.endIndex] : [];
+
+        let promises = [];
+        let objectClient;
+        const getObjectClient = function () {
+          if (objectClient) {
+            return objectClient;
+          }
+          return _this.props.createObjectClient(value);
+        };
+
+        if (shouldLoadItemIndexedProperties(item, loadedProperties)) {
+          promises.push(enumIndexedProperties(getObjectClient(), start, end));
+        }
+
+        if (shouldLoadItemNonIndexedProperties(item, loadedProperties)) {
+          promises.push(enumNonIndexedProperties(getObjectClient(), start, end));
+        }
+
+        if (shouldLoadItemEntries(item, loadedProperties)) {
+          promises.push(enumEntries(getObjectClient(), start, end));
+        }
+
+        if (shouldLoadItemPrototype(item, loadedProperties)) {
+          promises.push(getPrototype(getObjectClient()));
+        }
+
+        if (shouldLoadItemSymbols(item, loadedProperties)) {
+          promises.push(enumSymbols(getObjectClient(), start, end));
+        }
+
+        if (promises.length > 0) {
+          // Set the loading state with the pending promises.
+          _this.setState(function (prevState, props) {
+            const nextLoading = new Map(prevState.loading);
+            nextLoading.set(path, promises);
+            return {
+              loading: nextLoading
+            };
+          });
+
+          const responses = yield Promise.all(promises);
+
+          // Let's loop through the responses to build a single response object.
+          const response = responses.reduce(function (accumulator, res) {
+            Object.entries(res).forEach(function ([k, v]) {
+              if (accumulator.hasOwnProperty(k)) {
+                if (Array.isArray(accumulator[k])) {
+                  accumulator[k].push(...v);
+                } else if (typeof accumulator[k] === "object") {
+                  accumulator[k] = Object.assign({}, accumulator[k], v);
+                }
+              } else {
+                accumulator[k] = v;
+              }
+            });
+            return accumulator;
+          }, {});
+
+          _this.setState(function (prevState, props) {
+            const nextLoading = new Map(prevState.loading);
+            nextLoading.delete(path);
+
+            const isRoot = _this.props.roots.some(function (root) {
+              const rootValue = getValue(root);
+              return rootValue && rootValue.actor === value.actor;
+            });
+
+            return {
+              actors: isRoot ? prevState.actors : new Set(prevState.actors).add(value.actor),
+              loadedProperties: new Map(prevState.loadedProperties).set(path, response),
+              loading: nextLoading
+            };
+          });
+        }
       }
-
-      if (nodeIsEntries(item) && !nodeHasAllEntriesInPreview(parent) && parentActor && !getObjectEntries(parentActor)) {
-        loadObjectEntries(parentValue);
-      }
-    }
+    })();
   }
 
   focusItem(item) {
     if (!this.props.disabledFocus && this.state.focusedItem !== item) {
       this.setState({
         focusedItem: item
       });
 
@@ -4839,79 +4905,73 @@ class ObjectInspector extends Component 
     const isPrimitive = nodeIsPrimitive(item);
 
     const unavailable = isPrimitive && itemValue && itemValue.hasOwnProperty && itemValue.hasOwnProperty("unavailable");
 
     if (nodeIsOptimizedOut(item)) {
       objectValue = dom.span({ className: "unavailable" }, "(optimized away)");
     } else if (nodeIsMissingArguments(item) || unavailable) {
       objectValue = dom.span({ className: "unavailable" }, "(unavailable)");
-    } else if (nodeIsFunction(item) && !nodeIsGetter(item) && !nodeIsSetter(item)) {
+    } else if (nodeIsFunction(item) && !nodeIsGetter(item) && !nodeIsSetter(item) && (this.props.mode === MODE.TINY || !this.props.mode)) {
       objectValue = undefined;
       label = this.renderGrip(item, Object.assign({}, this.props, {
-        simplified: depth !== 0,
         functionName: label
       }));
     } else if (nodeHasProperties(item) || nodeHasAccessors(item) || nodeIsMapEntry(item) || isPrimitive) {
       let repsProp = Object.assign({}, this.props);
       if (depth > 0) {
         repsProp.mode = this.props.mode === MODE.LONG ? MODE.SHORT : MODE.TINY;
       }
+      if (expanded) {
+        repsProp.mode = MODE.TINY;
+      }
 
       objectValue = this.renderGrip(item, repsProp);
     }
 
     const hasLabel = label !== null && typeof label !== "undefined";
     const hasValue = typeof objectValue !== "undefined";
 
-    const SINGLE_INDENT_WIDTH = 15;
-    const indentWidth = (depth + (isPrimitive ? 1 : 0)) * SINGLE_INDENT_WIDTH;
-
     const {
       onDoubleClick,
       onLabelClick,
       dimTopLevelWindow
     } = this.props;
 
     return dom.div({
       className: classnames("node object-node", {
         focused,
         lessen: !expanded && (nodeIsDefaultProperties(item) || nodeIsPrototype(item) || dimTopLevelWindow === true && nodeIsWindow(item) && depth === 0)
       }),
-      style: {
-        marginLeft: indentWidth
+      onClick: e => {
+        e.stopPropagation();
+        if (isPrimitive === false) {
+          this.setExpanded(item, !expanded);
+        }
       },
-      onClick: isPrimitive === false ? e => {
-        e.stopPropagation();
-        this.setExpanded(item, !expanded);
-      } : null,
       onDoubleClick: onDoubleClick ? e => {
         e.stopPropagation();
         onDoubleClick(item, {
           depth,
           focused,
           expanded
         });
       } : null
-    }, isPrimitive === false ? Svg("arrow", {
-      className: classnames({
-        expanded: expanded
-      })
-    }) : null, hasLabel ? dom.span({
+    }, arrow, hasLabel ? dom.span({
       className: "object-label",
       onClick: onLabelClick ? event => {
         event.stopPropagation();
         onLabelClick(item, {
           depth,
           focused,
           expanded,
           setExpanded: this.setExpanded
         });
       } : null
-    }, label) : null, hasLabel && hasValue ? dom.span({ className: "object-delimiter" }, " : ") : null, hasValue ? objectValue : null);
+    }, label) : null, hasLabel && hasValue ? dom.span({ className: "object-delimiter" }, ": ") : null, hasValue ? objectValue : null);
   }
 
   renderGrip(item, props) {
     const object = getValue(item);
     return Rep(Object.assign({}, props, {
       object,
       mode: props.mode || MODE.TINY,
       defaultRep: Grip
@@ -4924,40 +4984,42 @@ class ObjectInspector extends Component 
       autoExpandAll = true,
       disabledFocus,
       inline,
       itemHeight = 20,
       disableWrap = false
     } = this.props;
 
     const {
-      expandedKeys,
+      expandedPaths,
       focusedItem
     } = this.state;
 
     let roots = this.getRoots();
     if (roots.length === 1) {
       const root = roots[0];
       const name = root && root.name;
       if (nodeIsPrimitive(root) && (name === null || typeof name === "undefined")) {
         return this.renderGrip(root, this.props);
       }
     }
 
     return Tree({
       className: classnames({
         inline,
-        nowrap: disableWrap
+        nowrap: disableWrap,
+        "object-inspector": true
       }),
       autoExpandAll,
       autoExpandDepth,
       disabledFocus,
       itemHeight,
 
-      isExpanded: item => expandedKeys.has(this.getKey(item)),
+      isExpanded: item => expandedPaths.has(this.getKey(item)),
+      isExpandable: item => nodeIsPrimitive(item) === false,
       focused: focusedItem,
 
       getRoots: this.getRoots,
       getParent,
       getChildren: this.getChildren,
       getKey: this.getKey,
 
       onExpand: item => this.setExpanded(item, true),
@@ -4973,143 +5035,193 @@ ObjectInspector.displayName = "ObjectIns
 
 ObjectInspector.propTypes = {
   autoExpandAll: PropTypes.bool,
   autoExpandDepth: PropTypes.number,
   disabledFocus: PropTypes.bool,
   disableWrap: PropTypes.bool,
   inline: PropTypes.bool,
   roots: PropTypes.array,
-  getObjectProperties: PropTypes.func.isRequired,
-  loadObjectProperties: PropTypes.func.isRequired,
   itemHeight: PropTypes.number,
   mode: PropTypes.oneOf(Object.values(MODE)),
+  createObjectClient: PropTypes.func.isRequired,
   onFocus: PropTypes.func,
   onDoubleClick: PropTypes.func,
   onLabelClick: PropTypes.func
 };
 
 module.exports = ObjectInspector;
 
 /***/ }),
-/* 57 */
+/* 43 */
 /***/ (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/. */
-
-const Tree = __webpack_require__(58);
-
-module.exports = {
-  Tree
-};
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+
+var _tree = __webpack_require__(44);
+
+var _tree2 = _interopRequireDefault(_tree);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = {
+  Tree: _tree2.default
+}; /* This Source Code Form is subject to the terms of the Mozilla Public
+    * License, v. 2.0. If a copy of the MPL was not distributed with this
+    * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /***/ }),
-/* 58 */
+/* 44 */
 /***/ (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/. */
-
-const { DOM: dom, createClass, createFactory, PropTypes } = __webpack_require__(0);
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+
+var _react = __webpack_require__(0);
+
+var _react2 = _interopRequireDefault(_react);
+
+var _svgInlineReact = __webpack_require__(10);
+
+var _svgInlineReact2 = _interopRequireDefault(_svgInlineReact);
+
+var _arrow = __webpack_require__(45);
+
+var _arrow2 = _interopRequireDefault(_arrow);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+const { DOM: dom, createClass, createFactory, createElement, PropTypes } = _react2.default; /* This Source Code Form is subject to the terms of the Mozilla Public
+                                                                                             * License, v. 2.0. If a copy of the MPL was not distributed with this
+                                                                                             * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+__webpack_require__(46);
 
 const AUTO_EXPAND_DEPTH = 0; // depth
 
 /**
  * An arrow that displays whether its node is expanded (▼) or collapsed
  * (▶). When its node has no children, it is hidden.
  */
 const ArrowExpander = createFactory(createClass({
   displayName: "ArrowExpander",
 
+  propTypes: {
+    expanded: PropTypes.bool
+  },
+
   shouldComponentUpdate(nextProps, nextState) {
-    return this.props.item !== nextProps.item || this.props.visible !== nextProps.visible || this.props.expanded !== nextProps.expanded;
+    return this.props.expanded !== nextProps.expanded;
   },
 
   render() {
-    const attrs = {
-      className: "arrow theme-twisty",
-      onClick: this.props.expanded ? () => this.props.onCollapse(this.props.item) : e => this.props.onExpand(this.props.item, e.altKey)
-    };
-
-    if (this.props.expanded) {
-      attrs.className += " open";
+    const {
+      expanded
+    } = this.props;
+
+    const classNames = ["arrow"];
+    if (expanded) {
+      classNames.push("expanded");
     }
-
-    if (!this.props.visible) {
-      attrs.style = Object.assign({}, this.props.style || {}, {
-        visibility: "hidden"
-      });
-    }
-
-    return dom.div(attrs, this.props.children);
+    return createElement(_svgInlineReact2.default, {
+      className: classNames.join(" "),
+      src: _arrow2.default
+    });
   }
 }));
 
 const TreeNode = createFactory(createClass({
   displayName: "TreeNode",
 
-  componentDidMount() {
-    if (this.props.focused) {
-      this.refs.button.focus();
-    }
-  },
-
-  componentDidUpdate() {
-    if (this.props.focused) {
-      this.refs.button.focus();
-    }
+  propTypes: {
+    index: PropTypes.number.isRequired,
+    depth: PropTypes.number.isRequired,
+    focused: PropTypes.bool.isRequired,
+    expanded: PropTypes.bool.isRequired,
+    item: PropTypes.any.isRequired,
+    isExpandable: PropTypes.bool.isRequired,
+    onClick: PropTypes.func,
+    renderItem: PropTypes.func.isRequired
   },
 
   shouldComponentUpdate(nextProps) {
     return this.props.item !== nextProps.item || this.props.focused !== nextProps.focused || this.props.expanded !== nextProps.expanded;
   },
 
   render() {
-    const arrow = ArrowExpander({
-      item: this.props.item,
-      expanded: this.props.expanded,
-      visible: this.props.hasChildren,
-      onExpand: this.props.onExpand,
-      onCollapse: this.props.onCollapse
-    });
-
-    let isOddRow = this.props.index % 2;
+    const {
+      depth,
+      item,
+      focused,
+      expanded,
+      renderItem,
+      isExpandable
+    } = this.props;
+
+    const arrow = isExpandable ? ArrowExpander({
+      item,
+      expanded
+    }) : null;
+
+    const treeIndentWidthVar = "var(--tree-indent-width)";
+    const treeBorderColorVar = "var(--tree-indent-border-color, black)";
+    const treeBorderWidthVar = "var(--tree-indent-border-width, 1px)";
+
+    const paddingInlineStart = `calc(
+      (${treeIndentWidthVar} * ${depth})
+      ${isExpandable ? "" : "+ var(--arrow-total-width)"}
+    )`;
+
+    // This is the computed border that will mimic a border on tree nodes.
+    // This allow us to have as many "borders" as we need without adding
+    // specific elements for that purpose only.
+    // it's a gradient with "hard stops" which will give us as much plain
+    // lines as we need given the depth of the node.
+    // The gradient uses CSS custom properties so everything is customizable
+    // by consumers if needed.
+    const backgroundBorder = depth === 0 ? null : "linear-gradient(90deg, " + Array.from({ length: depth }).map((_, i) => {
+      const indentWidth = `(${i} * ${treeIndentWidthVar})`;
+      const alignIndent = `(var(--arrow-width) / 2)`;
+      const start = `calc(${indentWidth} + ${alignIndent})`;
+      const end = `calc(${indentWidth} + ${alignIndent} + ${treeBorderWidthVar})`;
+
+      return `transparent ${start},
+              ${treeBorderColorVar} ${start},
+              ${treeBorderColorVar} ${end},
+              transparent ${end}`;
+    }).join(",") + ")";
+
+    let ariaExpanded;
+    if (this.props.isExpandable) {
+      ariaExpanded = false;
+    }
+    if (this.props.expanded) {
+      ariaExpanded = true;
+    }
+
     return dom.div({
-      className: `tree-node div ${isOddRow ? "tree-node-odd" : ""}`,
-      onFocus: this.props.onFocus,
-      onClick: this.props.onFocus,
-      onBlur: this.props.onBlur,
+      className: "tree-node" + (focused ? " focused" : ""),
       style: {
-        padding: 0,
-        margin: 0
-      }
-    }, this.props.renderItem(this.props.item, this.props.depth, this.props.focused, arrow, this.props.expanded),
-
-    // XXX: OSX won't focus/blur regular elements even if you set tabindex
-    // unless there is an input/button child.
-    dom.button(this._buttonAttrs));
-  },
-
-  _buttonAttrs: {
-    ref: "button",
-    style: {
-      opacity: 0,
-      width: "0 !important",
-      height: "0 !important",
-      padding: "0 !important",
-      outline: "none",
-      MozAppearance: "none",
-      // XXX: Despite resetting all of the above properties (and margin), the
-      // button still ends up with ~79px width, so we set a large negative
-      // margin to completely hide it.
-      MozMarginStart: "-1000px !important"
-    }
+        paddingInlineStart,
+        backgroundImage: backgroundBorder
+      },
+      onClick: this.props.onClick,
+      role: "treeitem",
+      "aria-level": depth,
+      "aria-expanded": ariaExpanded
+    }, renderItem(item, depth, focused, arrow, expanded));
   }
 }));
 
 /**
  * Create a function that calls the given function `fn` only once per animation
  * frame.
  *
  * @param {Function} fn
@@ -5127,62 +5239,233 @@ function oncePerAnimationFrame(fn) {
     animationId = requestAnimationFrame(() => {
       fn.call(this, ...argsToPass);
       animationId = null;
       argsToPass = null;
     });
   };
 }
 
-const NUMBER_OF_OFFSCREEN_ITEMS = 1;
-
 /**
  * A generic tree component. See propTypes for the public API.
  *
- * @see `devtools/client/memory/components/test/mochitest/head.js` for usage
- * @see `devtools/client/memory/components/heap.js` for usage
+ * This tree component doesn't make any assumptions about the structure of your
+ * tree data. Whether children are computed on demand, or stored in an array in
+ * the parent's `_children` property, it doesn't matter. We only require the
+ * implementation of `getChildren`, `getRoots`, `getParent`, and `isExpanded`
+ * functions.
+ *
+ * This tree component is well tested and reliable. See the tests in ./tests
+ * and its usage in the performance and memory panels in mozilla-central.
+ *
+ * This tree component doesn't make any assumptions about how to render items in
+ * the tree. You provide a `renderItem` function, and this component will ensure
+ * that only those items whose parents are expanded and which are visible in the
+ * viewport are rendered. The `renderItem` function could render the items as a
+ * "traditional" tree or as rows in a table or anything else. It doesn't
+ * restrict you to only one certain kind of tree.
+ *
+ * The tree comes with basic styling for the indent, the arrow, as well as hovered
+ * and focused styles.
+ * All of this can be customize on the customer end, by overriding the following
+ * CSS custom properties :
+ *   --arrow-width: the width of the arrow.
+ *   --arrow-single-margin: the end margin between the arrow and the item that follows.
+ *   --arrow-fill-color: the fill-color of the arrow.
+ *   --tree-indent-width: the width of a 1-level-deep item.
+ *   --tree-indent-border-color: the color of the indent border.
+ *   --tree-indent-border-width: the width of the indent border.
+ *   --tree-node-hover-background-color: the background color of a hovered node.
+ *   --tree-node-focus-color: the color of a focused node.
+ *   --tree-node-focus-background-color: the background color of a focused node.
+ *
+ *
+ * ### Example Usage
+ *
+ * Suppose we have some tree data where each item has this form:
+ *
+ *     {
+ *       id: Number,
+ *       label: String,
+ *       parent: Item or null,
+ *       children: Array of child items,
+ *       expanded: bool,
+ *     }
+ *
+ * Here is how we could render that data with this component:
+ *
+ *     const MyTree = createClass({
+ *       displayName: "MyTree",
+ *
+ *       propTypes: {
+ *         // The root item of the tree, with the form described above.
+ *         root: PropTypes.object.isRequired
+ *       },
+ *
+ *       render() {
+ *         return Tree({
+ *           itemHeight: 20, // px
+ *
+ *           getRoots: () => [this.props.root],
+ *
+ *           getParent: item => item.parent,
+ *           getChildren: item => item.children,
+ *           getKey: item => item.id,
+ *           isExpanded: item => item.expanded,
+ *
+ *           renderItem: (item, depth, isFocused, arrow, isExpanded) => {
+ *             let className = "my-tree-item";
+ *             if (isFocused) {
+ *               className += " focused";
+ *             }
+ *             return dom.div({
+ *               className,
+ *             },
+ *               arrow,
+ *               // And here is the label for this item.
+ *               dom.span({ className: "my-tree-item-label" }, item.label)
+ *             );
+ *           },
+ *
+ *           onExpand: item => dispatchExpandActionToRedux(item),
+ *           onCollapse: item => dispatchCollapseActionToRedux(item),
+ *         });
+ *       }
+ *     });
  */
-const Tree = module.exports = createClass({
+const Tree = createClass({
   displayName: "Tree",
 
   propTypes: {
     // Required props
 
     // A function to get an item's parent, or null if it is a root.
+    //
+    // Type: getParent(item: Item) -> Maybe<Item>
+    //
+    // Example:
+    //
+    //     // The parent of this item is stored in its `parent` property.
+    //     getParent: item => item.parent
     getParent: PropTypes.func.isRequired,
+
     // A function to get an item's children.
+    //
+    // Type: getChildren(item: Item) -> [Item]
+    //
+    // Example:
+    //
+    //     // This item's children are stored in its `children` property.
+    //     getChildren: item => item.children
     getChildren: PropTypes.func.isRequired,
-    // A function which takes an item and ArrowExpander and returns a
-    // component.
+
+    // A function which takes an item and ArrowExpander component instance and
+    // returns a component, or text, or anything else that React considers
+    // renderable.
+    //
+    // Type: renderItem(item: Item,
+    //                  depth: Number,
+    //                  isFocused: Boolean,
+    //                  arrow: ReactComponent,
+    //                  isExpanded: Boolean) -> ReactRenderable
+    //
+    // Example:
+    //
+    //     renderItem: (item, depth, isFocused, arrow, isExpanded) => {
+    //       let className = "my-tree-item";
+    //       if (isFocused) {
+    //         className += " focused";
+    //       }
+    //       return dom.div(
+    //         {
+    //           className,
+    //           style: { marginLeft: depth * 10 + "px" }
+    //         },
+    //         arrow,
+    //         dom.span({ className: "my-tree-item-label" }, item.label)
+    //       );
+    //     },
     renderItem: PropTypes.func.isRequired,
+
     // A function which returns the roots of the tree (forest).
+    //
+    // Type: getRoots() -> [Item]
+    //
+    // Example:
+    //
+    //     // In this case, we only have one top level, root item. You could
+    //     // return multiple items if you have many top level items in your
+    //     // tree.
+    //     getRoots: () => [this.props.rootOfMyTree]
     getRoots: PropTypes.func.isRequired,
-    // A function to get a unique key for the given item.
+
+    // A function to get a unique key for the given item. This helps speed up
+    // React's rendering a *TON*.
+    //
+    // Type: getKey(item: Item) -> String
+    //
+    // Example:
+    //
+    //     getKey: item => `my-tree-item-${item.uniqueId}`
     getKey: PropTypes.func.isRequired,
+
     // A function to get whether an item is expanded or not. If an item is not
     // expanded, then it must be collapsed.
+    //
+    // Type: isExpanded(item: Item) -> Boolean
+    //
+    // Example:
+    //
+    //     isExpanded: item => item.expanded,
     isExpanded: PropTypes.func.isRequired,
+
     // The height of an item in the tree including margin and padding, in
     // pixels.
     itemHeight: PropTypes.number.isRequired,
 
     // Optional props
 
     // The currently focused item, if any such item exists.
     focused: PropTypes.any,
+
     // Handle when a new item is focused.
     onFocus: PropTypes.func,
+
     // The depth to which we should automatically expand new items.
     autoExpandDepth: PropTypes.number,
     // Should auto expand all new items or just the new items under the first
     // root item.
     autoExpandAll: PropTypes.bool,
-    // Optional event handlers for when items are expanded or collapsed.
+
+    // Note: the two properties below are mutually exclusive. Only one of the
+    // label properties is necessary.
+    // ID of an element whose textual content serves as an accessible label for
+    // a tree.
+    labelledby: PropTypes.string,
+    // Accessibility label for a tree widget.
+    label: PropTypes.string,
+
+    // Optional event handlers for when items are expanded or collapsed. Useful
+    // for dispatching redux events and updating application state, maybe lazily
+    // loading subtrees from a worker, etc.
+    //
+    // Type:
+    //     onExpand(item: Item)
+    //     onCollapse(item: Item)
+    //
+    // Example:
+    //
+    //     onExpand: item => dispatchExpandActionToRedux(item)
     onExpand: PropTypes.func,
-    onCollapse: PropTypes.func
+    onCollapse: PropTypes.func,
+    isExpandable: PropTypes.func,
+    // Additional classes to add to the root element.
+    className: PropTypes.string,
+    // style object to be applied to the root element.
+    style: PropTypes.object
   },
 
   getDefaultProps() {
     return {
       autoExpandDepth: AUTO_EXPAND_DEPTH,
       autoExpandAll: true
     };
   },
@@ -5192,99 +5475,63 @@ const Tree = module.exports = createClas
       scroll: 0,
       height: window.innerHeight,
       seen: new Set()
     };
   },
 
   componentDidMount() {
     window.addEventListener("resize", this._updateHeight);
-    this._autoExpand(this.props);
+    this._autoExpand();
+    this._updateHeight();
+  },
+
+  componentWillReceiveProps(nextProps) {
+    this._autoExpand();
     this._updateHeight();
   },
 
   componentWillUnmount() {
     window.removeEventListener("resize", this._updateHeight);
   },
 
-  componentWillReceiveProps(nextProps) {
-    this._autoExpand(nextProps);
-    this._updateHeight();
-  },
-
-  _autoExpand(props) {
-    if (!props.autoExpandDepth) {
+  _autoExpand() {
+    if (!this.props.autoExpandDepth) {
       return;
     }
 
     // Automatically expand the first autoExpandDepth levels for new items. Do
     // not use the usual DFS infrastructure because we don't want to ignore
     // collapsed nodes.
     const autoExpand = (item, currentDepth) => {
-      if (currentDepth >= props.autoExpandDepth || this.state.seen.has(item)) {
+      if (currentDepth >= this.props.autoExpandDepth || this.state.seen.has(item)) {
         return;
       }
 
-      props.onExpand(item);
+      this.props.onExpand(item);
       this.state.seen.add(item);
 
-      const children = props.getChildren(item);
+      const children = this.props.getChildren(item);
       const length = children.length;
       for (let i = 0; i < length; i++) {
         autoExpand(children[i], currentDepth + 1);
       }
     };
 
-    const roots = props.getRoots();
+    const roots = this.props.getRoots();
     const length = roots.length;
-    if (props.autoExpandAll) {
+    if (this.props.autoExpandAll) {
       for (let i = 0; i < length; i++) {
         autoExpand(roots[i], 0);
       }
     } else if (length != 0) {
       autoExpand(roots[0], 0);
     }
   },
 
-  render() {
-    const traversal = this._dfsFromRoots();
-
-    const renderItem = i => {
-      let { item, depth } = traversal[i];
-      return TreeNode({
-        key: this.props.getKey(item, i),
-        index: i,
-        item: item,
-        depth: depth,
-        renderItem: this.props.renderItem,
-        focused: this.props.focused === item,
-        expanded: this.props.isExpanded(item),
-        hasChildren: !!this.props.getChildren(item).length,
-        onExpand: this._onExpand,
-        onCollapse: this._onCollapse,
-        onFocus: () => this._focus(i, item)
-      });
-    };
-
-    const style = Object.assign({}, this.props.style || {}, {
-      padding: 0,
-      margin: 0
-    });
-
-    return dom.div({
-      className: `tree ${this.props.className ? this.props.className : ""}`,
-      ref: "tree",
-      onKeyDown: this._onKeyDown,
-      onKeyPress: this._preventArrowKeyScrolling,
-      onKeyUp: this._preventArrowKeyScrolling,
-      onScroll: this._onScroll,
-      style
-    }, traversal.map((v, i) => renderItem(i)));
-  },
-
   _preventArrowKeyScrolling(e) {
     switch (e.key) {
       case "ArrowUp":
       case "ArrowDown":
       case "ArrowLeft":
       case "ArrowRight":
         e.preventDefault();
         e.stopPropagation();
@@ -5454,28 +5701,29 @@ const Tree = module.exports = createClas
         this._focusPrevNode();
         return;
 
       case "ArrowDown":
         this._focusNextNode();
         return;
 
       case "ArrowLeft":
-        if (this.props.isExpanded(this.props.focused) && this.props.getChildren(this.props.focused).length) {
+        if (this.props.isExpanded(this.props.focused) && this._nodeIsExpandable(this.props.focused)) {
           this._onCollapse(this.props.focused);
         } else {
           this._focusParentNode();
         }
         return;
 
       case "ArrowRight":
         if (!this.props.isExpanded(this.props.focused)) {
           this._onExpand(this.props.focused);
+        } else {
+          this._focusNextNode();
         }
-        return;
     }
   },
 
   /**
    * Sets the previous node relative to the currently focused item, to focused.
    */
   _focusPrevNode: oncePerAnimationFrame(function () {
     // Start a depth first search and keep going until we reach the currently
@@ -5543,27 +5791,114 @@ const Tree = module.exports = createClas
     let parentIndex = 0;
     for (; parentIndex < length; parentIndex++) {
       if (traversal[parentIndex].item === parent) {
         break;
       }
     }
 
     this._focus(parentIndex, parent);
-  })
+  }),
+
+  _nodeIsExpandable: function (item) {
+    return this.props.isExpandable ? this.props.isExpandable(item) : !!this.props.getChildren(item).length;
+  },
+
+  render() {
+    const traversal = this._dfsFromRoots();
+    const {
+      focused
+    } = this.props;
+
+    const nodes = traversal.map((v, i) => {
+      const { item, depth } = traversal[i];
+      return TreeNode({
+        key: this.props.getKey(item, i),
+        index: i,
+        item,
+        depth,
+        renderItem: this.props.renderItem,
+        focused: focused === item,
+        expanded: this.props.isExpanded(item),
+        isExpandable: this._nodeIsExpandable(item),
+        onExpand: this._onExpand,
+        onCollapse: this._onCollapse,
+        onClick: e => {
+          this._focus(i, item);
+          if (this.props.isExpanded(item)) {
+            this.props.onCollapse(item);
+          } else {
+            this.props.onExpand(item, e.altKey);
+          }
+        }
+      });
+    });
+
+    const style = Object.assign({}, this.props.style || {}, {
+      padding: 0,
+      margin: 0
+    });
+
+    return dom.div({
+      className: `tree ${this.props.className ? this.props.className : ""}`,
+      ref: "tree",
+      role: "tree",
+      tabIndex: "0",
+      onKeyDown: this._onKeyDown,
+      onKeyPress: this._preventArrowKeyScrolling,
+      onKeyUp: this._preventArrowKeyScrolling,
+      onScroll: this._onScroll,
+      onFocus: ({ nativeEvent }) => {
+        if (focused || !nativeEvent || !this.refs.tree) {
+          return;
+        }
+
+        let { explicitOriginalTarget } = nativeEvent;
+        // Only set default focus to the first tree node if the focus came
+        // from outside the tree (e.g. by tabbing to the tree from other
+        // external elements).
+        if (explicitOriginalTarget !== this.refs.tree && !this.refs.tree.contains(explicitOriginalTarget)) {
+          this._focus(0, traversal[0].item);
+        }
+      },
+      onBlur: this._onBlur,
+      onClick: () => {
+        // Focus should always remain on the tree container itself.
+        this.refs.tree.focus();
+      },
+      "aria-label": this.props.label,
+      "aria-labelledby": this.props.labelledby,
+      "aria-activedescendant": focused && this.props.getKey(focused),
+      style
+    }, nodes);
+  }
 });
 
+exports.default = Tree;
+
 /***/ }),
-/* 59 */
+/* 45 */
+/***/ (function(module, exports) {
+
+module.exports = "<!-- This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. --><svg viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M8 13.4c-.5 0-.9-.2-1.2-.6L.4 5.2C0 4.7-.1 4.3.2 3.7S1 3 1.6 3h12.8c.6 0 1.2.1 1.4.7.3.6.2 1.1-.2 1.6l-6.4 7.6c-.3.4-.7.5-1.2.5z\"></path></svg>"
+
+/***/ }),
+/* 46 */
 /***/ (function(module, exports) {
 
 // removed by extract-text-webpack-plugin
 
 /***/ }),
-/* 60 */
+/* 47 */
+/***/ (function(module, exports) {
+
+// removed by extract-text-webpack-plugin
+
+/***/ }),
+/* 48 */
 /***/ (function(module, exports, __webpack_require__) {
 
 var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*!
   Copyright (c) 2016 Jed Watson.
   Licensed under the MIT License (MIT), see
   http://jedwatson.github.io/classnames
 */
 /* global define */
@@ -5608,1503 +5943,94 @@ var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBP
 				__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
 	} else {
 		window.classNames = classNames;
 	}
 }());
 
 
 /***/ }),
-/* 61 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var baseGet = __webpack_require__(62);
-
-/**
- * Gets the value at `path` of `object`. If the resolved value is
- * `undefined`, the `defaultValue` is returned in its place.
- *
- * @static
- * @memberOf _
- * @since 3.7.0
- * @category Object
- * @param {Object} object The object to query.
- * @param {Array|string} path The path of the property to get.
- * @param {*} [defaultValue] The value returned for `undefined` resolved values.
- * @returns {*} Returns the resolved value.
- * @example
- *
- * var object = { 'a': [{ 'b': { 'c': 3 } }] };
- *
- * _.get(object, 'a[0].b.c');
- * // => 3
- *
- * _.get(object, ['a', '0', 'b', 'c']);
- * // => 3
- *
- * _.get(object, 'a.b.c', 'default');
- * // => 'default'
- */
-function get(object, path, defaultValue) {
-  var result = object == null ? undefined : baseGet(object, path);
-  return result === undefined ? defaultValue : result;
-}
-
-module.exports = get;
-
-
-/***/ }),
-/* 62 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var castPath = __webpack_require__(22),
-    toKey = __webpack_require__(25);
-
-/**
- * The base implementation of `_.get` without support for default values.
- *
- * @private
- * @param {Object} object The object to query.
- * @param {Array|string} path The path of the property to get.
- * @returns {*} Returns the resolved value.
- */
-function baseGet(object, path) {
-  path = castPath(path, object);
-
-  var index = 0,
-      length = path.length;
-
-  while (object != null && index < length) {
-    object = object[toKey(path[index++])];
-  }
-  return (index && index == length) ? object : undefined;
-}
-
-module.exports = baseGet;
-
-
-/***/ }),
-/* 63 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var isArray = __webpack_require__(5),
-    isSymbol = __webpack_require__(11);
-
-/** Used to match property names within property paths. */
-var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,
-    reIsPlainProp = /^\w*$/;
-
-/**
- * Checks if `value` is a property name and not a property path.
- *
- * @private
- * @param {*} value The value to check.
- * @param {Object} [object] The object to query keys on.
- * @returns {boolean} Returns `true` if `value` is a property name, else `false`.
- */
-function isKey(value, object) {
-  if (isArray(value)) {
-    return false;
-  }
-  var type = typeof value;
-  if (type == 'number' || type == 'symbol' || type == 'boolean' ||
-      value == null || isSymbol(value)) {
-    return true;
-  }
-  return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||
-    (object != null && value in Object(object));
-}
-
-module.exports = isKey;
-
-
-/***/ }),
-/* 64 */
-/***/ (function(module, exports, __webpack_require__) {
-
-/* 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, __webpack_require__(65)))
-
-/***/ }),
-/* 65 */
-/***/ (function(module, exports) {
-
-var g;
-
-// This works in non-strict mode
-g = (function() {
-	return this;
-})();
-
-try {
-	// This works if eval is allowed (see CSP)
-	g = g || Function("return this")() || (1,eval)("this");
-} catch(e) {
-	// This works if the window reference is available
-	if(typeof window === "object")
-		g = window;
-}
-
-// g can still be undefined, but nothing to do about it...
-// We return undefined, instead of nothing here, so it's
-// easier to handle this case. if(!global) { ...}
-
-module.exports = g;
-
-
-/***/ }),
-/* 66 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var Symbol = __webpack_require__(13);
-
-/** 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;
-
-
-/***/ }),
-/* 67 */
+/* 49 */
 /***/ (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;
-
-
-/***/ }),
-/* 68 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var memoizeCapped = __webpack_require__(69);
-
-/** Used to match property names within property paths. */
-var reLeadingDot = /^\./,
-    rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g;
-
-/** Used to match backslashes in property paths. */
-var reEscapeChar = /\\(\\)?/g;
-
-/**
- * Converts `string` to a property path array.
- *
- * @private
- * @param {string} string The string to convert.
- * @returns {Array} Returns the property path array.
- */
-var stringToPath = memoizeCapped(function(string) {
-  var result = [];
-  if (reLeadingDot.test(string)) {
-    result.push('');
-  }
-  string.replace(rePropName, function(match, number, quote, string) {
-    result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match));
-  });
-  return result;
-});
-
-module.exports = stringToPath;
-
-
-/***/ }),
-/* 69 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var memoize = __webpack_require__(70);
-
-/** Used as the maximum memoize cache size. */
-var MAX_MEMOIZE_SIZE = 500;
-
-/**
- * A specialized version of `_.memoize` which clears the memoized function's
- * cache when it exceeds `MAX_MEMOIZE_SIZE`.
- *
- * @private
- * @param {Function} func The function to have its output memoized.
- * @returns {Function} Returns the new memoized function.
- */
-function memoizeCapped(func) {
-  var result = memoize(func, function(key) {
-    if (cache.size === MAX_MEMOIZE_SIZE) {
-      cache.clear();
-    }
-    return key;
-  });
-
-  var cache = result.cache;
-  return result;
-}
-
-module.exports = memoizeCapped;
-
-
-/***/ }),
-/* 70 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var MapCache = __webpack_require__(71);
-
-/** Error message constants. */
-var FUNC_ERROR_TEXT = 'Expected a function';
-
-/**
- * Creates a function that memoizes the result of `func`. If `resolver` is
- * provided, it determines the cache key for storing the result based on the
- * arguments provided to the memoized function. By default, the first argument
- * provided to the memoized function is used as the map cache key. The `func`
- * is invoked with the `this` binding of the memoized function.
- *
- * **Note:** The cache is exposed as the `cache` property on the memoized
- * function. Its creation may be customized by replacing the `_.memoize.Cache`
- * constructor with one whose instances implement the
- * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)
- * method interface of `clear`, `delete`, `get`, `has`, and `set`.
- *
- * @static
- * @memberOf _
- * @since 0.1.0
- * @category Function
- * @param {Function} func The function to have its output memoized.
- * @param {Function} [resolver] The function to resolve the cache key.
- * @returns {Function} Returns the new memoized function.
- * @example
- *
- * var object = { 'a': 1, 'b': 2 };
- * var other = { 'c': 3, 'd': 4 };
- *
- * var values = _.memoize(_.values);
- * values(object);
- * // => [1, 2]
- *
- * values(other);
- * // => [3, 4]
- *
- * object.a = 2;
- * values(object);
- * // => [1, 2]
- *
- * // Modify the result cache.
- * values.cache.set(object, ['a', 'b']);
- * values(object);
- * // => ['a', 'b']
- *
- * // Replace `_.memoize.Cache`.
- * _.memoize.Cache = WeakMap;
- */
-function memoize(func, resolver) {
-  if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) {
-    throw new TypeError(FUNC_ERROR_TEXT);
-  }
-  var memoized = function() {
-    var args = arguments,
-        key = resolver ? resolver.apply(this, args) : args[0],
-        cache = memoized.cache;
-
-    if (cache.has(key)) {
-      return cache.get(key);
-    }
-    var result = func.apply(this, args);
-    memoized.cache = cache.set(key, result) || cache;
-    return result;
-  };
-  memoized.cache = new (memoize.Cache || MapCache);
-  return memoized;
-}
-
-// Expose `MapCache`.
-memoize.Cache = MapCache;
-
-module.exports = memoize;
-
-
-/***/ }),
-/* 71 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var mapCacheClear = __webpack_require__(72),
-    mapCacheDelete = __webpack_require__(93),
-    mapCacheGet = __webpack_require__(95),
-    mapCacheHas = __webpack_require__(96),
-    mapCacheSet = __webpack_require__(97);
-
-/**
- * Creates a map cache object to store key-value pairs.
- *
- * @private
- * @constructor
- * @param {Array} [entries] The key-value pairs to cache.
- */
-function MapCache(entries) {
-  var index = -1,
-      length = entries == null ? 0 : entries.length;
-
-  this.clear();
-  while (++index < length) {
-    var entry = entries[index];
-    this.set(entry[0], entry[1]);
-  }
-}
-
-// Add methods to `MapCache`.
-MapCache.prototype.clear = mapCacheClear;
-MapCache.prototype['delete'] = mapCacheDelete;
-MapCache.prototype.get = mapCacheGet;
-MapCache.prototype.has = mapCacheHas;
-MapCache.prototype.set = mapCacheSet;
-
-module.exports = MapCache;
-
-
-/***/ }),
-/* 72 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var Hash = __webpack_require__(73),
-    ListCache = __webpack_require__(85),
-    Map = __webpack_require__(92);
-
-/**
- * Removes all key-value entries from the map.
- *
- * @private
- * @name clear
- * @memberOf MapCache
- */
-function mapCacheClear() {
-  this.size = 0;
-  this.__data__ = {
-    'hash': new Hash,
-    'map': new (Map || ListCache),
-    'string': new Hash
-  };
-}
-
-module.exports = mapCacheClear;
-
-
-/***/ }),
-/* 73 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var hashClear = __webpack_require__(74),
-    hashDelete = __webpack_require__(81),
-    hashGet = __webpack_require__(82),
-    hashHas = __webpack_require__(83),
-    hashSet = __webpack_require__(84);
-
-/**
- * Creates a hash object.
- *
- * @private
- * @constructor
- * @param {Array} [entries] The key-value pairs to cache.
- */
-function Hash(entries) {
-  var index = -1,
-      length = entries == null ? 0 : entries.length;
-
-  this.clear();
-  while (++index < length) {
-    var entry = entries[index];
-    this.set(entry[0], entry[1]);
-  }
-}
-
-// Add methods to `Hash`.
-Hash.prototype.clear = hashClear;
-Hash.prototype['delete'] = hashDelete;
-Hash.prototype.get = hashGet;
-Hash.prototype.has = hashHas;
-Hash.prototype.set = hashSet;
-
-module.exports = Hash;
-
-
-/***/ }),
-/* 74 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var nativeCreate = __webpack_require__(6);
-
-/**
- * Removes all key-value entries from the hash.
- *
- * @private
- * @name clear
- * @memberOf Hash
- */
-function hashClear() {
-  this.__data__ = nativeCreate ? nativeCreate(null) : {};
-  this.size = 0;
-}
-
-module.exports = hashClear;
-
-
-/***/ }),
-/* 75 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var isFunction = __webpack_require__(76),
-    isMasked = __webpack_require__(77),
-    isObject = __webpack_require__(24),
-    toSource = __webpack_require__(79);
-
-/**
- * Used to match `RegExp`
- * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
- */
-var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
-
-/** Used to detect host constructors (Safari). */
-var reIsHostCtor = /^\[object .+?Constructor\]$/;
-
-/** 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 detect if a method is native. */
-var reIsNative = RegExp('^' +
-  funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
-  .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
-);
-
-/**
- * The base implementation of `_.isNative` without bad shim checks.
- *
- * @private
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is a native function,
- *  else `false`.
- */
-function baseIsNative(value) {
-  if (!isObject(value) || isMasked(value)) {
-    return false;
-  }
-  var pattern = isFunction(value) ? reIsNative : reIsHostCtor;
-  return pattern.test(toSource(value));
-}
-
-module.exports = baseIsNative;
-
-
-/***/ }),
-/* 76 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var baseGetTag = __webpack_require__(12),
-    isObject = __webpack_require__(24);
-
-/** `Object#toString` result references. */
-var asyncTag = '[object AsyncFunction]',
-    funcTag = '[object Function]',
-    genTag = '[object GeneratorFunction]',
-    proxyTag = '[object Proxy]';
-
-/**
- * Checks if `value` is classified as a `Function` object.
- *
- * @static
- * @memberOf _
- * @since 0.1.0
- * @category Lang
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is a function, else `false`.
- * @example
- *
- * _.isFunction(_);
- * // => true
- *
- * _.isFunction(/abc/);
- * // => false
- */
-function isFunction(value) {
-  if (!isObject(value)) {
-    return false;
-  }
-  // The use of `Object#toString` avoids issues with the `typeof` operator
-  // in Safari 9 which returns 'object' for typed arrays and other constructors.
-  var tag = baseGetTag(value);
-  return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;
-}
-
-module.exports = isFunction;
-
-
-/***/ }),
-/* 77 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var coreJsData = __webpack_require__(78);
-
-/** Used to detect methods masquerading as native. */
-var maskSrcKey = (function() {
-  var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');
-  return uid ? ('Symbol(src)_1.' + uid) : '';
-}());
-
-/**
- * Checks if `func` has its source masked.
- *
- * @private
- * @param {Function} func The function to check.
- * @returns {boolean} Returns `true` if `func` is masked, else `false`.
- */
-function isMasked(func) {
-  return !!maskSrcKey && (maskSrcKey in func);
-}
-
-module.exports = isMasked;
-
-
-/***/ }),
-/* 78 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var root = __webpack_require__(14);
-
-/** Used to detect overreaching core-js shims. */
-var coreJsData = root['__core-js_shared__'];
-
-module.exports = coreJsData;
-
-
-/***/ }),
-/* 79 */
-/***/ (function(module, exports) {
-
-/** Used for built-in method references. */
-var funcProto = Function.prototype;
-
-/** Used to resolve the decompiled source of functions. */
-var funcToString = funcProto.toString;
-
-/**
- * Converts `func` to its source code.
- *
- * @private
- * @param {Function} func The function to convert.
- * @returns {string} Returns the source code.
- */
-function toSource(func) {
-  if (func != null) {
-    try {
-      return funcToString.call(func);
-    } catch (e) {}
-    try {
-      return (func + '');
-    } catch (e) {}
-  }
-  return '';
-}
-
-module.exports = toSource;
-
-
-/***/ }),
-/* 80 */
-/***/ (function(module, exports) {
-
-/**
- * Gets the value at `key` of `object`.
- *
- * @private
- * @param {Object} [object] The object to query.
- * @param {string} key The key of the property to get.
- * @returns {*} Returns the property value.
- */
-function getValue(object, key) {
-  return object == null ? undefined : object[key];
-}
-
-module.exports = getValue;
-
-
-/***/ }),
-/* 81 */
-/***/ (function(module, exports) {
-
-/**
- * Removes `key` and its value from the hash.
- *
- * @private
- * @name delete
- * @memberOf Hash
- * @param {Object} hash The hash to modify.
- * @param {string} key The key of the value to remove.
- * @returns {boolean} Returns `true` if the entry was removed, else `false`.
- */
-function hashDelete(key) {
-  var result = this.has(key) && delete this.__data__[key];
-  this.size -= result ? 1 : 0;
-  return result;
-}
-
-module.exports = hashDelete;
-
-
-/***/ }),
-/* 82 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var nativeCreate = __webpack_require__(6);
-
-/** Used to stand-in for `undefined` hash values. */
-var HASH_UNDEFINED = '__lodash_hash_undefined__';
-
-/** Used for built-in method references. */
-var objectProto = Object.prototype;
-
-/** Used to check objects for own properties. */
-var hasOwnProperty = objectProto.hasOwnProperty;
-
-/**
- * Gets the hash value for `key`.
- *
- * @private
- * @name get
- * @memberOf Hash
- * @param {string} key The key of the value to get.
- * @returns {*} Returns the entry value.
- */
-function hashGet(key) {
-  var data = this.__data__;
-  if (nativeCreate) {
-    var result = data[key];
-    return result === HASH_UNDEFINED ? undefined : result;
-  }
-  return hasOwnProperty.call(data, key) ? data[key] : undefined;
-}
-
-module.exports = hashGet;
-
+module.exports = __WEBPACK_EXTERNAL_MODULE_49__;
 
 /***/ }),
-/* 83 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var nativeCreate = __webpack_require__(6);
-
-/** Used for built-in method references. */
-var objectProto = Object.prototype;
-
-/** Used to check objects for own properties. */
-var hasOwnProperty = objectProto.hasOwnProperty;
-
-/**
- * Checks if a hash value for `key` exists.
- *
- * @private
- * @name has
- * @memberOf Hash
- * @param {string} key The key of the entry to check.
- * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
- */
-function hashHas(key) {
-  var data = this.__data__;
-  return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key);
-}
-
-module.exports = hashHas;
-
-
-/***/ }),
-/* 84 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var nativeCreate = __webpack_require__(6);
-
-/** Used to stand-in for `undefined` hash values. */
-var HASH_UNDEFINED = '__lodash_hash_undefined__';
-
-/**
- * Sets the hash `key` to `value`.
- *
- * @private
- * @name set
- * @memberOf Hash
- * @param {string} key The key of the value to set.
- * @param {*} value The value to set.
- * @returns {Object} Returns the hash instance.
- */
-function hashSet(key, value) {
-  var data = this.__data__;
-  this.size += this.has(key) ? 0 : 1;
-  data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;
-  return this;
-}
-
-module.exports = hashSet;
-
-
-/***/ }),
-/* 85 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var listCacheClear = __webpack_require__(86),
-    listCacheDelete = __webpack_require__(87),
-    listCacheGet = __webpack_require__(89),
-    listCacheHas = __webpack_require__(90),
-    listCacheSet = __webpack_require__(91);
-
-/**
- * Creates an list cache object.
- *
- * @private
- * @constructor
- * @param {Array} [entries] The key-value pairs to cache.
- */
-function ListCache(entries) {
-  var index = -1,
-      length = entries == null ? 0 : entries.length;
-
-  this.clear();
-  while (++index < length) {
-    var entry = entries[index];
-    this.set(entry[0], entry[1]);
-  }
-}
-
-// Add methods to `ListCache`.
-ListCache.prototype.clear = listCacheClear;
-ListCache.prototype['delete'] = listCacheDelete;
-ListCache.prototype.get = listCacheGet;
-ListCache.prototype.has = listCacheHas;
-ListCache.prototype.set = listCacheSet;
-
-module.exports = ListCache;
-
-
-/***/ }),
-/* 86 */
-/***/ (function(module, exports) {
-
-/**
- * Removes all key-value entries from the list cache.
- *
- * @private
- * @name clear
- * @memberOf ListCache
- */
-function listCacheClear() {
-  this.__data__ = [];
-  this.size = 0;
-}
-
-module.exports = listCacheClear;
-
-
-/***/ }),
-/* 87 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var assocIndexOf = __webpack_require__(7);
-
-/** Used for built-in method references. */
-var arrayProto = Array.prototype;
-
-/** Built-in value references. */
-var splice = arrayProto.splice;
-
-/**
- * Removes `key` and its value from the list cache.
- *
- * @private
- * @name delete
- * @memberOf ListCache
- * @param {string} key The key of the value to remove.
- * @returns {boolean} Returns `true` if the entry was removed, else `false`.
- */
-function listCacheDelete(key) {
-  var data = this.__data__,
-      index = assocIndexOf(data, key);
-
-  if (index < 0) {
-    return false;
-  }
-  var lastIndex = data.length - 1;
-  if (index == lastIndex) {
-    data.pop();
-  } else {
-    splice.call(data, index, 1);
-  }
-  --this.size;
-  return true;
-}
-
-module.exports = listCacheDelete;
-
-
-/***/ }),
-/* 88 */
-/***/ (function(module, exports) {
-
-/**
- * Performs a
- * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
- * comparison between two values to determine if they are equivalent.
- *
- * @static
- * @memberOf _
- * @since 4.0.0
- * @category Lang
- * @param {*} value The value to compare.
- * @param {*} other The other value to compare.
- * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
- * @example
- *
- * var object = { 'a': 1 };
- * var other = { 'a': 1 };
- *
- * _.eq(object, object);
- * // => true
- *
- * _.eq(object, other);
- * // => false
- *
- * _.eq('a', 'a');
- * // => true
- *
- * _.eq('a', Object('a'));
- * // => false
- *
- * _.eq(NaN, NaN);
- * // => true
- */
-function eq(value, other) {
-  return value === other || (value !== value && other !== other);
-}
-
-module.exports = eq;
-
-
-/***/ }),
-/* 89 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var assocIndexOf = __webpack_require__(7);
-
-/**
- * Gets the list cache value for `key`.
- *
- * @private
- * @name get
- * @memberOf ListCache
- * @param {string} key The key of the value to get.
- * @returns {*} Returns the entry value.
- */
-function listCacheGet(key) {
-  var data = this.__data__,
-      index = assocIndexOf(data, key);
-
-  return index < 0 ? undefined : data[index][1];
-}
-
-module.exports = listCacheGet;
-
-
-/***/ }),
-/* 90 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var assocIndexOf = __webpack_require__(7);
-
-/**
- * Checks if a list cache value for `key` exists.
- *
- * @private
- * @name has
- * @memberOf ListCache
- * @param {string} key The key of the entry to check.
- * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
- */
-function listCacheHas(key) {
-  return assocIndexOf(this.__data__, key) > -1;
-}
-
-module.exports = listCacheHas;
-
-
-/***/ }),
-/* 91 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var assocIndexOf = __webpack_require__(7);
-
-/**
- * Sets the list cache `key` to `value`.
- *
- * @private
- * @name set
- * @memberOf ListCache
- * @param {string} key The key of the value to set.
- * @param {*} value The value to set.
- * @returns {Object} Returns the list cache instance.
- */
-function listCacheSet(key, value) {
-  var data = this.__data__,
-      index = assocIndexOf(data, key);
-
-  if (index < 0) {
-    ++this.size;
-    data.push([key, value]);
-  } else {
-    data[index][1] = value;
-  }
-  return this;
-}
-
-module.exports = listCacheSet;
-
-
-/***/ }),
-/* 92 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var getNative = __webpack_require__(23),
-    root = __webpack_require__(14);
-
-/* Built-in method references that are verified to be native. */
-var Map = getNative(root, 'Map');
-
-module.exports = Map;
-
-
-/***/ }),
-/* 93 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var getMapData = __webpack_require__(8);
-
-/**
- * Removes `key` and its value from the map.
- *
- * @private
- * @name delete
- * @memberOf MapCache
- * @param {string} key The key of the value to remove.
- * @returns {boolean} Returns `true` if the entry was removed, else `false`.
- */
-function mapCacheDelete(key) {
-  var result = getMapData(this, key)['delete'](key);
-  this.size -= result ? 1 : 0;
-  return result;
-}
-
-module.exports = mapCacheDelete;
-
-
-/***/ }),
-/* 94 */
-/***/ (function(module, exports) {
-
-/**
- * Checks if `value` is suitable for use as unique object key.
- *
- * @private
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is suitable, else `false`.
- */
-function isKeyable(value) {
-  var type = typeof value;
-  return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')
-    ? (value !== '__proto__')
-    : (value === null);
-}
-
-module.exports = isKeyable;
-
-
-/***/ }),
-/* 95 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var getMapData = __webpack_require__(8);
-
-/**
- * Gets the map value for `key`.
- *
- * @private
- * @name get
- * @memberOf MapCache
- * @param {string} key The key of the value to get.
- * @returns {*} Returns the entry value.
- */
-function mapCacheGet(key) {
-  return getMapData(this, key).get(key);
-}
-
-module.exports = mapCacheGet;
-
-
-/***/ }),
-/* 96 */
+/* 50 */
 /***/ (function(module, exports, __webpack_require__) {
 
-var getMapData = __webpack_require__(8);
-
-/**
- * Checks if a map value for `key` exists.
- *
- * @private
- * @name has
- * @memberOf MapCache
- * @param {string} key The key of the entry to check.
- * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
- */
-function mapCacheHas(key) {
-  return getMapData(this, key).has(key);
-}
-
-module.exports = mapCacheHas;
-
-
-/***/ }),
-/* 97 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var getMapData = __webpack_require__(8);
-
-/**
- * Sets the map `key` to `value`.
- *
- * @private
- * @name set
- * @memberOf MapCache
- * @param {string} key The key of the value to set.
- * @param {*} value The value to set.
- * @returns {Object} Returns the map cache instance.
- */
-function mapCacheSet(key, value) {
-  var data = getMapData(this, key),
-      size = data.size;
-
-  data.set(key, value);
-  this.size += data.size == size ? 0 : 1;
-  return this;
-}
-
-module.exports = mapCacheSet;
-
-
-/***/ }),
-/* 98 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var baseToString = __webpack_require__(99);
-
-/**
- * Converts `value` to a string. An empty string is returned for `null`
- * and `undefined` values. The sign of `-0` is preserved.
- *
- * @static
- * @memberOf _
- * @since 4.0.0
- * @category Lang
- * @param {*} value The value to convert.
- * @returns {string} Returns the converted string.
- * @example
- *
- * _.toString(null);
- * // => ''
- *
- * _.toString(-0);
- * // => '-0'
- *
- * _.toString([1, 2, 3]);
- * // => '1,2,3'
- */
-function toString(value) {
-  return value == null ? '' : baseToString(value);
-}
-
-module.exports = toString;
-
-
-/***/ }),
-/* 99 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var Symbol = __webpack_require__(13),
-    arrayMap = __webpack_require__(100),
-    isArray = __webpack_require__(5),
-    isSymbol = __webpack_require__(11);
-
-/** Used as references for various `Number` constants. */
-var INFINITY = 1 / 0;
-
-/** Used to convert symbols to primitives and strings. */
-var symbolProto = Symbol ? Symbol.prototype : undefined,
-    symbolToString = symbolProto ? symbolProto.toString : undefined;
-
-/**
- * The base implementation of `_.toString` which doesn't convert nullish
- * values to empty strings.
- *
- * @private
- * @param {*} value The value to process.
- * @returns {string} Returns the string.
- */
-function baseToString(value) {
-  // Exit early for strings to avoid a performance hit in some environments.
-  if (typeof value == 'string') {
-    return value;
-  }
-  if (isArray(value)) {
-    // Recursively convert values (susceptible to call stack limits).
-    return arrayMap(value, baseToString) + '';
-  }
-  if (isSymbol(value)) {
-    return symbolToString ? symbolToString.call(value) : '';
-  }
-  var result = (value + '');
-  return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
-}
-
-module.exports = baseToString;
-
-
-/***/ }),
-/* 100 */
-/***/ (function(module, exports) {
-
-/**
- * A specialized version of `_.map` for arrays without support for iteratee
- * shorthands.
- *
- * @private
- * @param {Array} [array] The array to iterate over.
- * @param {Function} iteratee The function invoked per iteration.
- * @returns {Array} Returns the new mapped array.
- */
-function arrayMap(array, iteratee) {
-  var index = -1,
-      length = array == null ? 0 : array.length,
-      result = Array(length);
-
-  while (++index < length) {
-    result[index] = iteratee(array[index], index, array);
-  }
-  return result;
-}
-
-module.exports = arrayMap;
-
-
-/***/ }),
-/* 101 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var baseHas = __webpack_require__(102),
-    hasPath = __webpack_require__(103);
-
-/**
- * Checks if `path` is a direct property of `object`.
- *
- * @static
- * @since 0.1.0
- * @memberOf _
- * @category Object
- * @param {Object} object The object to query.
- * @param {Array|string} path The path to check.
- * @returns {boolean} Returns `true` if `path` exists, else `false`.
- * @example
- *
- * var object = { 'a': { 'b': 2 } };
- * var other = _.create({ 'a': _.create({ 'b': 2 }) });
- *
- * _.has(object, 'a');
- * // => true
- *
- * _.has(object, 'a.b');
- * // => true
- *
- * _.has(object, ['a', 'b']);
- * // => true
- *
- * _.has(other, 'a');
- * // => false
- */
-function has(object, path) {
-  return object != null && hasPath(object, path, baseHas);
-}
-
-module.exports = has;
-
-
-/***/ }),
-/* 102 */
-/***/ (function(module, exports) {
-
-/** Used for built-in method references. */
-var objectProto = Object.prototype;
-
-/** Used to check objects for own properties. */
-var hasOwnProperty = objectProto.hasOwnProperty;
-
-/**
- * The base implementation of `_.has` without support for deep paths.
- *
- * @private
- * @param {Object} [object] The object to query.
- * @param {Array|string} key The key to check.
- * @returns {boolean} Returns `true` if `key` exists, else `false`.
- */
-function baseHas(object, key) {
-  return object != null && hasOwnProperty.call(object, key);
-}
-
-module.exports = baseHas;
-
-
-/***/ }),
-/* 103 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var castPath = __webpack_require__(22),
-    isArguments = __webpack_require__(104),
-    isArray = __webpack_require__(5),
-    isIndex = __webpack_require__(106),
-    isLength = __webpack_require__(107),
-    toKey = __webpack_require__(25);
-
-/**
- * Checks if `path` exists on `object`.
- *
- * @private
- * @param {Object} object The object to query.
- * @param {Array|string} path The path to check.
- * @param {Function} hasFunc The function to check properties.
- * @returns {boolean} Returns `true` if `path` exists, else `false`.
- */
-function hasPath(object, path, hasFunc) {
-  path = castPath(path, object);
-
-  var index = -1,
-      length = path.length,
-      result = false;
-
-  while (++index < length) {
-    var key = toKey(path[index]);
-    if (!(result = object != null && hasFunc(object, key))) {
-      break;
-    }
-    object = object[key];
-  }
-  if (result || ++index != length) {
-    return result;
-  }
-  length = object == null ? 0 : object.length;
-  return !!length && isLength(length) && isIndex(key, length) &&
-    (isArray(object) || isArguments(object));
-}
-
-module.exports = hasPath;
-
-
-/***/ }),
-/* 104 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var baseIsArguments = __webpack_require__(105),
-    isObjectLike = __webpack_require__(15);
-
-/** Used for built-in method references. */
-var objectProto = Object.prototype;
-
-/** Used to check objects for own properties. */
-var hasOwnProperty = objectProto.hasOwnProperty;
-
-/** Built-in value references. */
-var propertyIsEnumerable = objectProto.propertyIsEnumerable;
-
-/**
- * Checks if `value` is likely an `arguments` object.
- *
- * @static
- * @memberOf _
- * @since 0.1.0
- * @category Lang
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is an `arguments` object,
- *  else `false`.
- * @example
- *
- * _.isArguments(function() { return arguments; }());
- * // => true
- *
- * _.isArguments([1, 2, 3]);
- * // => false
- */
-var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) {
-  return isObjectLike(value) && hasOwnProperty.call(value, 'callee') &&
-    !propertyIsEnumerable.call(value, 'callee');
+"use strict";
+
+
+let enumIndexedProperties = (() => {
+  var _ref = _asyncToGenerator(function* (objectClient, start, end) {
+    const { iterator } = yield objectClient.enumProperties({ ignoreNonIndexedProperties: true });
+    const response = yield iteratorSlice(iterator, start, end);
+    return response;
+  });
+
+  return function enumIndexedProperties(_x, _x2, _x3) {
+    return _ref.apply(this, arguments);
+  };
+})(); /* 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/. */
+
+let enumNonIndexedProperties = (() => {
+  var _ref2 = _asyncToGenerator(function* (objectClient, start, end) {
+    const { iterator } = yield objectClient.enumProperties({ ignoreIndexedProperties: true });
+
+    const response = yield iteratorSlice(iterator, start, end);
+    return response;
+  });
+
+  return function enumNonIndexedProperties(_x4, _x5, _x6) {
+    return _ref2.apply(this, arguments);
+  };
+})();
+
+let enumEntries = (() => {
+  var _ref3 = _asyncToGenerator(function* (objectClient, start, end) {
+    const { iterator } = yield objectClient.enumEntries();
+    const response = yield iteratorSlice(iterator, start, end);
+    return response;
+  });
+
+  return function enumEntries(_x7, _x8, _x9) {
+    return _ref3.apply(this, arguments);
+  };
+})();
+
+let enumSymbols = (() => {
+  var _ref4 = _asyncToGenerator(function* (objectClient, start, end) {
+    const { iterator } = yield objectClient.enumSymbols();
+    const response = yield iteratorSlice(iterator, start, end);
+    return response;
+  });
+
+  return function enumSymbols(_x10, _x11, _x12) {
+    return _ref4.apply(this, arguments);
+  };
+})();
+
+function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
+
+function getPrototype(objectClient) {
+  return objectClient.getPrototype();
+}
+
+function iteratorSlice(iterator, start, end) {
+  start = start || 0;
+  const count = end ? end - start + 1 : iterator.count;
+  return iterator.slice(start, count);
+}
+
+module.exports = {
+  enumEntries,
+  enumIndexedProperties,
+  enumNonIndexedProperties,
+  enumSymbols,
+  getPrototype
 };
 
-module.exports = isArguments;
-
-
-/***/ }),
-/* 105 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var baseGetTag = __webpack_require__(12),
-    isObjectLike = __webpack_require__(15);
-
-/** `Object#toString` result references. */
-var argsTag = '[object Arguments]';
-
-/**
- * The base implementation of `_.isArguments`.
- *
- * @private
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is an `arguments` object,
- */
-function baseIsArguments(value) {
-  return isObjectLike(value) && baseGetTag(value) == argsTag;
-}
-
-module.exports = baseIsArguments;
-
-
-/***/ }),
-/* 106 */
-/***/ (function(module, exports) {
-
-/** Used as references for various `Number` constants. */
-var MAX_SAFE_INTEGER = 9007199254740991;
-
-/** Used to detect unsigned integer values. */
-var reIsUint = /^(?:0|[1-9]\d*)$/;
-
-/**
- * Checks if `value` is a valid array-like index.
- *
- * @private
- * @param {*} value The value to check.
- * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
- * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
- */
-function isIndex(value, length) {
-  length = length == null ? MAX_SAFE_INTEGER : length;
-  return !!length &&
-    (typeof value == 'number' || reIsUint.test(value)) &&
-    (value > -1 && value % 1 == 0 && value < length);
-}
-
-module.exports = isIndex;
-
-
-/***/ }),
-/* 107 */
-/***/ (function(module, exports) {
-
-/** Used as references for various `Number` constants. */
-var MAX_SAFE_INTEGER = 9007199254740991;
-
-/**
- * Checks if `value` is a valid array-like length.
- *
- * **Note:** This method is loosely based on
- * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
- *
- * @static
- * @memberOf _
- * @since 4.0.0
- * @category Lang
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
- * @example
- *
- * _.isLength(3);
- * // => true
- *
- * _.isLength(Number.MIN_VALUE);
- * // => false
- *
- * _.isLength(Infinity);
- * // => false
- *
- * _.isLength('3');
- * // => false
- */
-function isLength(value) {
-  return typeof value == 'number' &&
-    value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
-}
-
-module.exports = isLength;
-
-
 /***/ })
 /******/ ]);
 });
\ No newline at end of file
--- a/devtools/client/webconsole/new-console-output/actions/messages.js
+++ b/devtools/client/webconsole/new-console-output/actions/messages.js
@@ -16,18 +16,16 @@ const {
   MESSAGE_ADD,
   NETWORK_MESSAGE_UPDATE,
   NETWORK_UPDATE_REQUEST,
   MESSAGES_CLEAR,
   MESSAGE_OPEN,
   MESSAGE_CLOSE,
   MESSAGE_TYPE,
   MESSAGE_TABLE_RECEIVE,
-  MESSAGE_OBJECT_PROPERTIES_RECEIVE,
-  MESSAGE_OBJECT_ENTRIES_RECEIVE,
 } = require("../constants");
 
 const defaultIdGenerator = new IdGenerator();
 
 function messageAdd(packet, idGenerator = null) {
   if (idGenerator == null) {
     idGenerator = defaultIdGenerator;
   }
@@ -112,89 +110,19 @@ function networkMessageUpdate(packet, id
 function networkUpdateRequest(id, data) {
   return {
     type: NETWORK_UPDATE_REQUEST,
     id,
     data,
   };
 }
 
-/**
- * This action is used to load the properties of a grip passed as an argument,
- * for a given message. The action then dispatch the messageObjectPropertiesReceive
- * action with the loaded properties.
- * This action is mainly called by the ObjectInspector component when the user expands
- *  an object.
- *
- * @param {string} id - The message id the grip is in.
- * @param {ObjectClient} client - The ObjectClient built for the grip.
- * @param {object} grip - The grip to load properties from.
- * @returns {async function} - A function that retrieves the properties
- *          and dispatch the messageObjectPropertiesReceive action.
- */
-function messageObjectPropertiesLoad(id, client, grip) {
-  return async (dispatch) => {
-    const response = await client.getPrototypeAndProperties();
-    dispatch(messageObjectPropertiesReceive(id, grip.actor, response));
-  };
-}
-
-function messageObjectEntriesLoad(id, client, grip) {
-  return (dispatch) => {
-    client.enumEntries(enumResponse => {
-      const {iterator} = enumResponse;
-      iterator.slice(0, iterator.count, sliceResponse => {
-        dispatch(messageObjectEntriesReceive(id, grip.actor, sliceResponse));
-      });
-    });
-  };
-}
-
-/**
- * This action is dispatched when properties of a grip are loaded.
- *
- * @param {string} id - The message id the grip is in.
- * @param {string} actor - The actor id of the grip the properties were loaded from.
- * @param {object} properties - A RDP packet that contains the properties of the grip.
- * @returns {object}
- */
-function messageObjectPropertiesReceive(id, actor, properties) {
-  return {
-    type: MESSAGE_OBJECT_PROPERTIES_RECEIVE,
-    id,
-    actor,
-    properties
-  };
-}
-
-/**
- * This action is dispatched when entries of a grip are loaded.
- *
- * @param {string} id - The message id the grip is in.
- * @param {string} actor - The actor id of the grip the properties were loaded from.
- * @param {object} entries - A RDP packet that contains the entries of the grip.
- * @returns {object}
- */
-function messageObjectEntriesReceive(id, actor, entries) {
-  return {
-    type: MESSAGE_OBJECT_ENTRIES_RECEIVE,
-    id,
-    actor,
-    entries
-  };
-}
-
 module.exports = {
   messageAdd,
   messagesClear,
   messageOpen,
   messageClose,
   messageTableDataGet,
   networkMessageUpdate,
   networkUpdateRequest,
-  messageObjectPropertiesLoad,
-  messageObjectEntriesLoad,
   // for test purpose only.
   messageTableDataReceive,
-  messageObjectPropertiesReceive,
-  messageObjectEntriesReceive,
 };
-
--- a/devtools/client/webconsole/new-console-output/components/console-output.js
+++ b/devtools/client/webconsole/new-console-output/components/console-output.js
@@ -10,18 +10,16 @@ const {
   PropTypes
 } = require("devtools/client/shared/vendor/react");
 const { connect } = require("devtools/client/shared/vendor/react-redux");
 
 const {
   getAllMessagesById,
   getAllMessagesUiById,
   getAllMessagesTableDataById,
-  getAllMessagesObjectPropertiesById,
-  getAllMessagesObjectEntriesById,
   getAllNetworkMessagesUpdateById,
   getVisibleMessages,
   getAllRepeatById,
 } = require("devtools/client/webconsole/new-console-output/selectors/messages");
 const MessageContainer = createFactory(require("devtools/client/webconsole/new-console-output/components/message-container").MessageContainer);
 const {
   MESSAGE_TYPE,
 } = require("devtools/client/webconsole/new-console-output/constants");
@@ -36,18 +34,16 @@ const ConsoleOutput = createClass({
     serviceContainer: PropTypes.shape({
       attachRefToHud: PropTypes.func.isRequired,
       openContextMenu: PropTypes.func.isRequired,
       sourceMapService: PropTypes.object,
     }),
     dispatch: PropTypes.func.isRequired,
     timestampsVisible: PropTypes.bool,
     messagesTableData: PropTypes.object.isRequired,
-    messagesObjectProperties: PropTypes.object.isRequired,
-    messagesObjectEntries: PropTypes.object.isRequired,
     messagesRepeat: PropTypes.object.isRequired,
     networkMessagesUpdate: PropTypes.object.isRequired,
     visibleMessages: PropTypes.array.isRequired,
     networkMessageActiveTabId: PropTypes.string.isRequired,
   },
 
   componentDidMount() {
     // Do the scrolling in the nextTick since this could hit console startup performances.
@@ -94,18 +90,16 @@ const ConsoleOutput = createClass({
 
   render() {
     let {
       dispatch,
       visibleMessages,
       messages,
       messagesUi,
       messagesTableData,
-      messagesObjectProperties,
-      messagesObjectEntries,
       messagesRepeat,
       networkMessagesUpdate,
       networkMessageActiveTabId,
       serviceContainer,
       timestampsVisible,
     } = this.props;
 
     let messageNodes = visibleMessages.map((messageId) => MessageContainer({
@@ -115,18 +109,16 @@ const ConsoleOutput = createClass({
       serviceContainer,
       open: messagesUi.includes(messageId),
       tableData: messagesTableData.get(messageId),
       timestampsVisible,
       repeat: messagesRepeat[messageId],
       networkMessageUpdate: networkMessagesUpdate[messageId],
       networkMessageActiveTabId,
       getMessage: () => messages.get(messageId),
-      loadedObjectProperties: messagesObjectProperties.get(messageId),
-      loadedObjectEntries: messagesObjectEntries.get(messageId),
     }));
 
     return (
       dom.div({
         className: "webconsole-output",
         onContextMenu: this.onContextMenu,
         ref: node => {
           this.outputNode = node;
@@ -149,18 +141,16 @@ function isScrolledToBottom(outputNode, 
 }
 
 function mapStateToProps(state, props) {
   return {
     messages: getAllMessagesById(state),
     visibleMessages: getVisibleMessages(state),
     messagesUi: getAllMessagesUiById(state),
     messagesTableData: getAllMessagesTableDataById(state),
-    messagesObjectProperties: getAllMessagesObjectPropertiesById(state),
-    messagesObjectEntries: getAllMessagesObjectEntriesById(state),
     messagesRepeat: getAllRepeatById(state),
     networkMessagesUpdate: getAllNetworkMessagesUpdateById(state),
     timestampsVisible: state.ui.timestampsVisible,
     networkMessageActiveTabId: state.ui.networkMessageActiveTabId,
   };
 }
 
 module.exports = connect(mapStateToProps)(ConsoleOutput);
--- a/devtools/client/webconsole/new-console-output/components/console-table.js
+++ b/devtools/client/webconsole/new-console-output/components/console-table.js
@@ -21,30 +21,30 @@ const TABLE_COLUMN_MAX_ITEMS = 10;
 const ConsoleTable = createClass({
 
   displayName: "ConsoleTable",
 
   propTypes: {
     dispatch: PropTypes.func.isRequired,
     parameters: PropTypes.array.isRequired,
     serviceContainer: PropTypes.shape({
-      hudProxyClient: PropTypes.object.isRequired,
+      hudProxy: PropTypes.object.isRequired,
     }),
     id: PropTypes.string.isRequired,
     tableData: PropTypes.object,
   },
 
   componentWillMount: function () {
     const {id, dispatch, serviceContainer, parameters} = this.props;
 
     if (!Array.isArray(parameters) || parameters.length === 0) {
       return;
     }
 
-    const client = new ObjectClient(serviceContainer.hudProxyClient, parameters[0]);
+    const client = new ObjectClient(serviceContainer.hudProxy.client, parameters[0]);
     let dataType = getParametersDataType(parameters);
 
     // Get all the object properties.
     dispatch(actions.messageTableDataGet(id, client, dataType));
   },
 
   getHeaders: function (columns) {
     let headerItems = [];
--- a/devtools/client/webconsole/new-console-output/components/grip-message-body.js
+++ b/devtools/client/webconsole/new-console-output/components/grip-message-body.js
@@ -18,59 +18,52 @@ const {
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 const { ObjectClient } = require("devtools/shared/client/main");
 const {
   MESSAGE_TYPE,
   JSTERM_COMMANDS,
 } = require("../constants");
 
-const actions = require("devtools/client/webconsole/new-console-output/actions/messages");
 const reps = require("devtools/client/shared/components/reps/reps");
 const { REPS, MODE } = reps;
 const ObjectInspector = createFactory(reps.ObjectInspector);
 const { Grip } = REPS;
 
 GripMessageBody.displayName = "GripMessageBody";
 
 GripMessageBody.propTypes = {
   grip: PropTypes.oneOfType([
     PropTypes.string,
     PropTypes.number,
     PropTypes.object,
   ]).isRequired,
   serviceContainer: PropTypes.shape({
     createElement: PropTypes.func.isRequired,
-    hudProxyClient: PropTypes.object.isRequired,
+    hudProxy: PropTypes.object.isRequired,
   }),
   userProvidedStyle: PropTypes.string,
   useQuotes: PropTypes.bool,
   escapeWhitespace: PropTypes.bool,
-  loadedObjectProperties: PropTypes.object,
-  loadedObjectEntries: PropTypes.object,
   type: PropTypes.string,
   helperType: PropTypes.string,
 };
 
 GripMessageBody.defaultProps = {
   mode: MODE.LONG,
 };
 
 function GripMessageBody(props) {
   const {
-    dispatch,
-    messageId,
     grip,
     userProvidedStyle,
     serviceContainer,
     useQuotes,
     escapeWhitespace,
     mode = MODE.LONG,
-    loadedObjectProperties,
-    loadedObjectEntries,
   } = props;
 
   let styleObject;
   if (userProvidedStyle && userProvidedStyle !== "") {
     styleObject = cleanupStyle(userProvidedStyle, serviceContainer.createElement);
   }
 
   let onDOMNodeMouseOver;
@@ -98,25 +91,23 @@ function GripMessageBody(props) {
     // Let's remove the property below when problem are fixed in OI.
     disabledFocus: true,
     roots: [{
       path: (grip && grip.actor) || JSON.stringify(grip),
       contents: {
         value: grip
       }
     }],
-    getObjectProperties: actor => loadedObjectProperties && loadedObjectProperties[actor],
-    loadObjectProperties: object => {
-      const client = new ObjectClient(serviceContainer.hudProxyClient, object);
-      dispatch(actions.messageObjectPropertiesLoad(messageId, client, object));
-    },
-    getObjectEntries: actor => loadedObjectEntries && loadedObjectEntries[actor],
-    loadObjectEntries: object => {
-      const client = new ObjectClient(serviceContainer.hudProxyClient, object);
-      dispatch(actions.messageObjectEntriesLoad(messageId, client, object));
+    createObjectClient: object =>
+      new ObjectClient(serviceContainer.hudProxy.client, object),
+    releaseActor: actor => {
+      if (!actor || !serviceContainer.hudProxy.releaseActor) {
+        return;
+      }
+      serviceContainer.hudProxy.releaseActor(actor);
     },
     openLink: serviceContainer.openLink,
   };
 
   if (typeof grip === "string" || (grip && grip.type === "longString")) {
     Object.assign(objectInspectorProps, {
       useQuotes,
       escapeWhitespace,
--- a/devtools/client/webconsole/new-console-output/components/message-container.js
+++ b/devtools/client/webconsole/new-console-output/components/message-container.js
@@ -33,46 +33,38 @@ const MessageContainer = createClass({
     messageId: PropTypes.string.isRequired,
     open: PropTypes.bool.isRequired,
     serviceContainer: PropTypes.object.isRequired,
     tableData: PropTypes.object,
     timestampsVisible: PropTypes.bool.isRequired,
     repeat: PropTypes.number,
     networkMessageUpdate: PropTypes.object,
     getMessage: PropTypes.func.isRequired,
-    loadedObjectProperties: PropTypes.object,
-    loadedObjectEntries: PropTypes.object,
   },
 
   getDefaultProps: function () {
     return {
       open: false,
     };
   },
 
   shouldComponentUpdate(nextProps, nextState) {
     const repeatChanged = this.props.repeat !== nextProps.repeat;
     const openChanged = this.props.open !== nextProps.open;
     const tableDataChanged = this.props.tableData !== nextProps.tableData;
     const timestampVisibleChanged =
       this.props.timestampsVisible !== nextProps.timestampsVisible;
     const networkMessageUpdateChanged =
       this.props.networkMessageUpdate !== nextProps.networkMessageUpdate;
-    const loadedObjectPropertiesChanged =
-      this.props.loadedObjectProperties !== nextProps.loadedObjectProperties;
-    const loadedObjectEntriesChanged =
-      this.props.loadedObjectEntries !== nextProps.loadedObjectEntries;
 
     return repeatChanged
       || openChanged
       || tableDataChanged
       || timestampVisibleChanged
-      || networkMessageUpdateChanged
-      || loadedObjectPropertiesChanged
-      || loadedObjectEntriesChanged;
+      || networkMessageUpdateChanged;
   },
 
   render() {
     const message = this.props.getMessage();
 
     let MessageComponent = getMessageComponent(message);
     return MessageComponent(Object.assign({message}, this.props));
   }
--- a/devtools/client/webconsole/new-console-output/components/message-types/console-api-call.js
+++ b/devtools/client/webconsole/new-console-output/components/message-types/console-api-call.js
@@ -21,35 +21,31 @@ const Message = createFactory(require("d
 ConsoleApiCall.displayName = "ConsoleApiCall";
 
 ConsoleApiCall.propTypes = {
   dispatch: PropTypes.func.isRequired,
   message: PropTypes.object.isRequired,
   open: PropTypes.bool,
   serviceContainer: PropTypes.object.isRequired,
   timestampsVisible: PropTypes.bool.isRequired,
-  loadedObjectProperties: PropTypes.object,
-  loadedObjectEntries: PropTypes.object,
 };
 
 ConsoleApiCall.defaultProps = {
   open: false,
 };
 
 function ConsoleApiCall(props) {
   const {
     dispatch,
     message,
     open,
     tableData,
     serviceContainer,
     timestampsVisible,
     repeat,
-    loadedObjectProperties,
-    loadedObjectEntries,
   } = props;
   const {
     id: messageId,
     indent,
     source,
     type,
     level,
     stacktrace,
@@ -58,18 +54,16 @@ function ConsoleApiCall(props) {
     parameters,
     messageText,
     userProvidedStyles,
   } = message;
 
   let messageBody;
   const messageBodyConfig = {
     dispatch,
-    loadedObjectProperties,
-    loadedObjectEntries,
     messageId,
     parameters,
     userProvidedStyles,
     serviceContainer,
     type,
   };
 
   if (type === "trace") {
--- a/devtools/client/webconsole/new-console-output/components/message-types/evaluation-result.js
+++ b/devtools/client/webconsole/new-console-output/components/message-types/evaluation-result.js
@@ -16,28 +16,24 @@ const GripMessageBody = require("devtool
 
 EvaluationResult.displayName = "EvaluationResult";
 
 EvaluationResult.propTypes = {
   dispatch: PropTypes.func.isRequired,
   message: PropTypes.object.isRequired,
   timestampsVisible: PropTypes.bool.isRequired,
   serviceContainer: PropTypes.object,
-  loadedObjectProperties: PropTypes.object,
-  loadedObjectEntries: PropTypes.object,
 };
 
 function EvaluationResult(props) {
   const {
     dispatch,
     message,
     serviceContainer,
     timestampsVisible,
-    loadedObjectProperties,
-    loadedObjectEntries,
   } = props;
 
   const {
     source,
     type,
     helperType,
     level,
     id: messageId,
@@ -62,18 +58,16 @@ function EvaluationResult(props) {
   } else {
     messageBody = GripMessageBody({
       dispatch,
       messageId,
       grip: parameters,
       serviceContainer,
       useQuotes: true,
       escapeWhitespace: false,
-      loadedObjectProperties,
-      loadedObjectEntries,
       type,
       helperType,
     });
   }
 
   const topLevelClasses = ["cm-s-mozilla"];
 
   return Message({
--- a/devtools/client/webconsole/new-console-output/constants.js
+++ b/devtools/client/webconsole/new-console-output/constants.js
@@ -9,18 +9,16 @@ const actionTypes = {
   BATCH_ACTIONS: "BATCH_ACTIONS",
   MESSAGE_ADD: "MESSAGE_ADD",
   MESSAGES_CLEAR: "MESSAGES_CLEAR",
   MESSAGE_OPEN: "MESSAGE_OPEN",
   MESSAGE_CLOSE: "MESSAGE_CLOSE",
   NETWORK_MESSAGE_UPDATE: "NETWORK_MESSAGE_UPDATE",
   NETWORK_UPDATE_REQUEST: "NETWORK_UPDATE_REQUEST",
   MESSAGE_TABLE_RECEIVE: "MESSAGE_TABLE_RECEIVE",
-  MESSAGE_OBJECT_PROPERTIES_RECEIVE: "MESSAGE_OBJECT_PROPERTIES_RECEIVE",
-  MESSAGE_OBJECT_ENTRIES_RECEIVE: "MESSAGE_OBJECT_ENTRIES_RECEIVE",
   REMOVED_ACTORS_CLEAR: "REMOVED_ACTORS_CLEAR",
   TIMESTAMPS_TOGGLE: "TIMESTAMPS_TOGGLE",
   FILTER_TOGGLE: "FILTER_TOGGLE",
   FILTER_TEXT_SET: "FILTER_TEXT_SET",
   FILTERS_CLEAR: "FILTERS_CLEAR",
   DEFAULT_FILTERS_RESET: "DEFAULT_FILTERS_RESET",
   FILTER_BAR_TOGGLE: "FILTER_BAR_TOGGLE",
   SELECT_NETWORK_MESSAGE_TAB: "SELECT_NETWORK_MESSAGE_TAB",
--- a/devtools/client/webconsole/new-console-output/new-console-output-wrapper.js
+++ b/devtools/client/webconsole/new-console-output/new-console-output-wrapper.js
@@ -74,17 +74,17 @@ NewConsoleOutputWrapper.prototype = {
     const serviceContainer = {
       attachRefToHud,
       emitNewMessage: (node, messageId) => {
         this.jsterm.hud.emit("new-messages", new Set([{
           node,
           messageId,
         }]));
       },
-      hudProxyClient: this.jsterm.hud.proxy.client,
+      hudProxy: this.jsterm.hud.proxy,
       openLink: url => {
         this.jsterm.hud.owner.openLink(url);
       },
       createElement: nodename => {
         return this.document.createElementNS("http://www.w3.org/1999/xhtml", nodename);
       },
     };
 
--- a/devtools/client/webconsole/new-console-output/reducers/messages.js
+++ b/devtools/client/webconsole/new-console-output/reducers/messages.js
@@ -33,26 +33,16 @@ const MessageState = Immutable.Record({
   visibleMessages: [],
   // Object for the filtered messages.
   filteredMessagesCount: getDefaultFiltersCounter(),
   // List of the message ids which are opened.
   messagesUiById: Immutable.List(),
   // Map of the form {messageId : tableData}, which represent the data passed
   // as an argument in console.table calls.
   messagesTableDataById: Immutable.Map(),
-  // Map of the form {messageId : {[actor]: properties}}, where `properties` is
-  // a RDP packet containing the properties of the ${actor} grip.
-  // This map is consumed by the ObjectInspector so we only load properties once,
-  // when needed (when an ObjectInspector node is expanded), and then caches them.
-  messagesObjectPropertiesById: Immutable.Map(),
-  // Map of the form {messageId : {[actor]: entries}}, where `entries` is
-  // a RDP packet containing the entries of the ${actor} grip.
-  // This map is consumed by the ObjectInspector so we only load entries once,
-  // when needed (when an ObjectInspector node is expanded), and then caches them.
-  messagesObjectEntriesById: Immutable.Map(),
   // Map of the form {groupMessageId : groupArray},
   // where groupArray is the list of of all the parent groups' ids of the groupMessageId.
   groupsById: Immutable.Map(),
   // Message id of the current group (no corresponding console.groupEnd yet).
   currentGroup: null,
   // Array of removed actors (i.e. actors logged in removed messages) we keep track of
   // in order to properly release them.
   // This array is not supposed to be consumed by any UI component.
@@ -64,18 +54,16 @@ const MessageState = Immutable.Record({
   networkMessagesUpdateById: {},
 });
 
 function messages(state = new MessageState(), action, filtersState, prefsState) {
   const {
     messagesById,
     messagesUiById,
     messagesTableDataById,
-    messagesObjectPropertiesById,
-    messagesObjectEntriesById,
     networkMessagesUpdateById,
     groupsById,
     currentGroup,
     repeatById,
     visibleMessages,
     filteredMessagesCount,
   } = state;
 
@@ -237,37 +225,16 @@ function messages(state = new MessageSta
           );
         }
       });
 
     case constants.MESSAGE_TABLE_RECEIVE:
       const {id, data} = action;
       return state.set("messagesTableDataById", messagesTableDataById.set(id, data));
 
-    case constants.MESSAGE_OBJECT_PROPERTIES_RECEIVE:
-      return state.set(
-        "messagesObjectPropertiesById",
-        messagesObjectPropertiesById.set(
-          action.id,
-          Object.assign({
-            [action.actor]: action.properties
-          }, messagesObjectPropertiesById.get(action.id))
-        )
-      );
-    case constants.MESSAGE_OBJECT_ENTRIES_RECEIVE:
-      return state.set(
-        "messagesObjectEntriesById",
-        messagesObjectEntriesById.set(
-          action.id,
-          Object.assign({
-            [action.actor]: action.entries
-          }, messagesObjectEntriesById.get(action.id))
-        )
-      );
-
     case constants.NETWORK_MESSAGE_UPDATE:
       return state.set(
         "networkMessagesUpdateById",
         Object.assign({}, networkMessagesUpdateById, {
           [action.message.id]: action.message
         })
       );
 
@@ -452,40 +419,30 @@ function limitTopLevelMessageCount(state
   }
   if (mapHasRemovedIdKey(record.messagesTableDataById)) {
     record.set("messagesTableDataById",
       record.messagesTableDataById.withMutations(cleanUpCollection));
   }
   if (mapHasRemovedIdKey(record.groupsById)) {
     record.set("groupsById", record.groupsById.withMutations(cleanUpCollection));
   }
-  if (mapHasRemovedIdKey(record.messagesObjectPropertiesById)) {
-    record.set("messagesObjectPropertiesById",
-      record.messagesObjectPropertiesById.withMutations(cleanUpCollection));
-  }
-  if (mapHasRemovedIdKey(record.messagesObjectEntriesById)) {
-    record.set("messagesObjectEntriesById",
-      record.messagesObjectEntriesById.withMutations(cleanUpCollection));
-  }
   if (objectHasRemovedIdKey(record.repeatById)) {
     record.set("repeatById", cleanUpObject(record.repeatById));
   }
 
   if (objectHasRemovedIdKey(record.networkMessagesUpdateById)) {
     record.set("networkMessagesUpdateById",
       cleanUpObject(record.networkMessagesUpdateById));
   }
 
   return record;
 }
 
 /**
  * Get an array of all the actors logged in a specific message.
- * This could be directly the actors representing the arguments of a console.log call
- * as well as all the properties that where expanded using the object inspector.
  *
  * @param {Message} message: The message to get actors from.
  * @param {Record} state: The redux state.
  * @return {Array} An array containing all the actors logged in a message.
  */
 function getAllActorsInMessage(message, state) {
   // Messages without argument cannot be associated with backend actors.
   if (!message || !Array.isArray(message.parameters) || message.parameters.length === 0) {
@@ -494,26 +451,16 @@ function getAllActorsInMessage(message, 
 
   const actors = [...message.parameters.reduce((res, parameter) => {
     if (parameter.actor) {
       res.push(parameter.actor);
     }
     return res;
   }, [])];
 
-  const loadedProperties = state.messagesObjectPropertiesById.get(message.id);
-  if (loadedProperties) {
-    actors.push(...Object.keys(loadedProperties));
-  }
-
-  const loadedEntries = state.messagesObjectEntriesById.get(message.id);
-  if (loadedEntries) {
-    actors.push(...Object.keys(loadedEntries));
-  }
-
   return actors;
 }
 
 /**
  * Returns total count of top level messages (those which are not
  * within a group).
  */
 function getToplevelMessageCount(record) {
--- a/devtools/client/webconsole/new-console-output/selectors/messages.js
+++ b/devtools/client/webconsole/new-console-output/selectors/messages.js
@@ -16,24 +16,16 @@ function getMessage(state, id) {
 function getAllMessagesUiById(state) {
   return state.messages.messagesUiById;
 }
 
 function getAllMessagesTableDataById(state) {
   return state.messages.messagesTableDataById;
 }
 
-function getAllMessagesObjectPropertiesById(state) {
-  return state.messages.messagesObjectPropertiesById;
-}
-
-function getAllMessagesObjectEntriesById(state) {
-  return state.messages.messagesObjectEntriesById;
-}
-
 function getAllGroupsById(state) {
   return state.messages.groupsById;
 }
 
 function getCurrentGroup(state) {
   return state.messages.currentGroup;
 }
 
@@ -59,11 +51,9 @@ module.exports = {
   getAllMessagesUiById,
   getAllMessagesTableDataById,
   getAllGroupsById,
   getCurrentGroup,
   getVisibleMessages,
   getFilteredMessagesCount,
   getAllRepeatById,
   getAllNetworkMessagesUpdateById,
-  getAllMessagesObjectPropertiesById,
-  getAllMessagesObjectEntriesById,
 };
--- a/devtools/client/webconsole/new-console-output/test/fixtures/serviceContainer.js
+++ b/devtools/client/webconsole/new-console-output/test/fixtures/serviceContainer.js
@@ -1,17 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 module.exports = {
   attachRefToHud: () => {},
   emitNewMessage: () => {},
-  hudProxyClient: {},
+  hudProxy: {
+    client: {},
+    releaseActor: actor => console.log("Release actor", actor),
+  },
   onViewSourceInDebugger: () => {},
   onViewSourceInStyleEditor: () => {},
   onViewSourceInScratchpad: () => {},
   openNetworkPanel: () => {},
   sourceMapService: {
     subscribe: () => {},
     originalPositionFor: () => {
       return new Promise(resolve => {
--- a/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/head.js
+++ b/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/head.js
@@ -13,16 +13,17 @@
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js",
   this);
 
 Services.prefs.setBoolPref("devtools.webconsole.new-frontend-enabled", true);
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("devtools.webconsole.new-frontend-enabled");
 });
+const { PREFS } = require("devtools/client/webconsole/new-console-output/constants");
 
 const { prepareMessage } = require("devtools/client/webconsole/new-console-output/utils/messages");
 const { stubPackets } = require("devtools/client/webconsole/new-console-output/test/fixtures/stubs/index.js");
 const {
   consoleApi,
   cssMessage,
   evaluationResult,
   networkEvent,
@@ -283,16 +284,19 @@ module.exports = {
   stubPackets,
 };
 `;
 }
 
 function* generateConsoleApiStubs() {
   const TEST_URI = "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html";
 
+  // Hiding log messages so we don't get unwanted client/server communication.
+  Services.prefs.setBoolPref(PREFS.FILTER.LOG, false);
+
   let stubs = {
     preparedMessages: [],
     packets: [],
   };
 
   let toolbox = yield openNewTabAndToolbox(TEST_URI, "webconsole");
   const hud = toolbox.getCurrentPanel().hud;
   let {ui} = hud;
@@ -325,16 +329,18 @@ function* generateConsoleApiStubs() {
         content.wrappedJSObject.triggerPacket();
         script.remove();
       }
     );
 
     yield received;
   }
 
+  Services.prefs.clearUserPref(PREFS.FILTER.LOG);
+
   yield closeTabAndToolbox();
   return formatFile(stubs, "ConsoleMessage");
 }
 
 function* generateCssMessageStubs() {
   const TEST_URI = "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-css-message.html";
 
   let stubs = {
--- a/devtools/client/webconsole/new-console-output/test/store/messages.test.js
+++ b/devtools/client/webconsole/new-console-output/test/store/messages.test.js
@@ -6,18 +6,16 @@ const {
   getAllGroupsById,
   getAllMessagesById,
   getAllMessagesTableDataById,
   getAllMessagesUiById,
   getAllNetworkMessagesUpdateById,
   getAllRepeatById,
   getCurrentGroup,
   getVisibleMessages,
-  getAllMessagesObjectPropertiesById,
-  getAllMessagesObjectEntriesById,
 } = require("devtools/client/webconsole/new-console-output/selectors/messages");
 const {
   clonePacket,
   getMessageAt,
   setupActions,
   setupStore,
 } = require("devtools/client/webconsole/new-console-output/test/helpers");
 const { stubPackets, stubPreparedMessages } = require("devtools/client/webconsole/new-console-output/test/fixtures/stubs/index");
@@ -754,216 +752,9 @@ describe("Message reducer:", () => {
       expect(table.get(id2)).toBe(tableData2);
 
       // This addition will remove the second table message.
       dispatch(actions.messageAdd(stubPackets.get("console.log('foobar', 'test')")));
 
       expect(getAllMessagesTableDataById(getState()).size).toBe(0);
     });
   });
-
-  describe("messagesObjectPropertiesById", () => {
-    it(`adds messagesObjectPropertiesById data in response to
-        MESSAGE_OBJECT_PROPERTIES_RECEIVE action`, () => {
-      const { dispatch, getState } = setupStore([]);
-
-      // Add 2 log messages with loaded object properties.
-      dispatch(actions.messageAdd(